什么是最大努力通知方案
最大努力通知型 (Best-effort delivery) 是最简单的一种柔性事务,适用于一些最终一致性时间敏感度低的业务,且被动方处理结果不影响主动方的处理结果。典型的使用场景:如银行通知、商户通知等。
最大努力通知型的实现方案,一般符合以下特点:
- 不可靠消息:业务活动主动方,在完成业务处理之后,向业务活动的被动方发送消息,直到通知 N 次后不再通知,允许消息丢失。
- 消息重复处理:由于可能存在消息重试发送的情况,接收方需要能够识别并处理重复消息,避免业务逻辑因重复通知而受到影响。
- 定期校对:业务活动的被动方,根据定时策略,向业务活动主动方查询 (主动方提供查询接口),恢复丢失的业务消息。
- 补偿机制:在某些情况下,如果仅依赖通知无法确保业务正确性,还需要有补偿措施来修复因通知失败导致的数据不一致问题。
实现考虑
- 消息队列:利用消息队列服务(如 RocketMQ、Kafka 等)来管理通知消息的发送、重试和死信处理。
- 幂等性设计:确保接收方的处理逻辑具有幂等性,即多次接收同一消息不会导致业务状态的改变。
- 状态检查与恢复:提供查询接口让被动方能主动检查事务状态,实现数据的自我修复。
示例
一个短信发送平台,背景是公司内部有多个业务都有发送短信的需求,如果每个业务独立实现短信发送功能,存在功能实现上的重复。因此专门做了一个短信平台项目,所有的业务方都接入这个短信平台,来实现发送短信的功能。简化后的架构如下所示:
短信发送流程如下:
-
业务方将短信发送请求提交给短信平台。
-
短信平台接收到要发送的短信,记录到数据库中,并标记其状态为【已接收】。
-
短信平台调用外部短信发送供应商的接口,发送短信。外部供应商的接口也是异步将短信发送到用户手机上,因此这个接口调用后,立即返回,进入第 4 步。
-
更新短信发送状态为【已发送】
-
短信发送供应商异步通知短信平台短信发送结果。而通知可能失败,因此最多只会通知 N 次。
-
短信平台接收到短信发送结果后,更新短信发送状态,可能是【成功】,也可能【失败】(如手机欠费)。到底是成功还是失败并不重要,重要的是我们知道了这调短信发送的最终结果
-
如果最多只通知 N 次,如果都失败了的话,那么短信平台将不知道短信到底有没有成功发送。因此短信发送供应商需要提供一个查询接口,以方便短信平台驱动的去查询,进行定期校对。
在这个案例中,短信发送供应商通知短信平台短信发送结果的过程,就是最典型的最大努力通知型方案,通知了 N 次就不再通知。通过提供一个短信结果查询接口,让短信平台可以进行定期的校对。而由于短信发送业务的时间敏感度并不高,比较适合采用这个方案。
需要注意的是,短信结果查询接口很重要,必须要进行定期校对。因为后期要进行对账,笔者在做这个项目的时候,一个月的短信发送总量在高峰期可以达到 1 亿条左右,即使一条短信只要 5 分钱,一个月就有 500W。
(这个 5 分钱是笔者估计的,在这么大的量的情况,一条短信到底需要多少钱我也不知道。因为商务对接过程,是没有我靓丽的身影的。总之短信发送要花很多钱,如果短信发送供应商说短信都发送成功了,而短信平台却一条成功的记录都没有,出现这种扯皮的情况就不好了)
最后提一点:当当网开源数据库中间件 sharding-jdbc 使用了最大努力通知型来实现分库分表情况下数据的一致性,说实话,个人觉得最大努力通知型不太适合于这种场景。目前,sharding-jdbc 也正在开发另一种柔性事务方案 TCC。
Reference