前言
消息队列是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。目前消息队列已经逐渐成为企业IT系统内部通信的核心手段,它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。当前使用较多的消息队列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ等,而部分数据库如Redis、MySQL以及phxsql也可实现消息队列的功能。
大多时候,我们使用消息队列来做三件事情:解耦、削峰、异步。这是消息队列最突出的优点,其他优点比如可以持久化数据,保证消息之间的顺序等等在业务中对我们的帮助也很大。
万事有利就有弊,消息队列有这些优点,自然也有它的缺点,比如:
1)系统研发成本增加。引入消息队列后,你就必须要对大多数消息队列有个深入的理解,否则如何做技术选型呢?而消息队列本身也比较复杂,在短时间内无法完全理解。所以是否使用消息队列需要根据具体场景判断,而不是为了使用技术而用技术。
2)系统复杂性增加。 一个系统如果直接将业务串行处理,那么只需要在一个系统中把代码写写写就好了。但如果引入消息队列,则要多考虑很多方面的问题,比如一致性问题、如何保证消息不被重复消费,如何保证保证消息可靠传输。因此,需要考虑的东西更多,系统复杂性增大。
3)系统可用性降低。 本来其他系统只要运行好好的,那你的系统就是正常的。现在你要加个消息队列进去,那消息队列挂了,你的系统势必受到影响。因此,系统可用性降低。
所以我们在考虑使用消息队列的时候,一定要对目前的主流框架有所了解,充分应用其优点,避免或弱化其缺点。
当今市面上主流的开源MOM(Message Oriented Middleware,消息中间件)基本上都是Apache旗下的项目,有老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发RocketMQ等。我们主要谈谈这几个MQ的性能、优缺点和相应的业务场景。这些MQ都是支持集群架构模式的。
另外说一下,其实Redis也是有MQ功能的,它完全可以当做一个轻量级的队列服务来使用。与RabbitMQ相比,入队时,当数据比较小时 Redis 的性能要高于 RabbitMQ,而如果数据大小超过了 10K,Redis 性能就大幅度降低,很难满足系统的使用需求;出队时,无论数据大小,Redis 都表现出非常好的性能,而 RabbitMQ 的出队性能则远低于 Redis。在我们印象中,Redis 是一个 key-value 缓存中间件,而不是一个消息队列中间件,基于以上两种原因,我们在考虑消息中间件的时候一般都不考虑 Redis。所以我们在下面的内容就不涉及Redis的相关内容了,感兴趣的小伙伴可以去研究一下。
1 JMS规范
首先我们聊聊JMS(Java Message Service)规范,也就是Java消息服务,它定义了Java中访问消息中间件的接口规范。所以我们应该明白,JMS只是接口,并没有给予实现,实现JMS接口的消息中间件称为“JMS Provider”。上面说到的ActiveMQ、RabbitMQ、Kafka、RocketMQ都基本遵循或参考了JMS规范,都有自己的特点和优势。
1.1 专业术语
JMS(Java Message Service):实现JMS接口的消息中间件;
Provider(MessageProvider):消息的生产者;
Consumer(MessageConsumer):消息的消费者;
PTP(Point to Point):点对点消费模型;
Pub/Sub(Publish/Subscribe):发布/订阅的消息模型;
Queue:队列目标,也就是我们说的消息队列,一般会真正的进行物理存储;
Topic:主题目标;
ConnectionFactory:连接工厂,用于创建连接到消息中间件的连接;
Connection:JMS客户端到JMSProvider之间的通讯链路;
Destination:目的地,指消息发布和接收的地点,包括队列和主题;
Session:会话,表示一个单线程的上下文,用于发送和接收消息
1.2 JMS消息格式
StreamMessage 原始值的数据流
MapMessage 一套名称/值对
TextMessage 一个字符串对象
BytesMessage 一个未解释的数据流
ObjectMessage 一个序列化的对象
2 ActiveMQ
ActiveMQ是一个完全支持JMS1.1和J2EE1.4规范的JMS Provider实现,尽管JMS规范出台已经很久了,但是JMS在早些年的J2EE应用中有着特殊的地位。可以说ActiveMQ是一个“古老”的消息中间件了,在那个时候它在业界应用的最广泛,也是曾经叱咤风云过的。但是从当今的业务需求来看,ActiveMQ想要有更强大的性能和海量数据处理能力,还需要不断升级版本,提升性能和架构设计的重构。
ActiveMQ有丰富的API、多种集群构建模式,这些足够满足我们80%以上的业务需求,事实也确实如此,做为业界老牌的消息中间件,它在中小型企业应用广泛。当然了,面对大规模、高并发应用服务做中间件选项,如淘宝、京东等大型电商网站,ActiveMQ就捉襟见肘了。
2.1 消息投递模式
我们先说JMS规范里最经典的两种消息投递模式:“点对点”和“发布订阅”。
1)点对点:生产者向队列投递一条消息,只有一个消费者能够监听得到这条消息(PTP),如下图:
2)发布订阅:生产者向队列投递一条消息,所有监听该队列的消费者都能够监听到这条消息(P/S),如下图:
2.2 指标
我们从服务性能、存储堆积能力、可扩展性三个方面考虑。
1)ActiveMQ的性能一般,在早期传统行业盛行的时代比较流行,但是面对如今的高并发、大数据的业务场景,就力不从心了。
2)数据存储默认采用kahadb存储(索引文件形式存储),也可以使用高性能的google leveldb(内存数据库存储),或者使用关系型数据库如Oracle、MySQL等存储。
3)ActiveMQ可以与Zookeeper进行构建主备集群模型,并且多套的主备模型直接可以采用Network的方式构建分布式集群。
2.3 ActiveMQ集群
ActiveMQ最经典的两种集群架构模式:Master-Slave、Network。
1)Master-Slave:
从名字就可以看出来就是主从方式,也就是主备方式,双机热备机制。Master-Slave就是消息被复制到slave broker,即使master broker遇到故障失去工作能力,你也可以切换到slave broker继续工作且不丢失消息。Master-Slave数目前ActiveMQ推荐的高可靠性和容错的解决方案。
Master-Slave集群的关键点:
a、上图绿色节点是主节点,灰色是备份节点,这两个节点都是运行状态。
b、zookeeper的作用就是当绿色主节点宕机时,进行及时切换到备份节点上去,使其进行主从角色互换,用于实现高可用性的方案。
c、Master-Slave集群模型的缺点也很明显,就是不能做到分布式的topic、queue,当消息量巨大时,我们的MQ集群压力过大,没办法满足分布式的需求。
2)Network
可以理解为网络通信方式。这种方式真正解决了分布式消息存储和故障转移、broker切换的问题。它支持分布式的topic、queue。一个broker会相同对待所有的订阅:不管他们是来自本地客户连接,还是远程broker,它都会递送有关的信息拷贝到每个订阅。远程broker得到这个信息拷贝后,会依次把它递送到其内部的本地连接上。
Network集群的关键点:
a、这种方案需要两套及以上的Master-Slave集群模型才可以搞定,部署很麻烦。
b、Network解决了分布式消息队列的问题,但是资源浪费严重。所以Master-Slave模型是传统型互联网公司的首选。
ActiveMQ毕竟是Apache的顶级项目之一,它开箱即用,类似于 RabbitMQ,少量代码就可以高效地实现高级应用场景。目前正在进行新版本重构与落地,我们期待它能够完成这次新生吧。