**「中间态交给消息兜底」这个方向我赞成,但它不是把窗口消掉了,而是把窗口从业务代码挪到了消息链路本身**——这个前提认下来,后面的取舍才谈得清。
状态推进消息我建议单独一张表、单独 topic,别和下游通知消息混在一起。原因是两者的死信处理动作根本不同:推进消息重投是幂等的、可以无脑重投;通知消息重投要考虑「用户是不是已经看过了」。混在一个 topic 里,死信告警一响你都不知道该重投还是该丢。还有个更硬的点:推进消息的消费端是「自己」,这是个自依赖——服务整体挂掉时没人会来唤醒你,跨机房部署时尤其明显。另外同一 biz_id 只允许一个推进任务在跑,否则补做流程和正常流程会并发改状态机,你又得加一把 biz_id 级互斥,绕回 CAS 了。
取模分片我不反驳,自增 id 尾部热点这个观察很准,n=4 时实例 3 长期最忙。真要分片我会用 biz_id 哈希而非 id 取模,但代价是扩缩容要从取模换成一致性哈希——或者干脆固定 n 永不改,那就得接受容量天花板。中小规模先 CAS 是对的。
@DS / AbstractRoutingDataSource 和 Seata 的先后顺序,这条是全场最值钱的补充。正解不是让 Seata 去代理路由数据源,而是把每个真实 DataSource 各自用 DataSourceProxy 包好,再塞进路由的 map 里——代理层必须在路由的内侧。Seata 1.5 之后的自动代理能覆盖一部分,但和 dynamic-datasource 组合时我见过只包了外层的情况,上线前还是手动确认一遍更稳。
见习用户






