Java 岗大厂面试百日冲刺 - 日积月累,每日三题【Day34,rabbitmq 集群同步原理
[](
)追问 1:如何保证消息不被重复消费?如何实现幂等性?
幂等性,比如一个数据或者一个请求,给后台重复发多次,针对这类情况,你得确保对应的数据结果是不会改变的,不能因为发了多个相同请求导致数据出错。
怎么保证消息队列消费的幂等性?
比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 就行。对了,ES 的插入接口是不是就采用了
插入并更新的策略
?发现相同的数据就直接更新他。如果是写 Redis,那没问题,反正每次都是
set,天然幂等性
。比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个
全局唯一的 id
,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去 Redis 里查一下,之前消费过吗
?如果没有消费过,你就处理,然后这个 id 写 进 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。比如基于数据库的
唯一键
来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。(类似于第一条,可以通过修改 SQL,转成插入或更新
的策略)
MySQL 中的
插入或替换
、插入或更新
、插入或忽略
策略,详情可参考[《MySQL 中特别实用的几种 SQL 语句送给大家》](
)
课间休息,看看 广州 城中村一角。
[](
)面试题 2:RabbitMQ 如何保证消息的顺序性
======================================================================================
消息队列中的若干消息如果是对同一个数据进行操作,这些操作又具有先后关系,必须按顺序执行,否则可能会造成数据错误。
比如有三个请求,是对数据库中的同一条数据进行了插入->更新->删除
操作,执行顺序必须保证,如果变成删除->更新->插入
就很可笑了,造成最终数据不一致
。
顺序错乱的场景:
一个 queue,有多个 consumer 去消费,这样就会造成顺序的错误,consumer从MQ里面读取数据是有序的
,但是每个consumer的执行时间是不固定的
,无法保证先读到消息的 consumer 一定先执行完操作,这样就会出现消息并没有按照顺序执行,造成数据顺序错误。
rabbitmq 如何保证消息的消费顺序
将原来的一个 queue 拆分成多个 queue,每个queue都有一个自己的consumer
。该种方案的核心是生产者在投递消息的时候根据业务数据关键值(例如订单 ID 哈希值对订单队列数取模)来将需要保证先后顺序的同一类数据(同一个订单的数据) 发送到同一个 queue 当中,让同一个consumer来按顺序处理
。
![在这里插入图片描述](https://img-blog.csdnimg.cn/9b429b11b681491c9f1d7821917906d7.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5n
aGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MzkwNTQ1,size_16,color_FFFFFF,t_70#pic_center)
[图片取自中华石杉架构课件](
)
一个 queue 就一个 consumer,在consumer中维护多个内存队列
,根据业务数据关键值(例如订单 ID 哈希值对内存队列数取模)将消息加入到不同的内存队列中
,然后多个真正负责处理消息的线程
去各自对应的内存队列
当中获取消息进行消费。
[图片取自中华石杉架构课件](
)
RabbitMQ 保证消息顺序性总结:
核心思路就是根据业务数据关键值划分成多个消息集合,而且每个消息集合中的消息数据都是有序的,每个消息集合有自己独立的一个 consumer。多个消息集合的存在保证了消息消费的效率,每个有序的消息集合对应单个的consumer也保证了消息消费时的有序性
。也就是保证了生产者 - MQServer - 消费者
是一对一对一的关系。
休息一下
[](
)面试题 3:消息队列满了以后该怎么处理?比如现在大量消息在 MQ 里长时间积压,你会如何解决?
===========================================================================================================
这种就是问的实际业务场景中的问题,这种情况原因一般是:消费者 consumer 出了 bug 或性能问题,消费量远低于消息增量。导致消息积压越来越多,几百万至上千万,就算 consumer 及时恢复,也要吃几个小时才能吃完
。同时,已经出现部分积压的消息过期失效,丢失了数据
。
这时候首先想到的是横向扩consumer
,先把这些消息尽快吃掉再说。。具体如下:
先修复 consumer 的问题,确保其恢复消费速度,然后将现有 cnosumer 都停掉;
kafka 的话,比如新建一个 topic,partition 是原来的 10 倍,临时建立好原先 10 倍或者 20 倍的 queue 数量;
写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的 10 倍数量的 queue 里去;
接着临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据;
这种做法相当于是
临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据
;等快速消费完积压数据之后,恢复成原来部署。
[](
)追问 1:MQ 消息过期失效怎么办?
像上面说到的,如果大量积压中的消息过期了,就会被删掉,数据就丢失了。这种其实没有啥好办法,只能等解决积压问题后再处理了。
比如夜深人静,大家都睡觉了,这时积压的消息也吃完了,你揉了揉眼,冲了一杯免费咖啡,找到写好的程序,把过期的数据找回来并重新放到 MQ 中,让他重新消费一遍就行了。
[](
)追问 3:如果 mq 经常写满你会怎么办?
评论