1、发展历程
早期淘宝内部有两套消息中间件系统:Notify和Napoli。 先有的Notify(至今12历史),后来因有序场景需求,且刚好当时Kafka开源(2011年),因此参照Kafka的设计理念自研了RocketMQ。 目前Notify和RocketMQ两者的定位以下:html
- RocketQ 主要面向消息有序的场景,可以提供更大的消息堆积能力,拉模式,消息持久化在磁盘
- Notify主要面向更加安全可靠地交易类场景,无序、推模式、消息持久化在mysql
RocketMQ发展历程以下:java
- Metaq 1.x 开源社区维护killme2008维护,由于依赖zk挂了,致使上下游服务全网宕机,到了12年基于开源Kafka,直接用java语言翻译重写
- Metaq 2.x 2012年11月上线,淘宝内部使用
- RocketMQ 3.x 后来一统江湖成为整个阿里系主流MQ。基于公司内部开源共建原则, RocketMQ项目只维护核心功能,且去除了全部其余运行时依赖,核心功能最简化。每一个BU的个性化需求都在RocketMQ项目之上进行深度定制。RocketMQ向其余BU提供的仅仅是Jar包,例如要定制一个Broker,那么只须要依赖rocketmq-broker这个jar包便可,可经过API进行交互,若是定制client,则依赖rocketmq-client这个jar包,对其提供的api进行再封装。
- RocketMQ 4.x.x 捐献给Apache社区,通过一年时间重构孵化成为顶级项目
Metaq更名为RocketMQ,RocketMQ项目作核心功能,淘宝内部其余个性化需求有作定制化开发,如:
com.taobao.metaq v3.0 (为淘宝应用提供消息服务 ) com.alipay.zpullmsg v1.0 (为支付宝应用提供消息服务) com.alibaba.commonmq v1.0 (为 B2B 应用提供消息服务)mysql

RocketMQ一共经历了三代里程碑演进:sql
- Notify 为阿里系第一代MQ产品。推模式,数据存储采用关系型数据库。
- Metaq 为阿里系第二代MQ产品。拉模式,自研的专有消息存储,在日志处理方面参考Kafka,典型表明MetaQ。
- RocketMQ为阿里系第三代MQ产品。以拉模式为主,兼有推模式,低延迟消息引擎RocketMQ,在二代功能特性的基础上,为电商金融领域添加了可靠重试、基于文件存储的分布式事务等特性。使用在了阿里大量的应用上,典型如双11场景,具备万亿级消息堆积能力。
RocketMQ项目根据开源与商业分红2个版本:docker
- Apache RocketMQ开源版
- 2013年,阿里云ONS(功能相比较更齐全,特别是运维体系完善,例如:运维管控,安全受权,深度培训等归入商业重中之重)
- 2015年,Aliware MQ(Message Queue)是RocketMQ的商业版本,是阿里云商用的专业消息中间件,是企业级互联网架构的核心产品,基于高可用分布式集群技术,搭建了包括发布订阅、消息轨迹、资源统计、定时(延时)、监控报警等一套完整的消息云服务。
RocketMQ项目根据开源与商业分红2个版本:数据库
- Apache RocketMQ是对外开源版
- 2013年,阿里云ONS(功能相比较更齐全,特别是运维体系完善,例如:运维管控,安全受权,深度培训等归入商业重中之重)
- 2015年,Aliware MQ(Message Queue)是RocketMQ的商业版本,是阿里云商用的专业消息中间件,是企业级互联网架构的核心产品,基于高可用分布式集群技术,搭建了包括发布订阅、消息轨迹、资源统计、定时(延时)、监控报警等一套完整的消息云服务。
2、系统架构
系统定位
- 是一个队列模型的消息中间件,具备高性能、高可靠、高实时、分布式特色
- 同时支持Push与Pull方式消费消息
- 能支撑天猫双十一海量消息考验
- 可以保证严格的消息顺序
- 提供丰富的消息拉取模式
- 高效的订阅者水平扩展能力
- 亿级消息堆积能力

