如何使用Java Spring同步在码头集群中运行的微服务实例

时间:2019-01-28 08:57:36

标签: java spring-boot locking jetty microservices

我正在开发在Jetty嵌入式服务器上运行的Java 8 Spring 5微服务。我打算产生该微服务的多个实例,因此将有多个Jetty服务器在不同端口上同时运行,每个产生的实例一个。

所有实例共享一个与MongoDB数据库相同的数据库。

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

但是,此数据会在一段时间后过期,因此一个实例将不得不在一段时间后调用外部Web服务。

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

这是我发现问题的时间,因为当另一个实例调用Web服务时,我不知道如何锁定码头服务器的一个实例。

我一直在研究MongoDBs 4.0事务功能,以尝试在服务被调用时锁定文档,但是没有成功(仍然:))。

1 个答案:

答案 0 :(得分:0)

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

这是数据库真正擅长的事情。通过特制的唯一索引,您可以准确地做到这一点。您甚至不需要为此进行事务处理,因为您只有一个集合(表)。

解决方案是使用乐观锁定。我没有在Java中使用过自己(仅在PHP中),但是发现this question可以为您提供帮助。长话短说,您在属性上使用@org.springframework.data.annotation.Version

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

  • 如果状态为fetched,则使用它;
  • 如果状态为fetched,则尝试将其更改为old;如果数据库由于并发修改而拒绝它,则应等待状态变为fetching为止;如果保存成功,则调用远程服务并将结果作为属性保留在Entity中;
  • 如果状态为fetched,则应等待状态变为fetching