MQ问答

1. MQ的优缺点?

优点:解耦,异步,削峰

缺点:可用性,复杂性,一致性

2. ActiveMQ,Kafka,RabbitMQ,RocketMQ优缺点?

特性 ActiveMQ RabbitMQ RocketMQ Kafka
单机吞吐量 万级,吞吐量比RocketMQ和Kafka要低了一个数量级 万级,吞吐量比RocketMQ和Kafka要低了一个数量级 10万级,RocketMQ也是可以支撑高吞吐的一种MQ 10万级别,这是kafka最大的优点,就是吞吐量高。一般配合大数据类的系统来进行实时数据计算、日志采集等场景
topic数量对吞吐量的影响 topic可以达到几百,几千个的级别,吞吐量会有较小幅度的下降这是RocketMQ的一大优势,在同等机器下,可以支撑大量的topic topic从几十个到几百个的时候,吞吐量会大幅度下降所以在同等机器下,kafka尽量保证topic数量不要过多。如果要支撑大规模topic,需要增加更多的机器资源
时效性 ms级 微秒级,这是rabbitmq的一大特点,延迟是最低的 ms级 延迟在ms级以内
可用性 高,基于主从架构实现高可用性 高,基于主从架构实现高可用性 非常高,分布式架构 非常高,kafka是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
消息可靠性 有较低的概率丢失数据 经过参数优化配置,可以做到0丢失 经过参数优化配置,消息可以做到0丢失
功能支持 MQ领域的功能极其完备 基于erlang开发,所以并发能力很强,性能极其好,延时很低 MQ功能较为完善,还是分布式的,扩展性好 功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准
优劣势总结 非常成熟,功能强大,在业内大量的公司以及项目中都有应用偶尔会有较低概率丢失消息而且现在社区以及国内应用都越来越少,官方社区现在对ActiveMQ 5.x维护越来越少几个月才发布一个版本而且确实主要是基于解耦和异步来用的,较少在大规模吞吐的场景中使用 erlang语言开发,性能极其好,延时很低;吞吐量到万级,MQ功能比较完备而且开源提供的管理界面非常棒,用起来很好用社区相对比较活跃,几乎每个月都发布几个版本分在国内一些互联网公司近几年用rabbitmq也比较多一些但是问题也是显而易见的,RabbitMQ确实吞吐量会低一些,这是因为他做的实现机制比较重。而且erlang开发,国内有几个公司有实力做erlang源码级别的研究和定制?如果说你没这个实力的话,确实偶尔会有一些问题,你很难去看懂源码,你公司对这个东西的掌控很弱,基本职能依赖于开源社区的快速维护和修复bug。而且rabbitmq集群动态扩展会很麻烦,不过这个我觉得还好。其实主要是erlang语言本身带来的问题。很难读源码,很难定制和掌控。 接口简单易用,而且毕竟在阿里大规模应用过,有阿里品牌保障日处理消息上百亿之多,可以做到大规模吞吐,性能也非常好,分布式扩展也很方便,社区维护还可以,可靠性和可用性都是ok的,还可以支撑大规模的topic数量,支持复杂MQ业务场景而且一个很大的优势在于,阿里出品都是java系的,我们可以自己阅读源码,定制自己公司的MQ,可以掌控社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准JMS规范走的有些系统要迁移需要修改大量代码还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用RocketMQ挺好的 kafka的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展同时kafka最好是支撑较少的topic数量即可,保证其超高吞吐量而且kafka唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性天然适合大数据实时计算以及日志收集

3. 如何保证消息队列的高可用?

RabbitMQ高可用 - 集群

RabbitMQ 有三种模式

  • 单机模式
  • 普通集群模式
    • 缺点1:在RabbitMQ集群内部产生大量的数据传输
    • 缺点2:可用性无法保障
  • 镜像集群模式
    • 缺点1:性能开销大,所有消息都需要同步
    • 缺点2:无法扩展

kafka高可用 - 分布

多个broker组成,每个broker是一个节点,你创建一个topic,这个topic就划分多个partition,每个partition可存在于不同的broker上,每个partition就放一部分数据。

