Java 在多实例应用程序上避免单例消息计数器的模式

Java 在多实例应用程序上避免单例消息计数器的模式,java,architecture,multi-instance-deployment,Java,Architecture,Multi Instance Deployment,我想知道对于一个应该是无状态的应用程序,建议使用哪个模式来处理表示已处理消息数量的计数器 例如,在应用程序部署在多台服务器上的体系结构中,数据库用于存储持久信息(会话等)。但是,这些信息不会像消息计数器那样暴露于并发更新中。在单实例应用程序中,我们可以使用单例,但这里的情况并非如此 你有什么建议来实施这样一个计数器? 使用计数器是一种糟糕的设计吗?我不认为有什么模式可以完成这个非常抽象的任务。此外: 在单实例应用程序中,我们可以使用单例,但这里的情况并非如此 在多线程系统中使用单实例并不能保证数

我想知道对于一个应该是无状态的应用程序,建议使用哪个模式来处理表示已处理消息数量的计数器

例如,在应用程序部署在多台服务器上的体系结构中,数据库用于存储持久信息(会话等)。但是,这些信息不会像消息计数器那样暴露于并发更新中。在单实例应用程序中,我们可以使用单例,但这里的情况并非如此

你有什么建议来实施这样一个计数器?
使用计数器是一种糟糕的设计吗?

我不认为有什么模式可以完成这个非常抽象的任务。此外:

在单实例应用程序中,我们可以使用单例,但这里的情况并非如此

在多线程系统中使用单实例并不能保证数据安全。您需要一些同步原语。非常简单的部分是关键部分


如果您的所有应用程序都应该更新一些计数器,那么重构这个计数器看起来是合理的。。。将“计数器”管理转换为微服务,并使用微服务内的关键部分更新资源。在这种情况下,在每个给定时刻,保证您只有一个线程更新计数器。

我可能不会直接回答您的问题,但我可以为您提供一个可用计数器服务的参考,该服务是多线程、多节点、可扩展的,同时考虑可用性场景。检查jgroups柜台服务


这可以引导您找到分布式计数器场景中的一组问题,也可以作为实时工作参考。

数据库的可能解决方案:

  • 例如,在Oracle中创建一个存储过程来更新计数器并返回新值(update…RETURNING…INTO)
  • 例如,mongodb中的$inc

计数器将存储在数据库中,并可用于连接到此数据库的每个应用程序实例

,这在很大程度上取决于您将使用计数器的用途。用例是什么?例如,我们可能会收到许多事务(数量已知),这些事务的处理被分派到多个服务器上。在所有交易处理结束时,应生成一份报告。但是,如何知道最后一笔交易已被处理?独立计算每台服务器上的交易,并在需要总计时将这些数字相加。每个服务器负责自己的同步。我认为这可能是这个问题的解决方案,但假设我们有数十亿个事务,microservice将接收来自数十台服务器的请求,所有这些请求都将压缩到一台服务器上,而对于这台服务器,水平可伸缩性是不可能的。@AnthonyCorrado如果不同步,就无法生成线程安全的单调递增计数器。这背后的真正任务是什么?例如,我们可能会收到许多事务(数量已知),这些事务的处理被分派到多个服务器上。在所有交易处理结束时,应生成一份报告。但是,如何知道最后一个事务已被处理?@AnthonyCorrado能否为每个事务分配一个GUID,并将GUID列表存储在某个位置(它至少应存储在DB中)?您只需计算GUID数即可验证上一个事务是否已处理。可以是“是”。但是,如果一个新事务在INSERT和COUNT之间到达,会发生什么呢?我们可能会有这样一种情况,几条消息被认为是最后一条,不是吗?有没有一种方法可以“同步”插入并选择数据库中的计数?我认为这并不能解决问题。仍然只有一个计数器协调器执行实际递增。一次只能有一台机器,@anthonycorado希望避免这种情况<代码>简而言之,在集群中,当前协调器维护命名计数器的哈希映射。成员向其发送请求(递增、递减等),协调器以原子方式应用请求并发回响应。如果计数器需要绝对一致性,这应该是(内存中)的参考模型,或者我们可以使用数据库方法(这会导致更多延迟)。但可以肯定的是,如果我们只需要一个最终一致的计数器,我们将有更多的设计选项我们只能提出解决办法。