解决了什么问题?
分布式系统通过消息队列等手段互相解耦带来的状态不一致, 如数据落库成功但是kafka消息发送失败等情况
是什么?
利用本地数据库事务的原子性,将数据入库和消息入库(outbox-records)变为原子性操作。
异步启动一个 poller() worker 定时从 outbox-records 中取出消息尝试发送, 消息至少被成功发送一次, 保证了分布式系统数据的一致性。
问题
- 高并发场景下会导致更高的延迟
- 消息接收端需要做幂等性校验
- 发送失败/超时不能自动回退数据库操作
使用 PostgreSQL 的行锁
通过给 Outbox 表的查询语句加上行锁
SELECT id, event, payload, topic
FROM outbox
FOR UPDATE SKIP LOCKED
就可以让多个 poller 同时抢占发信任务,提高效率的同时也不会导致竞争
SKIP LOCKED 是 pg 独有的拓展,语义是跳过已经上锁的行