消息幂等

背景 & 问题

本位柯苏远写于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
相关推荐
雷渊19 分钟前
深入分析Spring的事务隔离级别及实现原理
java·后端·面试
Smilejudy29 分钟前
不可或缺的相邻引用
后端
惜鸟29 分钟前
Elasticsearch 的字段类型总结
后端
rebel31 分钟前
Java获取excel附件并解析解决方案
java·后端
微客鸟窝33 分钟前
Redis常用数据类型和命令
后端
熊猫片沃子34 分钟前
centos挂载数据盘
后端·centos
微客鸟窝35 分钟前
Redis配置文件解读
后端
不靠谱程序员37 分钟前
"白描APP" OCR 软件 API 逆向抓取
后端·爬虫
小华同学ai39 分钟前
6.4K star!企业级流程引擎黑马,低代码开发竟能如此高效!
后端·github
Paladin_z42 分钟前
【导入导出】功能设计方案(Java版)
后端