1、为什么要使用消息队列(MQ)

(ActiveMQ、RibbitMQ、RocketMQ、Kafka)
首先,它是一把双刃剑,引入它之前要考虑它的缺点是否对于本系统是否是致命的。弄清它的优点和缺点,扬长避短,进行技术选型。

主要场景:解耦、 异步、削峰填谷。

优点:它具有低耦合、可靠投递、广播、流量控制、最终一致性的一系列功能,成为异步RPC的主要手段之一。
缺点:(1)、MQ如果故障会出现一系列问题,系统可用性降低。
            (2)、会更加复杂,要考虑的问题会变多。
            (3)、一致性问题

2、消息中间件的组成

broker:消息服务器,作为server提供消息服务器。
producer:消息生产者,业务的发起方,负责生产消息给broker。
consumer:消息消费者,业务的处理方式,负责从broker获取消息进行处理。
topic:主题,不同的生产者向topic发送消息,由mq分发给不同的订阅者,负责消息的广播。
queue:队列,PHP模式下,特定的生产者向特定queue发送消息,订阅者订阅特定的queue完成指定消息接收。
message:消息体,封装业务数据,实现消息的传输。

3、四大消息中间件MQ介绍

(1)RocketMQ:吞吐量十万级,阿里系下开源的一款分布式、队列模型的消息中间件,参照kafka设计思想使用Java实现的一套mq,主要用于订单交易系统。
        特点:
                能保证严格的消息顺序。
                提供针对消息的过滤功能。
                提供丰富的消息拉取模式。
                高效的订阅者水平扩展能力。
                实时的消息订阅机制。
                亿级消息堆积能力。
        官方提供了一些不同于kafka的对比差异:  https://rocketmq.apache.org/docs/motivation/

(2)RibbitMQ:吞吐量万级,使用Erlang编写的一个开源的消息队列,支持很多协议,适合企业级的开发。同时实现了Broker架构,核心思想是生产者不会将消息直接发送给队列,消息在发送给客户端时先在中心队列排队。对路由、负载均衡、数据持久化都有很好的支持。多用于进行企业级的ESB整合。
(评价:Erlang这门语言天生并发强,延时低。但是我并不觉得这是一个很大的优点,因为速度快点和速度慢点只要在毫秒之间,大家都是可以接受的。
    RibbitMQ有一个很适合国内大多数公司优点,就是它有自己的一个后台管理界面,很方便,支持很多日常开发操作需求 同时它的开源社区也很活跃。)
    
(3)ActiveMQ:吞吐量万级,Apache下的一个子项目。使用Java完全支持JMS1.1和J2EE1.4规范的JMS Probider实现,少量代码就可以    高效的实现高级应用场景。
        缺点:偶尔会丢消息,社区不活跃,官方维护周期变长。
                             
(4)Kafka:Apache下的一个子项目。使用scala实现的一个高性能分布式Publish/Subscribe消息队列系统。
        特点:
           快速持久化:通过磁盘顺序读写与零拷贝机制,可以在O(1)的系统开销下进行消息持久化。
           高吞吐:在一台普通的服务器上即可以达到10W/s的吞吐速率。
           高堆积:支持topic下消费者较长时间离线,消息堆积量大。
           完全的分布式系统:Broker、Producer、Consumer都远胜自动支持分布式,依赖zookeeper自动实现复杂均衡。
           支持Hadoop数据并行加载:对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。

4、总结

ActiveMQ:
    近几年来说不推荐使用,社区活跃度低。
RibbitMQ:
    中小型公司更适合,社区活跃度高。
    优点:
            1.轻量级,部署放便快捷
            2.支持灵活的路由配置,可以根据配置的路由规则,让生产者生产出来的消息发送到不同的队列中。
            3.兼容性好,RabbitMQ的客户端支持大多数的编程语言
    缺点:
            1.如果有大量的消息堆积在队列中,性能会急剧下降
            2.RabbitMQ是用Erlang开发的,在功能拓展和二次开发上不友好
            3.对比RocketMQ和kafka,RabbitMQ性能是最差的
RocketMQ:
    中大型公司更适合,社区活虽然跃度高,但是如果有一天阿里不再维护了,RocketMQ是java源码设计的,也可以自己公司的技术人员去进行维护和升级,公司需要具备一定的实力。
    优点
        1.功能全,RocketMQ基本具备了消息队列应有的所有功能
        2.RocketMQ使用java语言开发,在进行debug源码,扩展功能和二次开发方面都很友好
        3.性能高,毫秒级响应,经受过多次双十一的考验
    缺点
        1.兼容性不好,目前只支持java和c++,但C++尚不成熟
        2.社区活跃度一般
Kafka:
    大数据领域更适合,天生就是搞实时性计算,日志采集,社区活跃度高。
    优点
        1.可靠性和稳定性很高  
        2.性能卓越,单机吞吐量高  
        3.有很好的管理界面Kafka-Manager  
        4.日志领域非常成熟  
    缺点 
        1.消费失败后不能重试  
        2.由于是异步和批处理,延迟高  
        3.使用短轮询方式,实时性取决于轮询间隔时间

5、消息队列的一些日常问题

(1)怎么保证消息队列的高可用?
       以RibbitMQ来举例,它的镜像集群模式就可以解答这个问题。
       RibbitMQ使用的话分为单机模式(测试)和普通集群模式(非高可用)和镜像集群模式(高可用)
       三种模式的区别:https://cloud.tencent.com/developer/article/2002166
       Kafka的话它是有那么一种保证机制,他会把topic分成不同的portition,给每个portition搞多个副本,分为leader和follower这两个角色,然后只有leader是对外提供读写的,follower会从leader同步数据,如果leader挂了之后会从follower之间重新选举一个leader。
(2)怎么保证重复消息的幂等性?
        第一个办法就是可以用数据库来进行限制,每次插入数据都判断它的主键id是否存在,如果存在就不插入。
       第二个办法就是对于每条消息,MQ内部生成一个全剧唯一、与业务无关的消息ID。每次MQ服务器收到消息都会根据这个消息ID来确定是否插入到数据。

(3)RibbitMQ可能存在的数据丢失问题

生产者-confirm机制(异步):你先把生产者设置成confirm模式,然后发送消息,发送完消息你就不用管了。RibbitMQ如果收到这条消息的话,就会回调你生产者本地的一个接口,通知你说这条消息已经收到。RibbitMQ如果在接受消息的时候报错了,就会回调你的借口,告诉你这个消息接受失败了,你可以再次发送。
     RibbitMQ-持久化到磁盘:首先把queue设置成持久化,第二就是发送消息的时候将消息的deliveryMode设置成2。
    消费者:你需要把autoAck机制关闭,然后每次你自己确定已经处理完了一条消息之后,再发送给ack消息,然后RibbitMQ就会将这一条消息重新分配给其他消费者去处理。
(4)RibbitMQ和kafka怎么保证从消息队列里拿到的数据按顺序执行?
      使用内存queue的方式,把消息按顺序放入queue中,当queue把消息分发给消费者时,也是有顺序的。

6、如果让你来开发一个消息队列中间件,你会怎么设计架构?

        首先这个mq得支持扩容,采用分布式的模式,参照kafka的理念,每一个broker是服务器上的一个节点,一个topic可以把他拆成多个partition,那么每个partition可以去放topic的一部分数据。
                如果说资源不够了,没有关系,你可以给topic增加更多的partition,进行一个数据的迁移什么的。
        第二就是你得考虑这个mq的数据要不要落磁盘?那肯定要了,你可以按顺序去往磁盘里面写数据,落磁盘也能保证别的进程挂了数据不会丢。