本篇从基础角度解析分布式消息队列的基础;讲述了MQ的主要应用场景与MQ的性能指标;MQ的技术选型关注点;主流MQ的集群架构与原理解析。一些基础原理性东西会比较多,希望大家能有所收获。
1.MQ应用场景与MQ性能衡量指标
MQ应用场景:服务解耦,削峰填谷,异步化缓冲
服务解耦:根据服务的依赖性,是微服务一个技术手段;(强依赖:
对于执行的方式可能是同步的double调用,同步的http做Springcloud,jrpc都可)
弱依赖:采用消息中间件,完成消息的解耦;弱依赖,不一定可以失败;跟可靠性投递相关
削峰填谷:将流量的巅峰跟低谷做一个均衡。生产环境中,即时性很高或者流量很大的一些应用场景,类似秒杀或者大促
异步化缓冲:需要做到最终一致性即可。
分布式消息队列(MQ)应用思考点:
生产端可靠性投递(保证消息投递成功);消费端幂等(消费不能消费多次);
高可用;低延迟;消息的可靠性(replica);消息的堆积能力;扩展性(扩容)
2.MQ的技术选型关注点
如何进行技术选型:各个MQ的性能,优缺点,相应的业务场景;
**Active MQ:**适合与传统行业,中小型企业,承载能力不优秀
Rabbit MQ:镜像队列(主要是满足数据不丢失),横向扩展能力不太好;
集群架构模式,分布式,可扩展,高可用,可维护性;
综合成本,集群规模,人员成本;
未来方向,规划,思考;
3.ActiveMQ集群架构与原理解析
初识 JMS 与其专业术语
先和大家一起了解一下古老而又神秘的消息中间件"ActiveMQ"。首先,说起ActiveMQ,就必须先聊聊JMS(Java Message Service)规范,也就是Java消息服务,它定义了Java中访问消息中间件的接口的规范。在这里注意哦,JMS只是接口,并没有给予实现,实现JMS接口的消息中间件称为 “JMS Provider”,目前知名的开源 MOM (Message Oriented Middleware,也就是消息中间件)系统包括Apache的ActiveMQ、RocketMQ、Kafka,以及RabbitMQ,可以说他们都 “基本遵循” 或 “参考” JMS规范,都有自己的特点和优势。
专业术语
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可能就显得力不从心了。
消息投递模式
我们首先要了解JMS规范里最经典的两种消息投递模式,即 “点对点” 与 “发布订阅”。
点对点:生产者向队列投递一条消息,只有一个消费者能够监听得到这条消息(PTP),下图所示:
发布订阅:生产者向队列投递一条消息,所有监听该队列的消费者都能够监听得到这条消息(P/S),下图所示:
ActiveMQ各项指标
衡量一个MOM,我们主要从三方面考虑即可,即服务性能、存储堆积能力、可扩展性。
服务性能
ActiveMQ的性能一般,在早期传统行业为王的时代还是比较流行的,但现如今面对高并发、大数据的业务场景,往往力不从心!
数据存储
默认采用kahadb存储(索引文件形式存储),也可以使用高性能的google leveldb(内存数据库存储), 或者可以使用MySql、Oracle进程消息存储(关系型数据库存储)。
集群架构
ActiveMQ 可以与zookeeper进行构建 主备集群模型,并且多套的主备模型直接可以采用Network的方式构建分布式集群。
ActiveMQ集群架构模式
ActiveMQ最经典的两种集群架构模式,Master-Slave 、Network 集群模式!
Master-Slave:
Master-Slave:顾名思义,就是主从方式,当然这里要理解为主备的方式,也就是双机热备机制;Master Slave 背后的想法是,消息被复制到slave broker,因此即使master broker遇到了像硬件故障之类的错误,你也可以立即切换到slave broker而不丢失任何消息。 Master Slave是目前ActiveMQ推荐的高可靠性和容错的解决方案。
技术思考:Master-Slave集群模型的关键点:
上图(Master-Slave)绿色的为主节点,灰色的则为备份节点,这两个节点都是运行状态的。
zookeeper的作用就是为了当绿色的主节点宕机时,进行及时切换到备份的灰色节点上去,使其进行主从角色的互换,用于实现高可用性的方案。
Master-Slave集群模型的缺点也显而易见,就是不能做到分布式的topic、queue,当消息量巨大时,我们的MQ集群压力过大,没办法满足分布式的需求。
Network:
Network:这里可以理解为网络通信方式,也可以说叫Network of brokers。这种方式真正解决了分布式消息存储和故障转移、broker切换的问题。可以理解消息会进行均衡;从ActiveMQ1.1版本起,ActiveMQ支持networks of brokers。它支持分布式的queues和topics。一个broker会相同对待所有的订阅(subscription):不管他们是来自本地的客户连接,还是来自远程broker,它都会递送有关的消息拷贝到每个订阅。远程broker得到这个消息拷贝后,会依次把它递送到其内部的本地连接上。
技术思考:Network集群模型的关键点:
首先,这种方案需要两套或多套(Master-Slave)的集群模型才可以搞定,部署非常麻烦,需要两套或多套集群直接相互交叉配置,相互间能够感知到彼此的存在。下面我给出一段XML配置,简单来说就是在ActiveMQ的配置文件里要进行多套(Master-Slave)之间的 networkConnector配置工作:
<broker brokerName="receiver" persistent="false" useJmx="false"><transportConnectors><transportConnector uri="tcp://localhost:62002"/></transportConnectors><networkConnectors><networkConnector
uri="static:( tcp://localhost:61616,tcp://remotehost:61616)"/></networkConnectors></broker>
其次,Network虽然解决了分布式消息队列这个难题,但是还有很多潜在的问题,最典型的就是资源浪费问题,并且也可能达不到所预期的效果;通常采用Master-Slave模型是传统型互联网公司的首选,作为互联网公司往往会选择开箱即用的消息中间件,从运维、部署、使用各个方面都要优于ActiveMQ,当然ActiveMQ毕竟是 “老牌传统强Q”,Apache的顶级项目之一。
有兴趣的小伙伴可以关注一下官网,官网地址如下:https://activemq.apache.org/
3.RabbitMQ集群架构模型与原理解析
Rabbit四种集群架构:
主备模式:
Master-Slave:热备份;使用haproxy做主备
配置信息:
远程模式:
早期版本提供的多活的存储;主要是做数据的异地的容灾;
也可提升性能,单个集群处理不过来,可将消息传递到下游节点;
架构简单,配置简单;配置复杂,使用极少。
定义:远距离通信和复制,可以实现双活的一种模式,简称为Shovel
所谓Shovel就是我们可以把消息进行不同数据中的复制工作,可以
跨地域的让两个mq集群互联
配置信息:
Step3:添加配置键rabbitmq.config
Step4:源与目的地服务器使用相同的配置文件(rabbitmq.config)
镜像模式:
个人理解:软件系统的copy,将相同的软件以及数据在
在镜像系统(备份系统)上运行,提高数据的安全性与可靠性;
最经典的是Mirror镜像模式,保证数据100%不丢失
实际工作中用的最多,并且实现集群非常的简单,一般互联网大厂
都会构建这种镜像集群模式
缺点:不能进行横向的扩展(消息易堆积,横向只是多加一个备份,负担)
高可靠;数据同步;奇数几点(集群脑裂或宕机快速选出Master)
多活模型:
异地的容灾,双活,数据的转储功能;
实现异地数据复制的主流模式;因为shove模式配置比较复杂,所以一般来说异地集群都是使用这种双活或者多活模型来实现;
这种模式需要rabbitMQ的federation插件,可以实现持续可靠的AMQP数据通信,多活模式实际配置与应用非常简单
Federation插件是一个不需要构建Cluster,而在Broker之间传输
消息的高性能插件,federation插件可以在Brokers或者在Cluster之间
传输消息,连接的双方可以使用不同的users和virtual hosts,双方也可
以使用版本不同的RabbbitMQ和Erlang.federation插件使用AMQP协议
通讯,可以接受不连续的传输;
4.RocketMQ集群架构与原理解析
RocketMQ是一款分布式,队列模型的消息中间件,由阿里巴巴自主研发
的一款适用于高并发,高可靠性,海量数据场景的消息中间件;
早期开源2.x版本名为MetaQ;15年迭代3.x版本,更名为RocketMQ,16年开始贡献到Apache,经过1年多的孵化,最终成为Apache顶级的开源项目,更新非常频繁,社区活跃度也非常高;
其消息的路由、存储、集群划分都借鉴了Kafka优秀的设计思路,并结合自身的 “双十一” 场景进行了合理的扩展和API丰富。
优秀的能力与支持
接下来我们一起来看一下RocketMQ优秀的能力吧 ~
支持集群模型、负载均衡、水平扩展能力
亿级别的消息堆积能力
采用零拷贝的原理、顺序写盘、随机读(索引文件)
丰富的API使用
代码优秀,底层通信框架采用Netty NIO框架
NameServer 代替 Zookeeper
强调集群无单点,可扩展,任意一点高可用,水平可扩展
消息失败重试机制、消息可查询
开源社区活跃度、是否足够成熟(经过双十一考验)
专业术语
Producer:消息生产者,负责产生消息,一般由业务系统负责产生消息。
Consumer:消息消费者,负责消费消息,一般是后台系统负责异步消费。
Push Consumer:Consumer的一种,需要向Consumer对象注册监听。
Pull Consumer:Consumer的一种,需要主动请求Broker拉取消息。
Producer Group:生产者集合,一般用于发送一类消息。
Consumer Group:消费者集合,一般用于接受一类消息进行消费。
Broker : MQ消息服务(中转角色,用于消息存储与生产消费转发)。
RocketMQ核心源码包及功能说明
rocketmq-broker 主要的业务逻辑,消息收发,主从同步, pagecache
rocketmq-client 客户端接口,比如生产者和消费者
rocketmq-common 公用数据结构等等
rocketmq-distribution 编译模块,编译输出等
rocketmq-example 示例,比如生产者和消费者
rocketmq-fliter 进行Broker过滤的不感兴趣的消息传输,减小带宽压力
rocketmq-logappender、rocketmq-logging日志相关
rocketmq-namesrv Namesrv服务,用于服务协调
rocketmq-openmessaging 对外提供服务
rocketmq-remoting 远程调用接口,封装Netty底层通信
rocketmq-srvutil 提供一些公用的工具方法,比如解析命令行参数
rocketmq-store 消息存储核心包
rocketmq-test 提供一些测试代码包
rocketmq-tools 管理工具,比如有名的mqadmin工具
集群架构模型
RocketMQ为我们提供了丰富的集群架构模型,包括单点模式、主从模式、双主模式、以及生产上使用最多的双主双从模式(或者说多主多从模式),在这里我们仅介绍一下经典的双主双从集群模型,如下图所示:
Producer集群就是生产者集群(他们在同一个生产者组 Producer Group)
Consumer集群就是消费者集群(他们在同一个消费者组 Consumer Group)
NameServer集群作为超轻量级的配置中心,只做集群元数据存储和心跳工作,不必保障节点间数据强一致性,也就是说NameServer集群是一个多机热备的概念。
对于Broker而言,通常Master与Slave为一组服务,他们互为主从节点,通过NameServer与外部的Client端暴露统一的集群入口。Broker就是消息存储的核心MQ服务了。
集群架构思考
RocketMQ作为国内顶级的消息中间件,其性能主要依赖于天然的分布式Topic/Queue,并且其内存与磁盘都会存储消息数据,借鉴了Kafka的 “空中接力” 概念(这个我们后面学习Kafka的时候会详细的说明),所谓 “空中接力” 就是指数据不一定要落地,RocketMQ提供了同步/异步双写、同步/异步复制的特性。在真正的生产环境中应该选择符合自己业务的配置。下面针对于RocketMQ的高性能及其瓶颈在这里加以说明:
技术思考:
RocketMQ如果在实际生产环境采用8M-8S的集群架构(8主8从)硬件单点Master为32C,96G内存,500G的SSD
**IOPS:**一个用于计算机存储设备,固态硬盘或存储区域网络性能测试的量测方式,可以视为美妙的读写次数
其主要瓶颈最终会落在IOPS上面,当高峰期来临的时候,磁盘读写能力是主要的性能瓶颈,每秒收发消息IOPS达到10W+ 消息,这也是公司内部主要的可靠性消息中间件
在很多时候,业务会有一些非核心的消息投递,后续会进行消息中间件的业务拆分,把不重要的消息(可以允许消息丢失、非可靠性投递的消息)采用Kafka的异步发送机制,借助Kafka强大的吞吐量和消息堆积能力来做业务的分流(当然RocketMQ的性能也足够好)。
为什么瓶颈在IOPS?
根本原因还是因为云环境导致的问题,云环境的SSD物理存储显然和自建机房SSD会有不小的差距,这一点我们无论是从数据库的磁盘性能、还是搜索服务(ElasticSearch)的磁盘性能,都能给出准确的瓶颈点,单机IOPS达到1万左右就是云存储SSD的性能瓶颈,这个也解释了 “木桶短板原理” 的效应,在真正的生产中,CPU的工作主要在等待IO操作,高并发下 CPU资源接近极限,但是IOPS还是达不到我们想要的效果。
5.kafka介绍与高性能原因分析
Kafka介绍:日志收集和传输;适合产生大量数据的互联网服务的数据收集业务
如果你想做消息一条不丢,kafka能够实现,效率会相对低下。
kafka特点:
分布式;跨平台;实时性;伸缩性强
Kafka做日志收集,瓶颈点在ES,ES集群的磁盘满了,导致ES消息限流;
消息都堆积在kafka,数据堆积量可能达到了几十亿;并不影响kafka消息接收能力。
Kafka高性能的原因:
顺序写,PageCache空中接力,高效读写;(顺序写排,可以提高磁盘的利用率)
高性能,高吞吐;
后台异步,主动Flush;
预读策略,IO调度
6.kafka高性能核心pageCache与zeroCopy原理解析
pagecache:
页面缓存,是操作系统实现的一种主要的磁盘缓存的机制,以此来减少对磁盘IO的缓存。
目的就是为了减少磁盘io的操作。
具体来说就是讲磁盘中的数据,缓存到内存中。将对磁盘的访问转到内存上。
现在很多的操作系统为了弥补性能差异,都是将内存当做磁盘来缓存。
当redis抗不住高缓存,高并发场景、可能会借用到内存,存入到Java内存中,也会影响Java的性能
当一个系统准备去读取磁盘上的文件,操作系统首先不是去读取磁盘上的文件
首先检查所读取的数据在pageCache中是否存在,存在即命中,直接返回数据即可,
避免了对物理磁盘的直接操作;如果没有命中,会往磁盘发送IO请求,并且将读取
的数据先添加到缓存页中去做缓存;(数据库多次查询相同的数据时速度明显块,也
是cache的功能,也就是缓存)
对于写操作,检查数据缓存的页是否在缓存页中,不存在就会在缓存页中添加相应
的页,然后把数据添加到相应的页中;(被修改的页就是脏页),操作系统会在合适
的时机调度实现,将脏页中的数据添加到磁盘里,保证数据的一致性
kafaka不做图上的四次copy
zero copy:
只是将我们磁盘中的文件的数据复制到了页面缓存中一次、然后将页面缓存直接发送到网卡中
7.kafka集群模型讲解
大部分时间都是做的内存级别的replicate副本集.当生产者和消费者速率
相当的时候,不需要去用到磁盘,磁盘就做一个异步的备份而已;
也就是说消费者直接从内存缓存(PageCache)中提取出来即可。
可靠性:并不会保证100%的可靠性,使用replicate。因为多个节点,当某
个节点数据丢失,可以从其他节点PageCache中获取。
版权归原作者 TOMORROW6COME 所有, 如有侵权,请联系我们删除。