active mq topic消费后删除_《我想进大厂》之MQ夺命连环11问

bd33a755-9017-eb11-8da9-e4434bdf6706.png

继之前的mysql夺命连环之后,我发现我这个标题被好多套用的,什么夺命zookeeper,夺命多线程一大堆,这一次,开始面试题系列MQ专题,消息队列作为日常常见的使用中间件,面试也是必问的点之一,一起来看看MQ的面试题。

你们为什么使用mq?具体的使用场景是什么?

mq的作用很简单,削峰填谷。以电商交易下单的场景来说,正向交易的过程可能涉及到创建订单、扣减库存、扣减活动预算、扣减积分等等。每个接口的耗时如果是100ms,那么理论上整个下单的链路就需要耗费400ms,这个时间显然是太长了。

c033a755-9017-eb11-8da9-e4434bdf6706.png

如果这些操作全部同步处理的话,首先调用链路太长影响接口性能,其次分布式事务的问题很难处理,这时候像扣减预算和积分这种对实时一致性要求没有那么高的请求,完全就可以通过mq异步的方式去处理了。同时,考虑到异步带来的不一致的问题,我们可以通过job去重试保证接口调用成功,而且一般公司都会有核对的平台,比如下单成功但是未扣减积分的这种问题可以通过核对作为兜底的处理方案。

c133a755-9017-eb11-8da9-e4434bdf6706.png

使用mq之后我们的链路变简单了,同时异步发送消息我们的整个系统的抗压能力也上升了。

那你们使用什么mq?基于什么做的选型?

我们主要调研了几个主流的mq,kafka、rabbitmq、rocketmq、activemq,选型我们主要基于以下几个点去考虑:

  1. 由于我们系统的qps压力比较大,所以性能是首要考虑的要素。
  2. 开发语言,由于我们的开发语言是java,主要是为了方便二次开发。
  3. 对于高并发的业务场景是必须的,所以需要支持分布式架构的设计。
  4. 功能全面,由于不同的业务场景,可能会用到顺序消息、事务消息等。

基于以上几个考虑,我们最终选择了RocketMQ。

c333a755-9017-eb11-8da9-e4434bdf6706.png

你上面提到异步发送,那消息可靠性怎么保证?

消息丢失可能发生在生产者发送消息、MQ本身丢失消息、消费者丢失消息3个方面。

生产者丢失

生产者丢失消息的可能点在于程序发送失败抛异常了没有重试处理,或者发送的过程成功但是过程中网络闪断MQ没收到,消息就丢失了。

由于同步发送的一般不会出现这样使用方式,所以我们就不考虑同步发送的问题,我们基于异步发送的场景来说。

异步发送分为两个方式:异步有回调和异步无回调,无回调的方式,生产者发送完后不管结果可能就会造成消息丢失,而通过异步发送+回调通知+本地消息表的形式我们就可以做出一个解决方案。以下单的场景举例。

  1. 下单后先保存本地数据和MQ消息表,这时候消息的状态是发送中,如果本地事务失败,那么下单失败,事务回滚。
  2. 下单成功,直接返回客户端成功,异步发送MQ消息
  3. MQ回调通知消息发送结果,对应更新数据库MQ发送状态
  4. JOB轮询超过一定时间(时间根据业务配置)还未发送成功的消息去重试
  5. 在监控平台配置或者JOB程序处理超过一定次数一直发送不成功的消息,告警,人工介入。

c533a755-9017-eb11-8da9-e4434bdf6706.png

一般而言,对于大部分场景来说异步回调的形式就可以了,只有那种需要完全保证不能丢失消息的场景我们做一套完整的解决方案。

MQ丢失

如果生产者保证消息发送到MQ,而MQ收到消息后还在内存中,这时候宕机了又没来得及同步给从节点,就有可能导致消息丢失。

比如RocketMQ:

RocketMQ分为同步刷盘和异步刷盘两种方式,默认的是异步刷盘,就有可能导致消息还未刷到硬盘上就丢失了,可以通过设置为同步刷盘的方式来保证消息可靠性,这样即使MQ挂了,恢复的时候也可以从磁盘中去恢复消息。

比如Kafka也可以通过配置做到:

acks=all 只有参与复制的所有节点全部收到消息,才返回生产者成功。这样的话除非所有的节点都挂了,消息才会丢失。
replication.factor=N,设置大于1的数,这会要求每个partion至少有2个副本
min.insync.replicas=N,设置大于1的数,这会要求leader至少感知到一个follower还保持着连接
retries=N,设置一个非常大的值,让生产者发送失败一直重试

