文章目录
一. MQ的作用
当项目中有以下几种情况,就可以考虑上MQ了
- 服务解耦:分布式中的模块之间解耦
- 削峰填谷:当有大量流量的时候,可能来不及处理,需要先把数据存到一个地方,然后在慢慢处理,例如天猫双11的时候
- 异步化缓冲:异步化处理,不用要求强一致性,最终一致性就好。
二. 使用MQ需要考虑的点
结合自己实际的用户场景,考虑使用哪种MQ,因为不同的MQ可能侧重点不同
- 生产端可靠性投递:如果是金融类的场景的话,生产者发送的消息必须要同步到消费者,不能有任何的丢失。
- 消费端幂等性:消费端不能重复消费
- 高可用:可用性是不是良好,用的是什么模型
- 低延迟:如果对响应有要求,那就得考虑延迟性
- 可靠性:是否可靠
- 扩展性:是否可以轻松的扩展
- 堆积能力:消息的堆积能力,如果有大量请求的时候就要考虑好
三. JMS
JMS(Java Message Service)规范,也就是Java消息服务,它定义了Java中访问消息中间件的接口的规范。在这里注意哦,JMS只是接口,并没有给予实现,实现JMS接口的消息中间件称为 “JMS Provider”,目前知名的开源 MOM (Message Oriented Middleware,也就是消息中间件)系统包括Apache的ActiveMQ、RocketMQ、Kafka,以及RabbitMQ,可以说他们都 “基本遵循” 或 “参考” JMS规范,都有自己的特点和优势。
3.1 JMS消息模型
点对点(PTP)
生产者向队列投递一条消息,只有一个消费者能够监听得到这条消息(PTP),下图所示:
发布订阅(P/S)
发布订阅:生产者向队列投递一条消息,所有监听该队列的消费者都能够监听得到这条消息(P/S),下图所示:
3.2 基础知识储备
- 专业术语
- JMS(Java Message Service):实现JMS 接口的消息中间件;
- Provider(MessageProvider):消息的生产者;
- Consumer(MessageConsumer):消息的消费者;
- PTP(Point to Point):即点对点的消息模型,这也是非常经典的模型;
- Pub / Sub(Publish/Subscribe):,即发布/订阅的消息模型;
- Queue:队列目标,也就是我们常说的消息队列,一般都是会真正的进行物理存储;
- Topic:主题目标;
- ConnectionFactory:连接工厂,JMS 用它创建连接;
- Connection:JMS 客户端到JMS Provider 的连接;
- Destination:消息的目的地;
- Session:会话,一个发送或接收消息的线程(这里Session可以类比Mybatis的Session);
- JMS 消息格式定义:
- StreamMessage 原始值的数据流
- MapMessage 一套名称/值对
- TextMessage 一个字符串对象
- BytesMessage 一个未解释字节的数据流
- ObjectMessage 一个序列化的Java对象
四. ActiveMQ
ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在早些年的 “J2EE应用” 时期扮演着特殊的地位,可以说那个年代ActiveMQ在业界应用最广泛,当然如果现在想要有更强大的性能和海量数据处理能力,ActiveMQ还需要不断的升级版本,不断的提升性能和架构设计的重构。
就算现在我们 80% 以上的业务我们使用ActiveMQ已经足够满足需求,其丰富的API、多种集群构建模式使得他成为业界老牌消息中间件,在中小型企业中应用广泛!
当然如果你想针对大规模、高并发应用服务做消息中间件技术选型,譬如淘宝、京东这种大型的电商网站,尤其是双11这种特殊时间,ActiveMQ可能就显得力不从心了
4.1 ActiveMQ各项指标
衡量一个MOM,我们主要从三方面考虑即可,即服务性能、存储堆积能力、可扩展性。
- 服务性能
- ActiveMQ的性能一般,在早期传统行业为王的时代还是比较流行的,但现如今面对高并发、大数据的业务场景,往往力不从心!
- 数据存储
- 默认采用kahadb存储(索引文件形式存储),也可以使用高性能的google leveldb(内存数据库存储), 或者可以使用MySql、Oracle进程消息存储(关系型数据库存储)。
- 集群架构
- ActiveMQ 可以与zookeeper进行构建 主备集群模型,并且多套的主备模型直接可以采用Network的方式构建分布式集群。
4.2 ActiveMQ集群架构模式
ActiveMQ最经典的两种集群架构模式,Master-Slave 、Network 集群模式!
- Master-Slave:就是主从方式,当然这里要理解为主备的方式,也就是双机热备机制;Master Slave 背后的想法是,消息被复制到slave broker,因此即使master broker遇到了像硬件故障之类的错误,你也可以立即切换到slave broker而不丢失任何消息。 Master Slave是目前ActiveMQ推荐的高可靠性和容错的解决方案。
- Network :这里可以理解为网络通信方式,也可以说叫Network of brokers。这种方式真正解决了分布式消息存储和故障转移、broker切换的问题。可以理解消息会进行均衡;从ActiveMQ1.1版本起,ActiveMQ支持networks of brokers。它支持分布式的queues和topics。一个broker会相同对待所有的订阅(subscription):不管他们是来自本地的客户连接,还是来自远程broker,它都会递送有关的消息拷贝到每个订阅。远程broker得到这个消息拷贝后,会依次把它递送到其内部的本地连接上。
4.3 两种模式的优缺点
- Master-Slave:他是主备的,不能做到类似于es的分片存储,所以不能做到分布式的topic、queue,当消息量巨大时,我们的MQ集群压力过大,没办法满足分布式的需求。
- Network:1.这种方案需要两套或多套(Master-Slave)的集群模型才可以搞定,部署非常麻烦。2.Network虽然解决了分布式消息队列这个难题,但是还有很多潜在的问题,最典型的就是资源浪费问题,并且也可能达不到所预期的效果。
- 建议:如果是中小型项目,消息量不会特别大的时候,可以用Master-Slave模型,如果要是大型项目的话,换其他的的MQ吧
- 注:以上都是在5.x以下说的,新版的话可能会有变化
五. RabbitMQ集群架构
5.1 主备模式
一个主/备方案(如果主节点挂了,从节点提供服务,和activeMQ利用Zookeeper做主备一样,不同的是RabbitMQ是用HaProxy做的)
5.2 远程模式
远距离通信和复制,可以实现双活的一种模式,简称Shovel模式
所谓Shovel就是我们可以把消息进行不同数据中心的复制工作,可以跨域的让两个MQ集群互联
但是这个模式有几个缺点:
1.配置麻烦
2.稳定性不好
5.3 镜像模式
集群模式非常经典的就是Mirror镜像模式,保证100%数据不丢失
在实际工作中用的最多,并且实现集群非常的简单,一般互联网大厂都会构建这种镜像集群模式。
但是这种模式有一个缺点,不支持横向扩展
5.4 多活模式
这种模式也是实现异地数据复制的主流模式,因为Shovel模式配置比较复杂,所以一般来说实现异地集群都是使用这种双活或者多活模型来实现的
这种模型需要依赖RabbitMQ的federation插件,可以实现持续的可靠的AMQP数据通信,多活模式的配置和应用非常简单
采用双中心模式(多中心),那么在两套或多套数据中心各部署一套RabbitMQ集群,各中心的RabbitMQ服务除了需要为业务提供正常的消息服务外,中心之间还需要实现部分队列消息共享
5.4.1 Federation插件
Federation插件是一个不需要构建Cluster,而在Brokers之间传递消息的高性能插件,Federation插件可以在Brokers或者Clusters之间消息传输,链接的双方可以是不同的用户权限和版本,双方也可以使用版本不同的RabbitMQ和erlang,Federation插件使用AMQP协议通信,可以接受不连续的传输。
六. RocketMQ
RocketMQ是一款分布式、队列模型的消息中间件,由阿里巴巴自主研发的一款适用于高并发、高可靠性、海量数据场景的消息中间件。早期开源2.x版本名为MetaQ;15年迭代3.x版本,更名为RocketMQ,16年开始贡献到Apache,经过1年多的孵化,最终成为Apache顶级的开源项目,更新非常频繁,社区活跃度也非常高;目前最新版本为4.5.1-release版本(2019-7-20日前)。RocketMQ参考借鉴了优秀的开源消息中间件Apache Kafka(这也是我们后面课程中重点要讲解的内容哦),其消息的路由、存储、集群划分都借鉴了Kafka优秀的设计思路,并结合自身的 “双十一” 场景进行了合理的扩展和API丰富。
6.1 优秀的能力与支持
- 支持集群模型、负载均衡、水平扩展能力
- 亿级别的消息堆积能力
- 采用零拷贝的原理、顺序写盘、随机读(索引文件)
- 丰富的API使用
- 代码优秀,底层通信框架采用Netty NIO框架
- NameServer 代替 Zookeeper
- 强调集群无单点,可扩展,任意一点高可用,水平可扩展
- 消息失败重试机制、消息可查询
- 开源社区活跃度、是否足够成熟(经过双十一考验)
6.2 专业术语
- Producer:消息生产者,负责产生消息,一般由业务系统负责产生消息。
- Consumer:消息消费者,负责消费消息,一般是后台系统负责异步消费。
- Push Consumer:Consumer的一种,需要向Consumer对象注册监听。
- Pull Consumer:Consumer的一种,需要主动请求Broker拉取消息。
- Producer Group:生产者集合,一般用于发送一类消息。
- Consumer Group:消费者集合,一般用于接受一类消息进行消费。
- Broker : MQ消息服务(中转角色,用于消息存储与生产消费转发)。
6.3 集群架构模型
RocketMQ为我们提供了丰富的集群架构模型,包括单点模式、主从模式、双主模式、以及生产上使用最多的双主双从模式(或者说多主多从模式),在这里我们仅介绍一下经典的双主双从集群模型,如下图所示:
- Producer集群就是生产者集群(他们在同一个生产者组 Producer Group)
- Consumer集群就是消费者集群(他们在同一个消费者组 Consumer Group)
- NameServer集群作为超轻量级的配置中心,只做集群元数据存储和心跳工作,不必保障节点间数据强一致性,也就是说NameServer集群是一个多机热备的概念。
- 对于Broker而言,通常Master与Slave为一组服务,他们互为主从节点,通过NameServer与外部的Client端暴露统一的集群入口。Broker就是消息存储的核心MQ服务了。
七 Kafka
Kafka是linkedin开源的分布式消息系统,目前是Apache的顶级项目
Kafka主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输。
0.8版本开始支持复制,但不支持事务,对消息的重复,丢失,错误没有严格的要求,适合产生大量数据的互联网服务的数据收集工作。
7.1 Kafka的特点
- 跨平台
- 分布式
- 伸缩性
- 实时性
7.2 高性能的原因
- 顺序写:不删除数据,避免随机写
- Page Cache:利用linux的缓存来存储数据
- 高性能
- 高吞吐
- 后台异步
- 主动Flush
- 预读策略
- IO调度
- 零拷贝:
kafka中的消费者在读取服务端的数据时,需要将服务端的磁盘文件通过网络发送到消费者进程,网络发送需要经过几种网络节点。如下图所示:
传统的读取文件数据并发送到网络的步骤如下:
(1)操作系统将数据从磁盘文件中读取到内核空间的页面缓存;
(2)应用程序将数据从内核空间读入用户空间缓冲区;
(3)应用程序将读到数据写回内核空间并放入socket缓冲区;
(4)操作系统将数据从socket缓冲区复制到网卡接口,此时数据才能通过网络发送。
通常情况下,Kafka的消息会有多个订阅者,生产者发布的消息会被不同的消费者多次消费,为了优化这个流程,Kafka使用了“零拷贝技术”,如下图所示: