大佬教程收集整理的这篇文章主要介绍了Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day34】—— 消息队列2,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
贵州 苗寨 夜景大家好c;我是陈哈哈c;北漂五年。相信大家和我一样c;
都有一个大厂梦
c;作为一名资深Java选手c;深知面试重要性c;接下来我准备用100天时间c;基于Java岗面试中的高频面试题c;以每日3题
的形式c;带你过一遍热门面试题及恰如其分的解答。 一路走来c;随着问题加深c;发现不会的也愈来愈多。但底气着实足了不少c;相信不少朋友和我一样c;日积月累才是最有效的学习方式!想起高三时一个同学的座右铭:只有沉下去c;才能浮上来。
共勉(juan)。
本栏目Java开发岗高频面试题主要出自以下各技术栈:Java基础知识
、集合容器
、并发编程
、JVM
、Spring全家桶
、@H_520_7@myBatis等ORMapping框架、@H_520_7@mySQL数据库、redis缓存
、RabbitMQ消息队列
、Linux操作技巧
等。
在一般网络环境下c;都存在一定的网络延迟、网络抖动
c;网络问题导致消息重复发送的情况是难以避免的c;毕竟网络环境无法预知c;因此@H_520_7@mQ默认允许消息重复发送。是的c;只要通过网络交换数据c;就无法避免这个问题。秉承着打不过就加入的原则c;解决这个问题的办法就是绕过这个问题。
那么问题就变成了:
如果消费端收到两条一样的消息c;应该怎样处理?
RabbitMQ、RocketMQ、Kafkac;都有可能会出现消息重复消费的问题。因为这问题通常不是 MQ 自己保证的c;而是消费方自己来保证的
。
比如说Kafkac; 他实际上有个 offset 的概念(偏移量)c;就是每个消息写进去c;都有一个 offsetc;代表消息的序号c;然后 consumer 消费了数据之后c;每隔一段时间(定时定期
)c;会把自己消费过的消息的 offset 提交一下
。代表我已经消费过了c;就算消费者重启c;Kafka也会让消费者继上次消费到的offset继续消费
。
场景示例:
kafka 中有一条数据:A
、B
c;kafka给这条数据分一个 offset(偏移量)c;offset为: 1001
、1002
。消费者从 kafka 去消费的时候c;也是按照这个顺序去消费。当消费者消费到 offset=1002
的这条数据(此时offset=1001还没消费完)c;刚提交 offset=1002 到 zookeeperc;消费者进程就被重启了
。此时消费过的数据 A
的 offset 还没有提交c;kafka 也就不知道消费者已经消费了1001这条数据
。那么重启之后c;消费者会找 Kafka 把上次消费到的那个地方后面的数据继续传递过来。数据 A
再次被消费。
如果消费者是拿到一条数据就往数据库里写一条c;就会导致把数据 A 在数据库里插入了 2 次
c;导致数据不一致。重复消费其实并不可怕c;可怕的是你没考虑到重复消费时c;怎么保证幂等性
。
幂等性c;比如一个数据或者一个请求c;给后台重复发多次c;针对这类情况c;你得确保对应的数据结果是不会改变的c;不能因为发了多个相同请求导致数据出错。
怎么保证消息队列消费的幂等性?
插入并更新的策略
?发现相同的数据就直接更新他。setc;天然幂等性
。全局唯一的 id
c;类似订单 id 之类的东西c;然后你这里消费到了之后c;先根据这个 id 去 redis 里查一下c;之前消费过吗
?如果没有消费过c;你就处理c;然后这个 id 写 进redis。如果消费过了c;那你就别处理了c;保证别重复处理相同的消息即可。唯一键
来保证重复数据不会重复插入多条。因为有唯一键约束了c;重复数据插入只会报错c;不会导致数据库中出现脏数据。(类似于第一条c;可以通过修改SQLc;转成插入或更新
的策略)@H_635_6@mySQL中的插入或替换
、插入或更新
、插入或忽略
策略c;详情可参考《MySQL中特别实用的几种sql语句送给大家》
课间休息c;看看 广州 城中村一角。
消息队列中的若干消息如果是对同一个数据进行操作c;这些操作又具有先后关系c;必须按顺序执行c;否则可能会造成数据错误。
比如有三个请求c;是对数据库中的同一条数据进行了插入->更新->删除
操作c;执行顺序必须保证c;如果变成删除->更新->插入
就很可笑了c;造成最终数据不一致
。
顺序错乱的场景:
一个queuec;有多个consumer去消费c;这样就会造成顺序的错误c;consumer从MQ里面读取数据是有序的
c;但是每个consumer的执行时间是不固定的
c;无法保证先读到消息的consumer一定先执行完操作c;这样就会出现消息并没有按照顺序执行c;造成数据顺序错误。
rabbitmq如何保证消息的消费顺序
将原来的一个queue拆分成多个queuec;每个queue都有一个自己的consumer
。该种方案的核心是生产者在投递消息的时候根据业务数据关键值(例如订单ID哈希值对订单队列数取模)来将需要保证先后顺序的同一类数据(同一个订单的数据) 发送到同一个queue当中c;让同一个consumer来按顺序处理
。
图片取自中华石杉架构课件
一个queue就一个consumerc;在consumer中维护多个内存队列
c;根据业务数据关键值(例如订单ID哈希值对内存队列数取模)将消息加入到不同的内存队列中
c;然后多个真正负责处理消息的线程
去各自对应的内存队列
当中获取消息进行消费。
图片取自中华石杉架构课件
RabbitMQ保证消息顺序性总结:
核心思路就是根据业务数据关键值划分成多个消息集合c;而且每个消息集合中的消息数据都是有序的c;每个消息集合有自己独立的一个consumer。多个消息集合的存在保证了消息消费的效率c;每个有序的消息集合对应单个的consumer也保证了消息消费时的有序性
。也就是保证了生产者 - MQServer - 消费者
是一对一对一的关系。
休息一下
这种就是问的实际业务场景中的问题c;这种情况原因一般是:消费者consumer出了bug或性能问题c;消费量远低于消息增量。导致消息积压越来越多c;几百万至上千万c;就算consumer及时恢复c;也要吃几个小时才能吃完
。同时c;已经出现部分积压的消息过期失效c;丢失了数据
。
这时候首先想到的是横向扩consumer
c;先把这些消息尽快吃掉再说。。具体如下:
临时将queue资源和consumer资源扩大10倍c;以正常的10倍速度来消费数据
;像上面说到的c;如果大量积压中的消息过期了c;就会被删掉c;数据就丢失了。这种其实没有啥好办法c;只能等解决积压问题后再处理了。
比如夜深人静c;大家都睡觉了c;这时积压的消息也吃完了c;你揉了揉眼c;冲了一杯免费咖啡c;找到写好的程序c;把过期的数据找回来并重新放到MQ中c;让他重新消费一遍就行了。
这样如果是消费者这边的硬伤c;就只能扩容来搞了c;多加一些服务器部署消费者程序。当然c;如果可以通过优化程序解决c;肯定要选择后者c;无论从技术还是业务角度来优化。否则经常写满就意味着经常丢数据c;只能人工写程序去补数据c;工作量更大c;加班更严重c;我可不愿意加班。
今天我们复习了面试中常考的消息队列
相关的三个问题c;你做到心中有数了么?对了c;如果你的朋友也在准备面试c;请将这个系列扔给他c;如果他认真对待c;肯定会感谢你的!!
好了c;今天就到这里c;学废了的同学c;记得在评论区留言:打卡。
c;给同学们以激励。
以上是大佬教程为你收集整理的Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day34】—— 消息队列2全部内容,希望文章能够帮你解决Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day34】—— 消息队列2所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。