一.为什么要用消息队列
·剖析
其实面试官是在问:消息队列都有哪些使用场景,项目中是怎么用的
消息队列的使用场景\项目中如何使用的
1.解耦
项目中有一张表,里面某一个字段是和其他项目组打通的,从其他项目同步过来的字段,因为并不是需要同步更新,所以使用的mq进行消息的同步,我们系统作为消费者消费消息,生产者不用对每一个系统都进行硬编码了。
2.异步
用户一个请求,后台自己系统写库需要100ms,但是还要向其他ABC三个系统数据库写入,分别需要300Ms,如果是同步,则用户等待时长为1m,异步则可以通过消息队列向其他三个ABC系统发送消息,从而给用户更快的交互。
3.削峰
一个系统0-12点的时候,请求量是每秒50左右,到了12-2点,突然暴增到5000,而mysql的处理瓶颈只有每秒2000,直接请求会导致数据库宕机,这时候就需要消息队列,MySQL直接从消息队列拉取数据,然后慢慢处理数据。
二.消息队列有什么优缺点
优点:上面说的 解耦、异步、削峰
缺点:
1.系统可用性降低:mq一旦出问题,系统会崩溃
2.增加系统复杂度:mq使用过程中要保证消息没有重复消费、确保消息没有丢失,保证消息传递的顺序性
3.消息一致性问题:ABC三个库,两个库成功了,一个库挂了,数据就不一致了
三.kafka、rocketmq、rabbitmq、activemq都有什么区别,以及适合哪些场景?
特性 | ActiveMQ | RabbitMQ | RocketMQ | kafka |
单机吞吐量 | 万级 | 万级 | 十万级,支持高吞吐 | 十万级,一般配合大数据类的系统进行实时日志采集、计算 |
TOP数据量对吞吐量的影响 | topic可以有几百上千,也算rocketmq的优势 | topic过多会导致性能下降,如果需要支持大规模topic,需要扩大机器规模 | ||
时效性 | ms | 微秒级,rabbitmq的一大特点 | ms | ms |
可用性 | 基于主从架构实现高可用 | 同activemq | 非常高,分布式架构 | 非常高,一个数据多个副本,一个节点宕机不会导致不可用 |
消息可靠性 | 有较低概率丢失数据 | 基本不丢 | 经过参数优化配置,可以做到0丢失 | 同RocketMQ |
功能支持 | MQ领域的功能及其完备 | 基于erlang开发,并发性能强,延时很低 | MQ功能完善,还是分布式,扩展极好 | 功能简单,主要支持简单MQ,适用于大数据场景 |
总结:
1.最早的mq,activemq现在逐渐用的人少了,也没经历过大并发量验证,不推荐
2.继activemq之后,开源的不错的mq,只是erlang语言组织了很多人研究的步伐,对公司而言几乎是不可控的状态,活跃度也高
3.rocketmq是阿里出品,但是已经捐给了apache,有黄的危险,如果是小公司,技术挑战一般,可以用rabbitMQ,大公司基础架构研发能力强,可以用rocketMQ
4.如果是大数据场景,kafka几乎是业内标杆
四.如何保证消息队列高可用
rabbitMQ
镜像集群模式
镜像集群模式下,queue和消息都会存在与多个实例之上,每个rabbit节点都有这个queue的一个完整镜像,每次写消息,都会自动同步到多个queue之上。
kafKa
kafka的基本架构:一个broker代表一个节点,创建一个topic可以分为多个partion,每个broker上面存放一个partion.
HA机制:kafka0.8版本之后,提供了HA机制,就是replica副本机制,每个partion的信息都会同步到其他机器上,形成自己的多个replica副本。所有的replica会选出一个leader,生产者和消费者都和这个leader打交道。然后其他replica都是follower.写数据的时候要保证所有的broker节点都收到了replica的副本后再发回ack成功的消息。
五.如何保证消息没有丢失
1.rabbitMQ保证消息不丢失的方案:
a.开启事务rabbitMQ:channel.txselect{代码块}channel.txcommit,如果消息没有被mq正常接收到,会收到异常报错,需要回滚事务,然后重新发送事务。
事务开启之后,会变成阻塞状态
缺点:吞吐量下降,太消耗性能。
b.confirm模式
生产者会发送带有唯一id的数据到mq,mq成功接收后返回ack。confirm模式是异步的,当过了一段时间生产者没有收到mq的确认消息后,会再次发送一次消息。
rabbitMQ持久化消息:
1.设置queue的持久化
2.设置消息的deliveryMode=2持久化消息
2.kafka
1.消费端弄丢了数据
关闭自动提交offset,等持久化之后再手动发送offset
2.kafka弄丢了数据
a.服务端设置 replaica = 2,每个partion必须有2个副本replica
b.acks = all,要等所有的replica都成功接收后,才认为是写成功了
3.生产者弄丢了数据
mq设置ack=all
六.如何保证消息没有重复消费
如何保证幂等性
1.每条消息要有一个唯一标识,消费者拿到消息后从redis中去查询,如果存在就不能再消费了,不存在再继续消费