You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

微服务架构下如何应对并发与乱序事件以维护数据完整性?

微服务架构下后台管理工具的并发与乱序事件处理问题

背景

  • 微服务发送事件,用于更新Elasticsearch中的读模型
  • 后台工具需展示订单、客户、地址等多类数据
  • 部分数据(如订单)的读模型由多个微服务的事件共同构建
  • 事件可能出现乱序或延迟到达的情况

订单索引的文档结构如下:

{
    "id": "2bc3ec03-eaf4-46cb-9a41-3854098c8763", // 来自 order.* 事件
    "line_items": [], // 来自 order.* 事件
    "shipping_address": { // 来自 shipping.* 事件
        "name": "",
        "surname": ""
    },
    "timestamp": 12381231238 // 修改数据的最新事件时间戳
}

问题

假设先处理了timestamp为2的订单事件,更新了Elasticsearch中的timestamp;10分钟后,timestamp为1的shipping_address.changed事件到达,若基于全局timestamp处理乱序事件,将不会更新读模型中的收货地址。

并发处理方案

通过为指定ID一次处理一个事件应对并发:事件到达时加入任务队列,利用Laravel的WithoutOverlapping中间件确保同一时间只有一个Worker修改对应文档。

现有乱序事件处理方案

1. 基于Redis的临时事件存储

  • 事件到达时暂存于Redis
  • 队列任务获取指定Key下的所有事件,按事件timestamp排序后处理
  • Redis中事件的TTL设为15分钟,符合当前业务场景
  • 可正确处理乱序事件,但增加了复杂度与内存占用
  • 若事件延迟超过15分钟,因timestamp早于Elastic文档中的最新timestamp,将无法被处理

2. 为不同数据源设置独立Timestamp

  • 文档中来自不同数据源的字段拥有独立timestamp

修改后的Elasticsearch文档结构:

{
    "id": "2bc3ec03-eaf4-46cb-9a41-3854098c8763",
    "line_items": [],
    "shipping_address": { // 数据来源为 shipping.* 事件
        "timestamp": 123123123, // 该字段的独立时间戳
        "name": "",
        "surname": ""
    },
    "timestamp": 1123123123 // order.* 事件对应的根时间戳
}
  • 仅当新事件的timestamp晚于对应字段存储的timestamp时才执行更新:处理order.*事件时对比根timestamp,处理shipping_address时对比shipping_address.timestamp与事件timestamp
  • 即使事件延迟数小时到达,仍可被处理

3. 将所有事件存储至数据库

  • 接收事件后存入数据库
  • 加入队列任务更新索引
  • 任务获取所有影响该索引的事件,按顺序从最早到最新依次处理
  • 可保障最高数据完整性,但担忧数据库数据量膨胀,可对已完成订单的旧事件进行归档或删除

寻求解答

  1. 是否有其他处理乱序事件的策略?
  2. 上述方案中哪种更合理?
  3. 各方案存在哪些缺陷?
  4. 是否有更简便的方式实现后台工具的数据展示(已弃用通过API查询微服务并合并数据的方案,因速度过慢)?

内容的提问来源于stack exchange,提问作者Kamil Latosinski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:43:18