1. MQ的优缺点
优点:
- 解耦:通过MQ解除上游系统和下游系统的调用耦合,下游系统只需要做消息的订阅和取消订阅,上游系统无需任何改动。(一生产,多消费的典型场景)
- 异步:通过MQ将一些不需要同步获取执行的结果,并且非常耗时的调用操作通过MQ异步化。
- 削峰:通过MQ将一些高峰期的高并发流量积压在MQ中,下游可以按自己的消费能力消费,不会出现过载消费的情况。
缺点:
- 可用性降低:如果MQ出现了问题,依赖MQ环节的服务都会出现瘫痪
- 复杂性提高:给系统引入额外的组件,调用链变长,变复杂。同时需要考虑的事情会变多(消息幂等,丢失,积压等等)
- 数据一致性:下游服务执行部分失败,导致数据不一致
2. MQ的选型
Kafka:
- 吞吐量:10w级别,吞吐量是Kafka最大的优点。
- 时效性:ms以内
- Topic数量对吞吐量的影响:topic达到几百上千,吞吐量有较小幅度下降
- 应用场景:主要用于大数据做日志采集,实时数据计算等场景。
- 高可用性:分布式系统架构,
- 优劣势:功能简单,但是吞吐量大,并且天然适合大数据采集和计算
RocketMQ:
- 吞吐量:10w级别,
- 时效性:ms
- Topic数量对吞吐量的影响:topic达到几百上千,吞吐量有较小幅度下降
- 应用场景:吞吐量大的业务场景
- 高可用性:分布式系统架构,易扩展
- 优劣势:接口移动,阿里开源,有大规模的应用,社区活跃度高,可靠性ok
RabbitMQ:
- 吞吐量:万级,比kafka和RocketMQ低了一个量级
- 时效性:微秒级别,延迟最低
- 应用场景:
- 高可用性:主从架构实现高可用
- 优劣势:erlang开发,时效性极好,开源版本提供的管理页面友好,强大。实现的机制较重,吞吐量较低
ActiveMQ:
- 吞吐量:万级,比kafka和RocketMQ低了一个量级
- 时效性:ms
- 应用场景:主要还是异步和削峰
- 高可用性:主从架构实现高可用
- 优劣势:较低概率可能会丢消息,同时开源社区不够活跃,目前更新较慢,假设遇到问题会很难解决。
3. 如何保证MQ的高可用
RabbitMQ:
单机模式,普通集群模式(中心化的),镜像集群模式(queue对等,实时性差,网络负载重,不可线性拓展)
Kafka:
分布式架构,有多个broker(master,slave)。比如一个topic,数据不是分布在一台机器上,利于水平拓展。同时提供多副本机制保证高可用,针对一个topic下的副本,只能写入到leader,然后同步到follower。是中心化的。broker之间的协调是通过zk完成的,选出一个controller,然后决定每个partition的主从。
RocketMQ:
分布式架构,有多个broker。和kafka不同,针对一个topic,在每个broker上会有多个queue,消息的消费是针对queue的,消息的冗余是通过主从复制,有同步复制和异步。broker的协调是通过nameServer来完成的,不同于kafka,RocketMQ没有选举机制,因为broker对等,一个broker挂了则由其他的broker处理请求,相当于剔除了这个broker。
4. 如何保证消息的幂等性
产生重复消费的可能性:
- 消费者重启前没提交消费到的数据index,可能会导致重复消费
- 网络抖动导致消费确认消息没到达MQ,可能会导致重复消费
保证幂等的手段:
- 如果是mysql,可以通过主键或者唯一索引等保证。 如果是redis,可以通过key保证
- 给每个消息增加一个全局唯一的id,然后通过redis做幂等性判断,这里可能会涉及到redis的事务原子性
5. 如何保证消息的可靠性
RocketMQ
1>从producer的角度
- 默认是同步堵塞的方式,可以通过返回值确认消息投递到了broker
- 如果是事务的方式,如果投递失败,会把消息存到commitLog中去
- 支持日志索引,投递不成功的消息可以通过提供的API查询到
2>从broker的角度
- 消息是会同步到commitLog中的,就算broker宕机也是能加载出来的
- broker支持同步刷盘和异步刷盘
- broker支持主从部署
3>从consumer的角度
- consumer在消息消费的时候会记录成功消费消息或者已经发回到broker的offset
- consumer维护的offset是会持久化的,就算consumer和broker都挂了,重启的时候,consumer会读取offset在发送给broker
- consumer消费失败的时候会重试,然后更新offset
6. 如何保证消息的消费顺序
顺序消息包含两种类型:
分区顺序:一个Partition内所有的消息按照先进先出的顺序进行发布和消费
全局顺序:一个Topic内所有的消息按照先进先出的顺序进行发布和消费
RocketMQ:我们知道针对一个topic是会有多个queue的,所以首先需要保证顺序消费的消息是发到同一个queue中的,通过提供的分区函数保证消息能够丢到一个queue中就好。 但是这样只能保证分区顺序,全局顺序的话那就是只有一个分区。
7. 消息队列里积压了很多消息怎么办
可以通过临时扩容,增加消费者数量,排查原先消费者出现的问题