虽然我们可以通过配置的方式来达到MQ本身高可用的目的,但是都对性能有损耗,怎样配置需要根据业务做出权衡。

消费者丢失

消费者丢失消息的场景:消费者刚收到消息,此时服务器宕机,MQ认为消费者已经消费,不会重复发送消息,消息丢失。

RocketMQ默认是需要消费者回复ack确认,而kafka需要手动开启配置关闭自动offset。

消费方不返回ack确认,重发的机制根据MQ类型的不同发送时间间隔、次数都不尽相同,如果重试超过次数之后会进入死信队列,需要手工来处理了。(Kafka没有这些)

c633a755-9017-eb11-8da9-e4434bdf6706.png

你说到消费者消费失败的问题,那么如果一直消费失败导致消息积压怎么处理?

因为考虑到时消费者消费一直出错的问题,那么我们可以从以下几个角度来考虑:

  1. 消费者出错,肯定是程序或者其他问题导致的,如果容易修复,先把问题修复,让consumer恢复正常消费
  2. 如果时间来不及处理很麻烦,做转发处理,写一个临时的consumer消费方案,先把消息消费,然后再转发到一个新的topic和MQ资源,这个新的topic的机器资源单独申请,要能承载住当前积压的消息
  3. 处理完积压数据后,修复consumer,去消费新的MQ和现有的MQ数据,新MQ消费完成后恢复原状

c833a755-9017-eb11-8da9-e4434bdf6706.png

那如果消息积压达到磁盘上限,消息被删除了怎么办?

这。。。他妈都删除了我有啥办法啊。。。冷静,再想想。。有了。

ca33a755-9017-eb11-8da9-e4434bdf6706.png

最初,我们发送的消息记录是落库保存了的,而转发发送的数据也保存了,那么我们就可以通过这部分数据来找到丢失的那部分数据,再单独跑个脚本重发就可以了。如果转发的程序没有落库,那就和消费方的记录去做对比,只是过程会更艰难一点。

说了这么多,那你说说RocketMQ实现原理吧?

RocketMQ由NameServer注册中心集群、Producer生产者集群、Consumer消费者集群和若干Broker(RocketMQ进程)组成,它的架构原理是这样的:

  1. Broker在启动的时候去向所有的NameServer注册,并保持长连接,每30s发送一次心跳
  2. Producer在发送消息的时候从NameServer获取Broker服务器地址,根据负载均衡算法选择一台服务器来发送消息
  3. Conusmer消费消息的时候同样从NameServer获取Broker地址,然后主动拉取消息来消费

cb33a755-9017-eb11-8da9-e4434bdf6706.png

为什么RocketMQ不使用Zookeeper作为注册中心呢?

我认为有以下几个点是不使用zookeeper的原因:

  1. 根据CAP理论,同时最多只能满足两个点,而zookeeper满足的是CP,也就是说zookeeper并不能保证服务的可用性,zookeeper在进行选举的时候,整个选举的时间太长,期间整个集群都处于不可用的状态,而这对于一个注册中心来说肯定是不能接受的,作为服务发现来说就应该是为可用性而设计。
  2. 基于性能的考虑,NameServer本身的实现非常轻量,而且可以通过增加机器的方式水平扩展,增加集群的抗压能力,而zookeeper的写是不可扩展的,而zookeeper要解决这个问题只能通过划分领域,划分多个zookeeper集群来解决,首先操作起来太复杂,其次这样还是又违反了CAP中的A的设计,导致服务之间是不连通的。
  3. 持久化的机制来带的问题,ZooKeeper 的 ZAB 协议对每一个写请求,会在每个 ZooKeeper 节点上保持写一个事务日志,同时再加上定期的将内存数据镜像(Snapshot)到磁盘来保证数据的一致性和持久性,而对于一个简单的服务发现的场景来说,这其实没有太大的必要,这个实现方案太重了。而且本身存储的数据应该是高度定制化的。
  4. 消息发送应该弱依赖注册中心,而RocketMQ的设计理念也正是基于此,生产者在第一次发送消息的时候从NameServer获取到Broker地址后缓存到本地,如果NameServer整个集群不可用,短时间内对于生产者和消费者并不会产生太大影响。

那Broker是怎么保存数据的呢?

RocketMQ主要的存储文件包括commitlog文件、consumequeue文件、indexfile文件。

Broker在收到消息之后,会把消息保存到commitlog的文件当中,而同时在分布式的存储当中,每个broker都会保存一部分topic的数据,同时,每个topic对应的messagequeue下都会生成consumequeue文件用于保存commitlog的物理位置偏移量offset,indexfile中会保存key和offset的对应关系。