四种集群部署方式:
- 单master (缺点:broker宕机,服务不可用)
- 多master无slave (缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复以前不可订阅)
- 多master多slave,异步复制 (缺点:Master 宕机,磁盘损坏状况,可能会丢失少许消息)
- 多master多slave,同步双写(缺点:性能比异步复制模式略低,大约低 10%左右)
生产环境部署都是多主多从。下面以2主2从为例api
组件角色

3、关键特性
1.单机支持1万以上持久化队列服务器
- 顺序写,随机读。 consumerQueue是逻辑队列存储元数据信息,commitlog负责存储消息,consumerQueue只存储消息在commitlog中的位置信息,定长存储,支持串行方式刷盘。
2.刷盘策略数据结构
两者的区别在因而写完PageCache直接返回,仍是刷盘后返回
3.消息查询/消息回溯
- 支持MessageID和MessageKey查询。(业务场景:如某个订单处理失败,是消息没收到仍是收处处理出错了)
- 按照时间来回溯消息,精度毫秒。(业务场景:订单分析,程序bug,致使今天从某个时间点的消息须要从新开始消费)
4.消息过滤
- Broker端(tag的哈希值比对,丢到对应的consumeQueue中) consumer端(直接和tag比)
5.消息获取机制
本质上都是Pull机制(据官方资料显示其中PushConsumer的实时性接近于push)。
- PushConsumer: consumer经过长轮询拉取消息后回调MessageListener接口完成消费,业务只须要完成MessageListener完成业务逻辑便可。(注册监听回调,一个线程专门长轮训从broker端拉消息,push到一个本地可配置队列)辑便可。(注册监听回调,一个线程专门长轮训从broker端拉消息,push到一个本地可配置队列)
- PullConsumer: 彻底由业务系统去控制,定时拉取消息,指定队列消费,主要由业务控制。
6.单队列并行消费
- 单队列一批消息拉取到消费端,既能够支持单线程串行有序消费,也能够支持多线程乱序消费提升并发性能,以下图所示:

采用滑动窗口方式并行消费,多个线程消费,提交offset都是最小offset。
7.消费负载均衡
都在客户端实现
Producer端:从NameServer获取MessageQueue列表,RR选择具体的消息队列发送消息。
Consumer端: 从NameServer获取MessageQueue列表和其余Consumer状态信息,达到平均消费目的(consumer超过队列数则处于空闲状态)

8.顺序消息原理
在RocketMQ中,主要指的是局部顺序,即一类消息为知足顺序性,必须 Producer 单线程顺序发送,且发送到同一个队列,这样 Consumer 就能够按照 Producer 发送 的顺序去消费消息。
- 普通顺序消息:Broker重启,队列总数发生变化,致使哈希取模后定位队列变化,致使短暂消息顺序不一致。
- 严格顺序消息:只要一台机器不可用,整个集群不可用。(同步双写保证)
9.事务支持
RocketMQ采用了2PC的方案来提交事务消息,同时增长一个补偿逻辑来处理二阶段超时或者失败的消息,以下图所示:

