写点什么

Java 岗大厂面试百日冲刺 - 日积月累,每日三题【Day34,rabbitmq 集群同步原理

用户头像
极客good
关注
发布于: 刚刚

[](


)追问 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


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


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,先把这些消息尽快吃掉再说。。具体如下:


  1. 先修复 consumer 的问题,确保其恢复消费速度,然后将现有 cnosumer 都停掉;

  2. kafka 的话,比如新建一个 topic,partition 是原来的 10 倍,临时建立好原先 10 倍或者 20 倍的 queue 数量;

  3. 写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的 10 倍数量的 queue 里去;

  4. 接着临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据;

  5. 这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据

  6. 等快速消费完积压数据之后,恢复成原来部署。


[](


)追问 1:MQ 消息过期失效怎么办?




像上面说到的,如果大量积压中的消息过期了,就会被删掉,数据就丢失了。这种其实没有啥好办法,只能等解决积压问题后再处理了。


比如夜深人静,大家都睡觉了,这时积压的消息也吃完了,你揉了揉眼,冲了一杯免费咖啡,找到写好的程序,把过期的数据找回来并重新放到 MQ 中,让他重新消费一遍就行了。


[](


)追问 3:如果 mq 经常写满你会怎么办?

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day34,rabbitmq集群同步原理