ce33a755-9017-eb11-8da9-e4434bdf6706.png

CommitLog文件保存于${Rocket_Home}/store/commitlog目录中,从图中我们可以明显看出来文件名的偏移量,每个文件默认1G,写满后自动生成一个新的文件。

d233a755-9017-eb11-8da9-e4434bdf6706.png

由于同一个topic的消息并不是连续的存储在commitlog中,消费者如果直接从commitlog获取消息效率非常低,所以通过consumequeue保存commitlog中消息的偏移量的物理地址,这样消费者在消费的时候先从consumequeue中根据偏移量定位到具体的commitlog物理文件,然后根据一定的规则(offset和文件大小取模)在commitlog中快速定位。

d633a755-9017-eb11-8da9-e4434bdf6706.png

Master和Slave之间是怎么同步数据的呢?

而消息在master和slave之间的同步是根据raft协议来进行的:

  1. 在broker收到消息后,会被标记为uncommitted状态
  2. 然后会把消息发送给所有的slave
  3. slave在收到消息之后返回ack响应给master
  4. master在收到超过半数的ack之后,把消息标记为committed
  5. 发送committed消息给所有slave,slave也修改状态为committed

你知道RocketMQ为什么速度快吗?

是因为使用了顺序存储、Page Cache和异步刷盘。

  1. 我们在写入commitlog的时候是顺序写入的,这样比随机写入的性能就会提高很多
  2. 写入commitlog的时候并不是直接写入磁盘,而是先写入操作系统的PageCache
  3. 最后由操作系统异步将缓存中的数据刷到磁盘

什么是事务、半事务消息?怎么实现的?

事务消息就是MQ提供的类似XA的分布式事务能力,通过事务消息可以达到分布式事务的最终一致性。

半事务消息就是MQ收到了生产者的消息,但是没有收到二次确认,不能投递的消息。

实现原理如下:

  1. 生产者先发送一条半事务消息到MQ
  2. MQ收到消息后返回ack确认
  3. 生产者开始执行本地事务
  4. 如果事务执行成功发送commit到MQ,失败发送rollback
  5. 如果MQ长时间未收到生产者的二次确认commit或者rollback,MQ对生产者发起消息回查
  6. 生产者查询事务执行最终状态
  7. 根据查询事务状态再次提交二次确认

最终,如果MQ收到二次确认commit,就可以把消息投递给消费者,反之如果是rollback,消息会保存下来并且在3天后被删除。

d833a755-9017-eb11-8da9-e4434bdf6706.png

关注公众号:科技缪缪,获取更多精彩技术文章和电子书

- END -

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/507888.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嘀嗒还是滴答_2021年顺风车车主口碑榜!滴滴、滴答、一喂顺风车成TOP3

出行平台烧钱抢用户抢司机,大家都见怪不怪了,只是近期平台为自身利益而牺牲司机的例子层出不穷,在司机刚进入平台补贴多流水多,没多久司机收入都不够交车租的,司机踩坑,全家受罪,很多司机表示自…

wampserver橙色如何变成绿色_实验室如何自建数据库和网站主页

