如何使用JavaSpring同步jetty集群中运行的微服务实例

如何使用JavaSpring同步jetty集群中运行的微服务实例,java,spring-boot,locking,jetty,microservices,Java,Spring Boot,Locking,Jetty,Microservices,我正在开发一个在Jetty嵌入式服务器上运行的Java8Spring5微服务。我打算生成此微服务的多个实例,因此将有多个Jetty服务器在不同的端口上并发运行,每个生成的实例一个 所有实例共享同一个数据库,即MongoDB数据库 在我的微服务中,我调用了第三方REST Web服务。我正在将REST WS返回的数据保存在数据库中,因此集群的所有实例都可以利用其中一个实例发出的请求 但是,此数据在一段时间后过期,因此一个实例必须在一段时间后调用外部Web服务 我不希望集群的两个或多个实例同时调用此外

我正在开发一个在Jetty嵌入式服务器上运行的Java8Spring5微服务。我打算生成此微服务的多个实例,因此将有多个Jetty服务器在不同的端口上并发运行,每个生成的实例一个

所有实例共享同一个数据库,即MongoDB数据库

在我的微服务中,我调用了第三方REST Web服务。我正在将REST WS返回的数据保存在数据库中,因此集群的所有实例都可以利用其中一个实例发出的请求

但是,此数据在一段时间后过期,因此一个实例必须在一段时间后调用外部Web服务

我不希望集群的两个或多个实例同时调用此外部web服务,如果一个实例正在调用此web服务,而另一个实例需要数据,它应该等待第一个实例检索数据,然后使用它

这就是我发现问题的时候,因为我不知道如何在另一个jetty服务器调用web服务时锁定jetty服务器的一个实例


我一直在研究MongoDBs 4.0事务特性,试图在调用服务时锁定文档,但没有成功(仍然:)。

您需要一种方法来序列化对该外部服务的访问,即确保在任何特定时刻执行单个请求

这是数据库真正擅长的事情。通过精心编制的唯一索引,您可以准确地获得该索引。您甚至不需要事务,因为您将只有一个集合(表)

解决方案是使用乐观锁定。我还没有在Java中使用自己(只在PHP中使用),但我发现这可以帮助您。长话短说,您可以对属性使用
@org.springframework.data.annotation.Version

您应该定义一个表示远程数据段的新实体,该实体具有一个具有以下可能值的
state
属性:
old
(默认值)、
fetching
fetched
。当本地服务需要数据时,它将加载实体并检查状态:

  • 如果状态为fetched,则使用它
  • 如果状态为
    old
    ,则尝试将其更改为
    fetching
    ;如果数据库因为并发修改而拒绝它,那么它应该等到状态变为“已获取”;如果保存成功,则调用远程服务并将结果作为属性保存在实体中
  • 如果状态为
    fetching
    ,则应等待状态变为
    fetched

这与其说是编码问题,不如说是编程技术问题,但我要说的是。。。查看一个可以提供分布式锁定的系统,如Hazelcast或Apache Zookeeper。@AndyBrown实际上我并不认为这是一个编程技术问题,因为很明显,解决方案与所使用的技术有很大的关系。例如,如果数据库是一个关系数据库,那么它很容易锁定两个进程;i、 e.如果服务器正在抓取,我将等待一段时间,然后再次从数据库中检索记录,它可能仍在抓取。这将使用不必要的处理器电源以及数据库访问。。我需要在获取记录时读取该记录的线程进行阻止,直到其他已经拥有锁的线程使用已获取或旧的更新记录。@jsmrt
忙等待与
锁定之间的区别是什么?在这个解决方案中,实例可以在不同的机器上运行,并且可以执行其他任务,而不是等待。如果您只需要线程,那么一个简单的
同步方法就足够了。我之所以提出这个解决方案,是因为您使用了术语“集群”,这意味着分布式系统@Constantin Galbenu我的意思是,您将如何实现算法的这一部分:“如果数据库因为并发修改而拒绝它,那么它应该等到状态变为已获取”,如果是通过执行一段时间(true)在中间有一个休眠循环,反复询问数据库状态是否改变,即忙等待,它的丑陋。我喜欢这个想法,但我不知道如何使数据库在状态值更改时引发事件,以便线程可以唤醒,而不必轮询记录的状态。@jsmrt您可以跟踪
oplog