货拉拉待办中心重构的标题里有两个关键词:低延迟和一致性。最近我在做同类订单履约平台的任务系统时,正好把这两个目标放在一起推演了一遍,发现它们不是“先快后稳”的两阶段,而是必须同时设计的两个约束。待办中心不像支付、库存那么容易被关注,但它一旦变慢或者出现脏数据,司机端、客服端、用户端都会同时感知到,属于典型的“平时不起眼,故障时炸一片”的系统。
这篇重点拆解的是:2秒的延迟到底从哪里来,切换成事件驱动后一致性为什么反而更难做,以及100ms这个目标要如何落到消费、缓存、推送和对账链路上。适合正在做业务中台、待办任务、消息驱动类系统的后端同学参考,尤其是那些准备把同步接口改造成异步事件流的团队,应该能少踩几个坑。
1. 重新拆一拆:2秒的延迟到底花在哪里
1.1 待办中心不是一张“任务表”,它是履约状态的集散地
任何订单履约类系统里,待办中心都承担着同一个职责:把散落在各个业务域的状态变化,转成具体执行者能看到的下一步动作。司机端要看“我现在该去哪个位置取货”,客服工作台要看“哪些订单需要人工介入”,用户端则要看到“订单异常之后我下一步能做什么”。这些都不是主流程里的核心查询,但它们的集合决定了整个平台的协作效率。
所以待办中心本质上不是一张任务表,而是一个履约状态的集散地。货拉拉那篇分享把主题定成“低延迟与一致性保障”,其实是在说:当所有端都依赖待办数据来驱动下一步操作时,等待模型和数据可靠性必须一起升级,而不是把查询SQL调快就完事。
旧架构里最常见的实现,是把所有待办固化成MySQL表,上游业务通过接口直接插入一行记录。这样做最简单,但弊端也很直接:调用链路长,依赖多,待办服务一旦出现慢SQL,上游下单逻辑都会被拖垮。如果为了跨服务强一致去引入分布式事务,成本极高且不必要。优化方向应该是改变请求模型,而不是在原有模型上修修补补。
1.2 轮询等待是2秒最主要的放大镜
如果客户端每2秒轮询一次待办列表,服务端处理得再快,用户感知到的延迟也在0到2秒之间。假设延迟分布比较均匀,平均值就会接近1秒,这正好能解释“2秒”这个体验数据里很大一部分来源。
第二个被放大的环节是读请求造成的数据库压力。2秒一次轮询意味着,当在线司机端数量到10万量级时,每秒会产生数万次列表查询,而这些请求大部分是空轮询,或者返回的集合几乎没有变化。待办中心的低延迟优化,首先要处理的就是这种空轮询造成的瞬时DB QPS,而不是把单条SQL从50ms优化到5ms。真正有价值的优化是:让没有新事件的查询不要再落到数据库。
第三点,旧的创建逻辑大概率是同步写入。上游订单状态变成已支付之后,HTTP调用待办服务,一旦待办服务线程池阻塞,超时后客户端重试,就有可能在待办表里插入两条一模一样的数据。从这个角度看,“2秒”只是表象,表象背后是等待模型不合理、幂等边界缺失。
1.3 完整延迟链路要切到这几个环节看
从领域事件发生到司机端真正看到待办,需要经过下面几个环节:业务侧本地事务提交、事件产生、消息平台传输、待办服务消费、持久化与缓存更新、端侧通知或轮询触发。
举个例子,一次支付成功后,业务库的事务提交时间可能只有5ms;但如果待办中心是靠另一个定时