本文首发于微信公众号:火行(ID:firegotech)实验室如何自建数据库和网站主页作者:沐倾(火行科研Club创始成员)编辑:火花(声明:本文适用于非计算机专业领域人士&#xff09…

mysql ( )连接_MySQL中concat函数(连接字符串)

MySQL中concat函数使用方法:CONCAT(str1,str2,…)返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。注意:如果所有参数均为非二进制字符串,则结果为非二进制字符串。如果自变量中含有任一二进制字符串&…

远程连接电脑_Python黑科技:在家远程遥控公司电脑,python+微信一键连接!

有时候需要远程家里的台式机使用,因为我平时都是用 MAC 多,但是远程唤醒只能针对局域网,比较麻烦,于是我想用微信实现远程唤醒机器。准备工作本程序主要是实现远程管理 Windows10操作系统的开机和关机:在 Windows机器的…

mysql count 优化索引_如何通过使用索引在InnoDB上优化COUNT(*)性能

我有一个小而狭窄的InnoDB表,大约有900万条记录。在桌子上count(*)或count(id)桌子上做的速度非常慢(超过6秒):DROP TABLE IF EXISTS perf2;CREATE TABLE perf2 (id int(11) NOT NULL AUTO_INCREMENT,channel_id int(11) DEFAULT NULL,timestamp bigint(…

ppt生成器_9款魔性#傻瓜生成器#,上班可以划水一天

有些 #傻瓜生成器#,表面上叫傻瓜,实际上一玩就停不下来。不分享出来,未免不近人情。毕竟,大伙上班累了,也需要一些奇怪的东西划划水不是?1 沙雕DIY跳舞生成器这款傻瓜生成器,真不能叫傻瓜&#…

vue组件prop变量和内部变量数据格式不一样时,变量同步prop值,变量改变通知父组件.

vue组件含有v-model的props,当对其进行封装,想对该属性进行双向绑定时,可以采用computed的方式包一层get(){return props.xxx},set(v)>{emit(update:xxx,v)},或者使用vueuse的useModel来深层代理,但是只适合要封装的组件prop的内部的变量数据类型一致,不一致就只能拆开写,通…

mysql移动文件后打不开_Windows端MySQL data目录迁移(貌似会启动不了)

遇到一个现场问题,实施人员把mysql的data放在C盘,用过一阵以后C盘快满了。于是准备做数据迁移,想到如下几种方案(均需要先把mysql服务停掉):1.转储SQL文件但是问题是,想要迁移的库占了1.5T,是T啊&#xff0…

302 found是什么意思_犯罪大师心中的恶魔答案是什么 心中的恶魔答案真相分析...

犯罪大师是今年很热门的一个破案题材的游戏,游戏中有很多匪夷所思的案件,需要玩家解答,游戏中经常更新一些突发案件,最新的突发案件是心中的恶魔是一个很不错的案件,那么到底要怎么才能找到正确的凶手呢?希…

mysql源码安装报错_mysql 的二进制和源码包 安装的报错总结

MySQL报错总结报错原因:/application/mysql-5.6.44/tmp不存在解决方法:mkdir /application/mysql-5.6.44/tmp报错原因: /application/mysql-5.6.44/存放socket 目录没有权限解决方法:chown -R mysql.mysql /application/mysql-5.6…

hao123电脑版主页_建议Lenovo用户卸载监守自盗的联想电脑管家

最近我一直很迷惑,作为一个不用笔记本电脑上xxxxhub/2048等奇妙平台的正经大学生,为什么时而会出现辣鸡页游广告弹窗?好吧,最后我耐心等待,终于在某次弹出垃圾广告的时候定位了这个进程——AdvPopForm.exe在“wprst”的…

mysql 自增 不是主键_程序员经典面试题,MySQL自增主键为什么不连续

在我们日常使用Mysql中,如果不是特殊的业务需要,一般我们都会使用自增主键,自增主键的好处可以在插入的时候尽量地减少页分割,增加Mysql的写入效率。我们有时候就会发现,自增主键并不是连续递增的,为什么有…

怎么彻底重装清空电脑_电脑开不了机怎么重装系统?不用送去维修店啦!

小白系统免费的人工客服点击联系电脑无法启动的时候怎么办呢?很多朋友直接送去电脑城了,但是去一次就如同在百度上查询自己得了什么病是一样的,查一下自己不舒服就癌症了,电脑城查一下就问你卖多少钱,费时费力&#xf…

安装mysql无法登录_【windows 下安装 mysql-server 无法登录问题解决】

----------------------------- 无感的首行 -----------------------------新版 mysql-server 5.7 安装后发现无法使用 mysql -uroot (-p) 来登录,查了下文档发现新版在安装时会初始化一个密码放在启动的错误文件里,错误文件的路径 %mysql-server-dir%da…

日语输入法电脑版_日语轻松入门小百科

如果你一直以来都对日语抱有强烈的兴趣,那么就赶紧跟我一起轻松入门吧~科普之一:日语五十音图什么是假名?什么是五十音图?日语的字母叫做假名,每个假名代表一个音节。假名有两种书写方式,即平假名和片假名&…

jta mysql_JTA 使用 MySQL 分布式事务

假定在MySQL实例1上有表create table person(id int,name varchar(32))MySQL实例2上也有一张同样的表,现在从实例1中的 person 表中删除一条数据,并把这条数据插入到实例2的表中,这两个操作在同一个事务中,因为跨越了数据库实例&a…

mysql load average_紧急求助:load average太高了!!

站点同时在线人数300人左右,top出来的load average超过4,有时达到了8点多!sleeping进程达到了三百多!大部分是来自apache,导致房问速度很慢!!不知问题出在哪里,请高手赐教,谢谢&…

a jni error has occurred_A-08 幂函数、有理函数、代数函数

欢迎光临我的专栏《微积分学习之旅》,一起学习,共同提高。函数是微积分的基础,我们已经学习了直线函数和多项式函数,本篇中我们继续学习幂函数、有理函数和代数函数。幂函数(Power Functions)如果一个函数形…