kafka 0.8以后提供HA机制。就是replica副本机制。每个partition会同步到其他机器上,生成多个replica副本,replica会选出一个leader。生产者只和leader打交道,其它的replica就是follower。写数据的时候leader负责同步到follower上。

写数据的时候,生产者写leader,leader写本地磁盘,follower主从从leader来pull。同步好数据,发送ack给leader,leader收到所有follower的ack后。返回成功给生产者。

PS:集群和分布的区别?

  • 分布式:一个业务分拆多个子业务,部署在不同的服务器上
  • 集群:同一个业务,部署在多个服务器上
1
2
小饭店原来只有一个厨师,切菜洗菜备料炒菜全干。后来客人多了,厨房一个厨师忙不过来,又请了个厨师,两个厨师都能炒一样的菜,这两个厨师的关系是集群。
为了让厨师专心炒菜,把菜做到极致,又请了个配菜师负责切菜,备菜,备料,厨师和配菜师的关系是分布式,一个配菜师也忙不过来了,又请了个配菜师,两个配菜师关系是集群。

4. 如何保证消息不被重复消费,保证消费的时候是幂等性?

kafka重复消费

kafka有一个offset的序号。每次consumer消费后,隔一段时间会把提交给,zookeeper告诉kafka哪些数据给消费了。当系统重启。consumer并未提交。这时kafka继续上次消费的offset给你。这就是出现了重复消费。

幂等性

  1. 写入数据库,查主键,有了不就再插入。
  2. 写入redis,每次都是set,天然幂等性。
  3. 做个全局id来判断。

5. 如何保证消息可靠性传输?丢失了怎么办?

rabbitMQ可靠性

  1. 生产者丢数据
    1. 开启rabitmq的事务功能(channel.txSelect),如果消息没有被rabbitMQ接收到,生产者收到异常,回滚(channel.txRcllback);再次提交。收到了成功,可以提交事务(channel.txCommit)。问题是:事务机制太耗性能,吞吐量会下来。
    2. channel开启confirm模式,每次写消息会分配一个唯一ID。j(异步)然后就不用管。如果写入rabitmq成功,回传一个ack消息。如果失败,回调nack接口。
  2. rabbitMQ丢数据
    1. 开启rabitmq持久化,写入磁盘。先创建queue的时候设置持久化。这样可以保证rabitmq持久化queue的元数据,但是不会持久化queue里的数据。
    2. 发送消息的时候,将消息的deliveryMode设置为2,就是将消息持久化。两个必须同时设置,才能保证rabitmq的持久化。
  3. 消费者丢数据
    1. 你打开了消费者autoAck机制。自动答应。也就是不管处理成功或失败都ack。

6. 如何保证消息的顺序性?

  1. 什么场景下会错乱?
    • RabbitMQ:一个queue,多个consumer。
    • Kafka:一个topic,一个partition,一个consumer,consumer内部多线程。
  2. 如何保证顺序性
    • RabbitMQ:一个queue对应一个consumer。
    • Kafka:一个topic,一个partition,一个consumer,运用内存队列。

7. 如何解决消息队列的延迟及过期失效问题?消息队列满了怎么处理?有几百万消息持续积压几小时,怎么解决?

  1. 有几百万消息持续积压几小时,怎么解决?
    1. 恢复consumer,停掉现有consumer
    2. 新建topic,partition原来10倍,临时简历10倍queue的量
    3. 写一个临时分发数据的consumer程序,在这个程序部署积压的消费数据,消费之后不做耗时处理,直接轮循写入临时建立好的10倍的queue
    4. 临时征用10倍的机器来部署consumer来消费queue
    5. 这种做法相当于临时扩大了10倍消费数据的能力
    6. 消费积压完的数据后,再恢复部署
  2. 如何解决消息队列的延迟及过期失效问题?
    • 设置过期时间也就是TTL,积压超过一定时间就会清理。
  3. 消息队列满了怎么处理?
    1. 快速写入到另外一个queue
    2. 快速丢弃数据。等高峰过后,在手动补回。

8. 写一个消息队列,如何进行架构?

  1. 高可用(伸缩性,方便扩容,参考kafka分布式)
  2. 高可靠(数据不丢失,写磁盘,保证写入顺序)