rabbitmq面试题总结
1、为什么要引入MQ系统,直接读写数据库不行吗?
其实就是问问你消息队列都有哪些使用场景,然后你项目里具体是什么场景,说说你在这个场景里用消息队列是什么?
先说一下消息队列常见的使用场景吧,其实场景有很多,但是比较核心的有3个:解耦、异步、削峰。
解耦:多系统多进程的数据交换,用pub/sub
异步:把大数据量的同步处理改为异步
削峰:一般的A系统使用MySQL,扛到每秒2k个请求就差不多了,如果每秒请求到5k的话,可能就直接把MySQL给打死了,导致系统崩溃,用户也就没法再使用系统了。如果使用MQ,每秒5k个请求写入MQ,A系统每秒钟最多处理2k个请求,因为MySQL每秒钟最多处理2k个。A系统从MQ中慢慢拉取请求,每秒钟就拉取2k个请求,不要超过自己每秒能处理的最
大请求数量就ok,这样下来,哪怕是高峰期的时候,A系统也绝对不会挂掉,这又设计请求排队的问题。
2、消息队列有什么优缺点?
优点:mysql面试题常问
解耦、异步、削峰
缺点:
系统可用性降低
系统引入的外部依赖越多,越容易挂掉。
系统复杂度提高
一致性问题
A系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是BCD
工控硬件漏洞的挖掘方法三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,这数据就不一致了。
3、rabbitmq的高可用性如何保证?
rabbitmq有三种模式:单机模式、普通集模式、镜像集模式,单机模式不存在高可用。
普通集模式也不存在高可用性,意思就是在多台机器上启动多个rabbitmq实例,每个机器启动一个。但是你创建的queue,只会放在一个rabbitmq实例上,但是每个实例都同步queue的元数据(元数据可以认为是queue的一些配置信息,通过元数据,可以到queue所在实例)。你消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从queue所在实例上拉取数据过来。这种方式确实很麻烦,也不怎么好,没做到所谓的分布式,就是个普通集。因为这导致你要么消费者每次随机连接一个实例然后拉取数据,要么固定连接那个queue所在实例消费数据,前者有数据拉取的开销,后者导致单实例性能瓶颈。而且如果那个放queue的实例宕机了,会导致接下来其他实例就无法从那个实例拉取,如果你开启了消息持久化,让rabbitmqexcel最多支持几线程落地存储消息的话,消息不一定会丢,得等这个实例恢复了,然后才可以继续从这个queue拉取数据。
镜像集模式的策略是高可用策略,指定的时候可以要求数据同步到所有节点的,也可以要求同步到指定数量的节点,再次创建queue的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。
4、如何解决消息队列的延时以及过期失效问题?
其实本质针对的场景,都是说,可能你的消费端出了问题,不消费了;或者消费的速度极其慢,造成消息堆积了,MQ存储快要爆了,甚至开始过期失效删除数据了。
针对这个问题可以有事前、事中、事后三种处理。
事前:开发预警程序,监控最大的可堆积消息数,超过就发预警消息(比如短信),不要等出生产事故了再处理。
事中:看看消费端是不是故障停止了,紧急重启。
事后:需要对消费端紧急扩容,增加处理消费者进程,如扩充10倍处理,但其实这也有个问题,即数据库的吞吐是有限制的,如果是消费到数据库也是没办法巨量扩容的,所以还
是要在吞吐能力支持下老老实实的泄洪消费。所以事前预防还是最重要的。否则出发删除过期数据,那就需要再重写生产消息的程序,重新产生消息。
5、rabbitmq单元测试工具有哪些如何保证不丢数据?
需要考虑3个可能丢数据的地方:生产端、队列本身、消费端
(1)生产端:开启事务(不推荐,太耗性能降低吞吐),推荐开启confirm模式,在生产者那里设置开启confirm模式之后,你每次写的消息都会分配一个唯一的id,然后如果写入了rabbitmq中,rabbitmq会给你回传一个ack消息,告诉你说这个消息ok了。如果rabbitsql语句insert into selectmq没能处理这个消息,会回调你的一个nack接口,告诉你这个消息接收失败,你可以重试。而且你可以结合这个机制自己在内存里维护每个消息id的状态,如果超过一定时间还没接收到这个消息的回调,那么你可以重发。
(2)队列本身:就是rabbitmq自己弄丢了数据,这个你必须开启rabbitmq的持久化,就是消息写入之后会持久化到磁盘,哪怕是rabbitmq自己挂了,恢复之后会自动读取之前存储的数据,一般数据不会丢。
设置持久化有两个步骤:
pht工程师是什么意思创建queue的时候将其设置为持久化,这样就可以保证rabbitmq持久化queue的元数据,但是它是不会持久化queue里的数据的。
第二个是发送消息的时候将消息的deliveryMode设置为2.就是将消息设置为持久化的,此时rabbitmq就会将消息持久化到磁盘上去。
(3)消费端:其实和kafka的原理很类似,kafka即手动提交offsize。用rabbitmq提供的ack机制,简单来说,就是你必须关闭rabbitmq的自动ack,通过自己的一个api来调用就行,然后每次你自己代码里确保处理完的时候,再在程序里ack。这样的话,如果你还没处理完,不就没有ack了?那rabbitmq就认为你还没处理完,这个时候rabbitmq会把这个消费分配给别的consumer去处理,消息是不会丢的。
6、如何保证队列的消息不被重复消费?
这个需要灵活作答,考察的是思考力,因为消费的场景有很多,有数据库、有缓存、有第三方接口
(1)比如针对数据库,你拿到这个消息做数据库的insert操作。那就容易了,给这个消息做一个唯一主键(或者UUID),那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。
(2)再比如redis缓存,你拿到这个消息做redis的set的操作,那就容易了,不用解决,因为你无论set几次结果都是一样的,set操作本来就算幂等操作。
(3)再比如第三方接口,需要确定两点,第三方接口程序是有去重能力的,那么脏一点直接丢数据过去,如果没有去重能力,还是需要我们来写程序去重,就是第2点的办法。
7、集节点类型都有什么?
节点的存储类型分为两种:
磁盘节点
内存节点
磁盘节点就是配置信息和元信息存储在磁盘上,内存节点把这些信息存储在内存中,当然
内次节点的性能是大大超越磁盘节点的。
单节点系统必须是磁盘节点,否则每次你重启rtabbitmq之后所有的系统配置信息都会丢失。
rabbitmq要求集中至少有一个磁盘节点,当节点加入和离开集时,必须通知磁盘节点。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论