上图说明了事务消息的大体方案,分为两个逻辑:正常事务消息的发送及提交、事务消息的补偿流程
事务消息发送及提交:
- 发送消息(half消息)
- 服务端响应消息写入结果
- 根据发送结果执行本地事务(若是写入失败,此时half消息对业务不可见,本地逻辑不执行)
- 根据本地事务状态执行Commit或者Rollback(Commit操做生成消息索引,消息对消费者可见)
补偿流程:
- 对没有Commit/Rollback的事务消息(pending状态的消息),从服务端发起一次“回查”
- Producer收到回查消息,检查回查消息对应的本地事务的状态
- 根据本地事务状态,从新Commit或者Rollback
- 补偿阶段用于解决消息Commit或者Rollback发生超时或者失败的状况。
10.延时消息
业务场景:支付曾经提过延时消费需求(对应消费失败后,延时多久再推送)
开源版本RocketMQ仅支持定时Level(几个梯度的延时,5s、10s、1min等) 阿里云的ONS支持定时level,以及制定毫秒级别延时时间
11.消息失败重试
Producer 的 send 方法自己支持内部重试,重试逻辑以下:
(1) 至多重试 3 次
(2) 若是发送失败,则轮转到下一个 Broker
(3) 这个方法的总耗时时间不超过 sendMsgTimeout设置的值,默认 10s因此,若是自己向 broker 发送消息产生超时异常,就不会再作重试。 再发送失败由应用层本身作。
- Consumer端:
广播模式:发送失败的消息丢弃, 广播模式对于失败重试代价太高,对整个集群性能会有较大影响,失败重试功能交由应用处理 集群模式:将消费失败的消息一条条的发送到broker的重试队列中去,若是此时依然有发送到重试队列仍是失败的消息,那就在cosumer的本地线 程
定时5秒钟之后重试从新消费消息,再走一次上面的消费流程。
12.Broker HA机制
- 同步双写:HA 采用同步双写方式,主备都写成功,向应用返回成功。
- 异步复制:slave启动一个线程,不断从master拉取commitlog中的数据,而后异步build出ConsumeQueue数据结构。
13.死信队列
因为某些缘由消息没法被正确的投递,为了确保消息不会被无端的丢弃,通常将其置于一个特殊角色的队列,这个队列通常称之为死信队列。与此对应的还有一个“回退队列”的概念,试想若是消费者在消费时发生了异常,那么就不会对这一次消费进行确认(Ack), 进而发生回滚消息的操做以后消息始终会放在队列的顶部,而后不断被处理和回滚,致使队列陷入死循环。为了解决这个问题,能够为每一个队列设置一个回退队列,它和死信队列都是为异常的处理提供的一种机制保障。实际状况下,回退队列的角色能够由死信队列和重试队列来扮演。
14.重试队列
重试队列其实能够当作是一种回退队列,具体指消费端消费消息失败时,为防止消息无端丢失而从新将消息回滚到 Broker 中。与回退队列不一样的是重试队列通常分红多个重试等级,每一个重试等级通常也会设置从新投递延时,重试次数越多投递延时就越大。举个例子:消息第一次消费失败入重试队列 Q1,Q1 的从新投递延迟为 5s,在 5s 事后从新投递该消息;若是消息再次消费失败则入重试队列 Q2,Q2 的从新投递延迟为 10s,在 10s 事后再次投递该消息。以此类推,重试越屡次从新投递的时间就越久,为此须要设置一个上限,超过投递次数就入死信队列。重试队列与延迟队列有相同的地方,都是须要设置延迟级别,它们彼此的区别是:延迟队列动做由内部触发,重试队列动做由外部消费端触发;延迟队列做用一次,而重试队列的做用范围会向后传递。
4、不足之处
RocketMQ无论系统架构,仍是底层存储都有居多亮点,以此来支撑强大的各类特性,不能否认也有居多不足之处:
- 不支持Master/Slave自动切换。RocketMQ开源版本目前还不支持把Slave自动转成Master,若是机器资源不足,须要把Slave转成Master,则要手动中止Slave角色的Broker,更改配置文件,用新的配置文件启动Broker。商业版本支持自动master/slave主从切换
- 不支持数据迁移,对服务扩容不太友好,也不灵活。若是服务须要扩容,只能增长服务器节点数了,而后新增queue分配到新节点上。若是新老机器负载不均衡,要么多增长queue到新机器上,要么替换性能不强的老旧机器
- 不支持多挂载点。当今硬件发展突飞猛进,pc服务器性能愈来愈强大,一个物理机器会挂载很块多磁盘,但一个RocketMQ实例却只能读写操做一个挂载点数据,想榨干机器资源,操做多挂载点须要部署多实例或依靠docker容器等来实现
博客地址引用:http://www.javashuo.com/article/p-zxhfrkhi-dw.html