消息幂等

背景 & 问题

本位柯苏远写于2024年4月18日22点15分

还是在公司的整个电商业务中要接入sms 短信发送功能。

上一篇文章地址:分布式锁实战 - 掘金 (juejin.cn)

这周到实际开发过程了,首先将整个需求的技术方案设计好了,然后进行开发。整个方案的设计图如下所示:

A服务:表示每个会产生sms消息的触发点,不单单是一个服务,而是很多个。 B服务:对外提供一个插入消息表的接口,所有触发发送sms短信的服务点都调用这个接口。 C服务:是一个轮询服务,对短信表进行轮询,找到待发送的sms 短信,然后调用sms api 发送短信给客户。

红框部分有个问题:

当A向B推送消息的时候,在B收到消息往数据库成功插入数据之后,当要给A服务返回成功标识的时候,由于网络问题接口超时了,A那边收到的返回就是接口超时,那么对于A服务来说我并不知道这个消息到底成功推送没有?A此时应该怎么做?如果重新推送的话可能会在数据库存入一个一模一样的消息。如果不重新推送的话,那消息可能就丢失了。 归根结底就是由于在第一步消息推送的时候如果发送接口超时,在A服务中我不知道如何处理当前超时的消息。

如何解决

再次重申问题:

  1. 如果推送消息接口超时,我按推送失败处理,继续推送这个消息,那么就可能往数据库插入两条一模一样的消息,导致的结果就是客户收到两条一模一样的消息。
  2. 如果推送消息接口超时,我按推送成功处理,不对这个消息再次推送,那么可能造成的问题就更大了,消息丢失了,这肯定不允许。

既然存在两个问题,那么我们就分别想解决方案。

针对问题1:解决思路挺直观的,因为会往数据库插入重复数据,所以我们给每个消息一个唯一id,当这个消息插入数据库之后,这个消息唯一id也存入了,然后对这个消息唯一id字段进行设置唯一键。这样在数据库层面就避免了消息存储重复的可能。

针对问题2:推送接口超时,不推的话,大部分业务是接受不了的,因为消息丢了,所以我们继续推一次这个消息,不用担心会重复发送,因为在存储层面我们用了消息唯一id做唯一键。

疑问

消息的唯一id怎么产生?

唯一id有很多种,用uuid,或者雪花算法都可以,我们这里用的是uuid。

将一个消息和一个uuid绑定的时候,当超时之后,这个消息对应的uuid要不要改?

肯定是不能改的,改了的话,在数据库层面就会重复插入同一条消息

那么不能改的话,当这个消息推送超时,如何解决继续用这个uuid推送?

其实很简单,让uuid变成这个消息的一个属性,然后推送超时,将这个消息弄到一个本地的队列里去,进行重试。一定要注意,每个消息的唯一id是不会变的。

后续安排

这个是我目前在工作中接触的第一个幂等场景,后续再看看其它幂等情况。

总结

  1. 消息重复发送的可能性。
  2. 引入消息唯一id在数据库层面做唯一索引。
  3. 消息推送超时,在内存进行重试,消息的唯一id是和每个消息强绑的,也就是说再重试的时候不能给消息生成新的唯一id
相关推荐
CodeSaku13 分钟前
是设计模式,我们有救了!!!(七、责任链模式:Chain of Responsibity)
后端
贵州数擎科技有限公司28 分钟前
Go-zero 构建 RPC 与 API 服务全流程
后端
笃行3501 小时前
KingbaseES读写分离集群架构解析
后端
IT_陈寒2 小时前
Python 3.12 新特性实战:10个性能优化技巧让你的代码快如闪电⚡
前端·人工智能·后端
绝无仅有4 小时前
前端开发环境搭建:从安装 Node 到成功运行代码
后端·面试·github
yshhuang4 小时前
在Windows上搭建开发环境
前端·后端
绝无仅有4 小时前
某个互联网大厂的Elasticsearch基础面试题与答案
后端·面试·github
无责任此方_修行中4 小时前
AWS IoT Core 成本优化实战:从 PoC 到生产的省钱之旅
后端·架构·aws
ITMan彪叔4 小时前
Java MQTT 主流开发方案对比
java·后端
Cache技术分享4 小时前
188. Java 异常 - Java 异常处理规范
前端·后端