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的数据要不要落磁盘?那肯定要了,你可以按顺序去往磁盘里面写数据,落磁盘也能保证别的进程挂了数据不会丢。