我有一个Spring Boot应用程序,它公开了REST API,并且还计划添加一个Spring Boot计划任务。
此任务的目的是从作为momgodb的数据存储中提取一些未决的“保留”并进行处理。
现在的问题是,当多个服务实例正在运行时,所有节点都很有可能会选择相同的'保留记录'。
我正在为此寻找mongodb锁,并正在检查mongodb的updateAndModidy /事务(在4.x中)。
也可以使用只有一个记录的单独锁定表,在此情况下,我锁定记录并执行操作并解锁记录。但是通过这种方式,一次只有一个节点可以正常工作,而且如果解锁操作失败,清理锁的开销也将很大。
因此问题涉及如上所述的运行和调度任务的服务的多个实例。我将不胜感激,如果任何人都可以针对此主题,无论技术(弹簧启动/ mongodb等)如何指向最佳实践或解决方案。
取决于您的部署,一种适用于我们的解决方案是使用Hazelcast使用来自同一应用程序的节点创建群集,然后在运行任务时,所有节点检查它们是否为主节点,只有主节点才能运行任务。
您可以在此处阅读有关Hazelcast的春季介绍:https://josdem.io/techtalk/spring/spring_boot_hazelcast_es/
我们使用的是带有Consul的Hazelcast,因此我们不必使用以下命令手动配置ips /端口:https://github.com/bitsofinfo/hazelcast-consul-discovery-spi
如果您没有很多(动态)节点,那么这是一个相对简单的解决方案,对我们来说很好(3个节点,与詹金斯的consul / fabio协调零停机时间部署)
过去,我们曾经使用Quartz的通用JDBC数据源作为同步机制来让Quartz调度来协调所有节点,但是实现是错误的,并且时不时地,我们最终会遇到需要手动解锁的TABLE锁。 ,杀死一些节点。
欢呼声
编辑:
这是我们班上一位的样子:
// Optionally autowired, in case we don't run in a cluster (development)
private final Optional<HazelcastInstance> hazelcast;
@Scheduled(cron = "${refresh.cron}")
public void scheduledRefresh() {
// Run if we are not in a cluster or
// we are the first member of the cluster
if (!hazelcast.isPresent() ||
hazelcast.get().getCluster().getMembers().iterator().next().localMember()) {
// Run restricted method
}