🌈🌈🌈🌈🌈🌈🌈🌈
欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术
的推送
发送 资料
可领取 深入理解 Redis 系列文章结合电商场景讲解 Redis 使用场景
、中间件系列笔记
和编程高频电子书
!
文章导读地址:点击查看文章导读!
🍁🍁🍁🍁🍁🍁🍁🍁
在分布式业务系统中,常常可能一个接口会被调用多次,而有些接口多次调用会存在问题
就比如对于订单创建来说,如果不消息调用多次,去创建了多个订单,肯定是不符合业务逻辑的,因此需要去加一个 幂等性控制
保证同一个用户,在短时间内对某一个订单的多次操作呈现出和操作一次相同的效果,这就保证了接口的幂等性
那什么会出现幂等性问题呢?
网络不稳定
:当网络不稳定时,客户端短时间内可能 发送多次相同的请求
,服务器需要正确处理从而避免重复操作导致意外情况重试机制
:在 MQ 中,可能对同一个任务,因为网络原因导致 推送到了 MQ 多次
,导致任务被多次消费,就比如说给用户发送一个邮箱通知的任务,如果被推送多次,没有进行幂等性控制的话,就会对该用户发送多次通知分布式系统
:在分布式系统中,可能会出现 不同节点同时处理相同的操作
,这时候也要进行幂等性控制因此,对于多次操作会出现意外情况的场景,都需要做幂等性控制,主要有以下3种方式:
这里拿用户邮箱推送来说,根据用户邮箱以及用户 id 设置一个唯一的 key:email_unique:{emailId}:{userId}
,当给某个用户推送完毕,就在 Redis 中设置一个 k-v
(这里过期时间设置为 30 分钟即可,不需要设置太久)
每当开始用户推送的时候,就去拿这个 key 去判断是否在 Redis 中存在,如果存在,表示已经推送过了,就不再重复操作
在多线程情况下,还是存在幂等性短暂失效的问题,当两个线程对同一个用户的推送请求同时进入到幂等性控制这行代码,发现 key 在 Redis 中不存在,于是还是重复推送
因此,这种方案适合于对幂等性不严格要求的场景下,而且在调用链路比较长的场景中,也比较实用
并且该方案使用起来非常简单
private AltResult handleMessageExt(MessageExt messageExt) {
// 幂等控制
if (StringUtils.isNotBlank(redisTemplate.opsForValue().get(message.cacheKey()))) {
return new AltResult(null);
}
// ... 推送
// 推送成功之后记录到 redis
redisTemplate.opsForValue().set(message.cacheKey(), UUID.randomUUID().toString());
return new AltResult(null);
}
针对调用方重试接口的情况,例如重复提交订单,这种幂等性设计可以使用 Token 机制来防止重复提交。
具体控制流程如下:
MySQL 控制幂等性有两种方式:
可以对某个字段建立唯一索引
:就比如订单场景中,将订单号设置为唯一索引,当重复插入时,就会报错 DuplicatedKeyException
, 那么我们就可以捕获该错误,返回用户提示,来避免重复执行操作
可以直接去数据库中查询某个订单是否存在,其实第一种方式类似,只不过第一种方式是直接操作,再捕获异常,这一种方式可以在操作前就判断幂等性