春季启动 Webservice / 微服务和调度

huangapple go评论91阅读模式
英文:

Spring boot Webservice / Microservices and scheduling

问题

我正在开发一个使用Spring Boot的应用程序,该应用程序暴露了REST API,并计划添加一个Spring Boot定时任务。

任务的目的是从数据存储(使用MongoDB)中获取一些待处理的“预订”并进行处理。

现在的问题是,当多个服务实例在运行时,所有节点都很可能会选择相同的“预订记录”。

我在考虑使用MongoDB的锁,并且正在检查MongoDB 4.x中的updateAndModify / 事务。

还有一种可能性是使用单独的锁表,只有一条记录,我可以在锁定记录后执行操作,然后解锁记录。 但这种方式一次只能有一个节点在工作,并且如果解锁操作失败,则需要清除锁定的开销。

因此,关于运行多个服务实例并安排上述任务的问题。我会非常感谢,如果有人能够指出关于此主题的最佳实践或解决方案,无论涉及哪些技术(Spring Boot / MongoDB等)。

英文:

I am having a spring boot application which exposes REST APIs and also am planning to add a spring boot scheduled task.

The purpose of task is to pick up some pending 'reservations' from data store which is momgodb and process it.

Now the question is when multiple instances of service running, there is high probability all the nodes will pick up same 'reservation records'.

I was looking at mongodb lock for this and was checking updateAndModidy / transactions (in 4.x) of mongodb.

Also possibility of separate lock table with only one record, where in I lock the record and perform operation and unlock record. But this way at a time only one node will be working and also overhead of cleaning up lock if unlock operation failed.

So question is regarding multiple instances of services running and scheduling the tasks as mentioned above. I would appreciate and grateful, if anyone could point to best practices or solution around this topic regardless of Technologies (spring boot / mongodb etc).

答案1

得分: 1

根据您的部署情况,我们使用的解决方案是使用Hazelcast从同一应用程序创建一个集群,然后在运行任务时,所有节点都会检查是否为主节点,只有主节点才会运行任务。

您可以在这里阅读有关Spring中Hazelcast的简介:https://josdem.io/techtalk/spring/spring_boot_hazelcast_es/

我们使用的是Hazelcast与Consul,因此我们不必手动配置IP/端口,可以使用此链接:https://github.com/bitsofinfo/hazelcast-consul-discovery-spi

如果您没有许多(动态)节点,这是一个相对简单的解决方案,我们已经使用了一段时间(3个节点,使用来自Jenkins的consul/fabio进行协调的零停机部署)。

过去,我们曾让Quartz调度协调所有节点,使用共同的JDBC数据源作为同步机制,但实现存在缺陷,不时会出现需要手动解锁的表锁,从而导致某些节点被终止。

编辑:

这是我们其中一个类的示例:

// 在非集群环境中(开发环境)可选择自动装配
private final Optional<HazelcastInstance> hazelcast;

@Scheduled(cron = "${refresh.cron}")
public void scheduledRefresh() {
    // 如果我们不在集群中,或者
    // 我们是集群的第一个成员
    if (!hazelcast.isPresent() ||
        hazelcast.get().getCluster().getMembers().iterator().next().localMember()) {
        // 执行受限制的方法
    }
}
英文:

Depending on your deployment, a solution that works for us is to create a cluster with the nodes from the same application using Hazelcast and then when the task is run, all the nodes check if they are master and only the master runs the task.

You can read an intro about Hazelcast in Spring here: https://josdem.io/techtalk/spring/spring_boot_hazelcast_es/

What we use is Hazelcast with Consul so we don't have to configure the ips/ports manualy, using this: https://github.com/bitsofinfo/hazelcast-consul-discovery-spi

If you don't have many (dynamic) nodes, it's a relatively simple solution that has been working fine for us (3 nodes, coordinated zero-downtime deployments with consul/fabio from Jenkins)

In the past we used to let Quartz scheduling coordinate all nodes, using a common JDBC datasource for Quartz as synchronization mechanism, but the implementation is faulty and every now and then we would end up with TABLE locks that we would have to unlock manually, killing some nodes.

Cheers

Edit:

This is how one of our class looks:

// Optionally autowired, in case we don&#39;t run in a cluster (development)
private final Optional&lt;HazelcastInstance&gt; hazelcast;

	@Scheduled(cron = &quot;${refresh.cron}&quot;)
	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
   }

huangapple
  • 本文由 发表于 2020年4月7日 04:23:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/61068344.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定