消息幂等

背景 & 问题

本位柯苏远写于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
相关推荐
Iced_Sheep36 分钟前
干掉 if else 之策略模式
后端·设计模式
XINGTECODE1 小时前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺1 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
凡人的AI工具箱2 小时前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang
先天牛马圣体2 小时前
如何提升大型AI模型的智能水平
后端
java亮小白19972 小时前
Spring循环依赖如何解决的?
java·后端·spring
2301_811274312 小时前
大数据基于Spring Boot的化妆品推荐系统的设计与实现
大数据·spring boot·后端
草莓base3 小时前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
Ljw...3 小时前
表的增删改查(MySQL)
数据库·后端·mysql·表的增删查改