消息队列存在的问题
# 一.重复消费
产生原因,大多数的消息队列都有消息重新发送的机制。当一个消费者消费一个消息时,肯呢个会出现服务的网络抖动,开发人员代码Bug,还有数据问题等都可能处理失败要求重发的。
听起来没有问题,但是万一多个服务监听一个消息呢?一个服务挂了,要求重发,那么该服务成功消费一次,但是其他服务会消费两次该服务,这就是重复消费。
解决方案:
一.前端保证
- 前端保证幂等性的方法按钮只能点击一次用户点击按钮后将按钮置灰,或者显示loading状态
- RPG模式:即Post-Redirect-Get,当客户提交表单 (opens new window)后,去执行一个客户端的重定向,转到提交成功页面。避免用户按F5刷新导致的重复提交,也能消除按浏览器后退键导致的重复提交问题。目前绝大多数公司都是这样做的,比如淘宝,京东等
二.后端保证
接口幂等:
幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。
幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现.
2
3
4
5
6
7
怎么保证幂等性?
分为强校验(重要逻辑,设计金额)和弱校验(不是关键逻辑)
- 全局唯一id实现幂等性
强校验:
适用于一些比较重要的场景,比如涉及金额相关的操作
通常会用订单号+业务场景 这样的唯一标识去查流水表,查到就直接返回(其他消费者重复消费到一个消费者),没有查到才去真正走一个逻辑(当前消费者因为上一个消息丢失了,现在因重复发送收到了一个真正的消息)
https://mp.weixin.qq.com/s?__biz=MzAwNDA2OTM1Ng==&mid=2453140974&idx=1&sn=22ee07f493f029f9ac8ae19266d14283&scene=21#wechat_redirect
弱校验
用在不是很重要的场景,如短信发送的逻辑。
这个简单,一些不重要的场景,比如给谁发短信啥的,我就把这个id+场景唯一标识作为Redis的key,放到缓存里面失效时间看你场景,一定时间内的这个消息就去Redis判断。(redis+LRU实现滑动窗口限流)
用KV就算消息丢了可能这样的场景也没关系,反正丢条无关痛痒的通知短信嘛(你敢说你没验证码短信丢失的情况?)。
# 二.顺序消费
介绍:一般都是同个业务场景下不同几个操作的消息同时过去,本身顺序是对的,但是你发出去的时候同时发出去了,消费的时候却乱掉了,这样就有问题了。
比如在一个大并发量操作数据库的情况下,我们将一些操作放到消息列表中实现高峰削谷。但是如果我们以一定的顺序放到队列中,但是被消费者消费时如果不是一个顺序的话,可能会造成很多的问题。
解决方案:不同的消息队列的具体实现不同,中间件可能会保证队列中小消息顺序,消费者也应该保证消息的消息顺序
在kafka中如何保证顺序性?https://blog.csdn.net/java_atguigu/article/details/123920233
# 三. 分布式事务
与单节点的事务不同。就拿消息队列来说,不同的消费者可能会去消费不同的消息,那么一个消费者成功了,另一个消费者失败了,那是不是不满足事务应该进行回滚呢?但是对于非单节点的分布式来说,拿我们以前的Transactional已经无法解决问题了。
# 四.消息丢失
可能因为网络原因造成消息丢失,或因为事务原因导致一个消息没有被正确消费