使用RocketMQ、RabbitMQ、Kafka的延时消息,消息在发送到消息队列服务端后并不会立马投递,而是根据消息中的属性延迟固定时间后才投递给消费者。
目录
为什么使用消息队列?
解耦
异步
削峰
消息队列有什么优点和缺点?
优点:解耦、异步、削峰
缺点:
(1)系统可用性降低
(2)系统复杂性提高
(3)一致性问题
消息重复的原因和解决办法?
原因:
解决办法:
什么是幂等操作?
常见办法
为什么使用消息队列?
这就是要问消息队列都有哪些使用场景,说说项目里具体是什么场景。
面试官最想听到的回答是:公司什么业务场景应用到了,有什么技术挑战,不用kafka会怎么样,用了会怎样;如:一个insert接口,存储上万条数据时,就会垮掉,用了消息中间件获取到的数据存到kafka,等待接收者(消费者)慢慢处理。。。。。
解耦
1号系统发送数据到ABC三个子系统,接口调用发送,如果有一个D系统也需要这个数据怎么办????如果B系统不需要了呢???当前1号系统要时时刻刻考虑ABCD四个子系统挂了怎么办?要不要重新发送?
结合系统中类似的场景,一个系统或者一个模块,调用了多个系统或者模块,互相之间调用很复杂,维护起来很麻烦。
异步
1号系统接收一个请求,需要再自己本地写库,还需要在ABC三个系统写库,自己本地写库需要20ms,ABC三个系统写库分别需要200ms、300ms、400ms;最终耗时是20 + 200 + 300 + 400 = 920 ms, 异步后,ABC三个子系统各自写库的时间,1号系统不再考虑了。
削峰
1号系统在0~20点 没什么事,每秒并发请求数量也就100个,每次一到20~24 点,每秒并发请求数量会增加到1万。如果系统最大的处理能力每秒钟处理1000个请求。。。这时需要我们进行流量的削峰,让系统可以平缓的处理这些突增的请求。
消息队列有什么优点和缺点?
优点:解耦、异步、削峰
缺点:
(1)系统可用性降低
系统引入的外部依赖越多,越容易挂掉,本来是1号系统调用ABC三个子系统的接口没啥问题,突然加个MQ进来,万一mq挂了,整套系统就崩了,业务就停顿了。
(2)系统复杂性提高
突然加个MQ进来,怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序?(👇下方有解决方案)。
(3)一致性问题
子系统A处理完直接返回成功了,用户都以为这个请求成功了;问题是BCD三个子系统, BC两个子系统写库成功了,结果D系统写库失败了,就会导致数据不一致了。
引入mq好处很多,也有针对ta带来的弊端。
消息重复的原因和解决办法?
(跟老师、前辈学习得出的)
原因:
(1)消息发送端 应用的消息重复发送,有以下几点:
★ 消息发送端 发送消息 给mq,mq收到消息 并成功存储,而这时mq 出现了问题,导致应用端没有收到 消息发送成功的返回提示,又进行重试产生了重复;
★ 消息中间件 因为负载高响应变慢, 成功把消息存储到消息中间件后,返回“成功”这个结果是超时的;
★ 消息中间件 将消息成功写入消息存储,再返回时网络出现问题,导致应用发送端重试,而重试时网络恢复,因此导致消息重复;
总结:消息发送端 产生消息重复 主要原因是消息成功进入消息存储后,因为各种原因导致 消息发送端 没有收到“成功”的返回结果,并且又有重试机制,导致消息重复。
(2)消息到达了消息存储,由 消息中间件进行向外的 投递时产生重复,有以下几点:
★ 消息被投递到 消息接收者应用进行处理,处理完毕后应用出问题了,mq不知道消息处理结果,会再次投递;
★ 消息被投递到 消息接收者应用进行处理,处理完毕后网络出现了问题,mq没收到消息处理结果,会再次投递;
★ 消息被投递到 消息接收者应用进行处理,处理时间比较长,mq因为消息超时会再次投递;
★ 消息被投递到 消息接收者应用进行处理,处理完毕后mq出现问题了,没能收到消息结果并处理,会再次投递;
★ 消息被投递到 消息接收者应用进行处理,处理完毕后mq收到结果 但是遇到消息存储故障,没能更新投递状态,会再次投递;
总结:投递过程中产生的消息重复 接收主要是因为消息接收者 成功处理消息后, 消息中间件不能及时更新投递状态造成的。
解决办法:
要求消息接收者 来处理这种重复的情况,也就是要求 消息接收者的 消息处理是幂等操作。
什么是幂等操作?
① 任意多次执行所产生的影响均与一次执行的影响相同;
② 不会影响系统状态,也不用担心重复执行对系统造成的改变;
例1:SQL操作, update Test set count = 10 where id = '0001';
这个操作多次执行,id等于0001的记录中 count字段的值都为10,这个操作就是幂等操作,不用担心这个操作被重复;
例2:另一条SQL,update Test set count = count + 1 where id = 0001 ;
这条语句就不是幂等的,一旦重复,结果就会发生变化。
常见办法
应对消息重复的办法是,使消息接收端的处理是一个幂等操作。 这样做就降低了 消息中间件 的整体复杂性,不过也给使用 消息中间件的 消息接收端 带来了一定限制。
1、MVCC:
多版本并发控制,乐观锁的一种实现,在生产者发送消息时, 进行数据更新时需要带上数据的版本号, 消费者去更新时需要比较持有数据的版本号,版本号不一致的操作无法成功。
2、去重表:
利用数据库的特性实现幂等,常用的就是在表上建立唯一索引,保证某一类数据一旦执行完毕,后续同样的请求不再重复处理了(可以通过一张日志表记录已经处理成功的消息ID, 如果新的消息ID在日志表中存在,就不再处理消息了。)
MQ消息丢失,有什么解决办法?
下游系统收到消息后——做回执即:ACK