【问题标题】:Concurrent message processing design controversy并发消息处理设计争议
【发布时间】:2019-06-25 03:53:26
【问题描述】:

最近我设计了一个系统,使用 Oracle 高级队列 (AQ) 使用 JMS 处理健康数据。该消息必须包含患者信息,例如姓名、健康卡号等。此外,该消息可能包含患者免疫记录。我正在使用 Spring Boot,我能够通过配置多个消息侦听器(最多 30 个)同时处理这些消息。所以我能够获得表演。但是,这些消息是按时间顺序处理的,导致数据不一致。例如,消息 A 表示新的患者记录,消息 B 表示使用消息 A 创建的对患者的更新。如果随后处理(消息 A,然后是消息 B),则结果与上游系统一致。但是,如果同时处理,结果与现实不同步(消息 B 可能在消息 A 之前得到处理)。 显然,如果有消息 A,我将不会开始处理消息 B。假设我有办法确定它(每条消息都有事件时间戳和状态)。但是如何实际实施呢? 如果有人分享他们的经验,我将不胜感激。实际技术无所谓,我正在寻找某种设计模式

【问题讨论】:

  • @JustinBertram 我正在使用 Oracle 高级队列 (AQ)。我正在考虑消息分组,但根据 Oracle,它必须是一个事务的一部分。在我的情况下这是不可能的,我无法控制消息的发送方式。
  • 我的回答是否解决了您的问题?如果是这样,请将其标记为正确,以帮助将来有相同问题的其他用户。如果不是,请详细说明原因。谢谢!

标签: multithreading algorithm design-patterns concurrency jms


【解决方案1】:

如果你想坚持使用 JMS 作为技术并且你不能使用消息分组,那么我看到了两种基本的方法来处理这个问题。

序列化所有消息处理

通过序列化所有消息处理,您将确保不会乱序处理任何内容。但是,这可能会导致性能显着下降。

重试乱序消息

当您发现您正在无序处理消息时,您可以简单地回滚该消息的使用并配置重新传递延迟,假设最终“领先”当前消息的消息将是在延迟时间内处理。大多数 JMS 代理有时支持同一消息的多次重新传递,即使重新传递延迟越来越长,并且最终能够在一定次数的传递尝试后将无法传递的消息放入某种“死信”队列中。这里的好处是您可以继续并发处理消息(具有并发提供的所有性能优势),并且您只需要在顺序实际中断时处理乱序消息。不利的一面是您可能会浪费一些时间多次重新处理一些相同的消息,并且您需要建立某种流程来处理最终被认为无法传递的消息(尽管您可能无论如何都必须这样做)。

【讨论】:

    【解决方案2】:

    在不牺牲顺序的情况下获得性能的一种方法是将数据分布到多个不重叠的主题。因此,患者 A 和患者 B 可以继续讨论不同的主题,但患者 A 的更新只会继续讨论患者 A 的主题。

    如何?一种开始方法是使用患者姓氏的第一个字母作为主题。因此,所有患者 Miller 的消息都在主题 M 上,而 John Doe 的所有消息都在主题 D 上。当然,这种分布并不理想(订阅者“X”的工作量不大),但您也可以使用全名模数的哈希码以 30 为例。或者,如果您有 ID,请使用 ID 的最后 2 位数字发布和订阅主题 00 到 99。

    如果您担心丢失消息,请改用 JMS 持久订阅或设置 X 个队列。

    【讨论】:

      【解决方案3】:

      只是为了结束讨论。正如@Justin Bertram 所建议的那样,我的最终决定只是将消息发送回队列并使用延迟选项。 Oracle Advance Queuing 允许使用延迟选项对消息进行排队。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-22
        • 1970-01-01
        • 2016-01-15
        • 2015-10-03
        • 2019-09-30
        相关资源
        最近更新 更多