1. 概述
MQ,Message Queue,是一种提供消息队列服务的中间件。MQ的用途:限流削峰、异步解耦、数据收集
1.1 基本概念
- 消息(Message):生产和消费数据的最小单位,每条消息必须属于一个主题。
- 主题(Topic):Topic表示一类消息的集合,每条消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位。producer:topic 1:n consumer:topic 1:1
- 标签(Tag):为消息设置的标签,用于同一主题下区分不同类型的消息。
- 队列(Queue):存储消息的物理实体。一个Topic中可以包含多个Queue,每个Queue中存放的就是该Topic的消息。一个Topic的Queue中的消息只能被一个消费者组中的一个消费者消费。
- 消息标识(MessageId/Key):RocketMQ中每个消息拥有唯一的MessageId,MessageId有两个:在生产者send()消息时会自动生成一个MessageId(msgId),当消息到达Broker后,Broker也会自动生成一个MessageId(offsetMsgId)。
- msgId:由producer端生成,其生成规则为:
producerIp + 进程pid + MessageClientIDSetter类的ClassLoader的hashCode + 当前时间 + AutomicInteger自增计数器
- offsetMsgId:由broker端生成,其生成规则为:
brokerIp + 物理分区的offset(Queue中的偏移量)
- key:由用户指定的业务相关的唯一标识
1.2 系统架构
1.2.1 Producer
- 负责生产消息。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。
- RocketMQ中的消息生产者都是以生产者组(Producer Group)的形式出现的。生产者组是同一类生产者的集合,这类Producer发送相同Topic类型的消息。一个生产者组可以同时发送多个主题的消息。
1.2.2 Consumer
- 消息消费者,负责消费消息。一个消息消费者会从Broker服务器中获取到消息,并对消息进行相关业务处理。
- RocketMQ中的消息消费者都是以消费者组(Consumer Group)的形式出现的。消费者组是同一类消费者的集合,这类Consumer消费的是同一个Topic类型的消息。消费者组使得在消息消费方面,实现负载均衡(将一个Topic中的不同的Queue平均分配给同一个Consumer Group的不同的Consumer)和容错的目标变得非常容易。
- 消费者组中Consumer的数量如果超出Queue数量,则多出的Consumer将不能消费消息。
1.2.3 Name Server
- NameServer是一个Broker与Topic路由的注册中心,支持Broker的动态注册与发现。
- Broker管理:接受Broker集群的注册信息并且保存下来作为路由信息的基本数据;提供心跳检测机制,检查Broker是否还存活。
- 路由信息管理:每个NameServer中都保存着Broker集群的整个路由信息和用于客户端查询的队列信息。Producer和Conumser通过NameServer可以获取整个Broker集群的路由信息,从而进行消息的投递和消费。
- 路由注册:NameServer是无状态的。在Broker节点启动时,轮询NameServer列表,与每个NameServer节点建立长连接,发起注册请求。在NameServer内部维护着⼀个Broker列表,用来动态存储Broker的信息。Broker节点以心跳包的方式上报给NameServer,每30秒发送一次心跳。心跳包中包含 BrokerId、Broker地址(IP+Port)、 Broker名称、Broker所属集群名称等等。NameServer在接收到心跳包后,会更新心跳时间戳,记录这个Broker的最新存活时间。
- 路由剔除:NameServer没有收到Broker的心跳,NameServer可能会将其从Broker列表中剔除。NameServer中有⼀个定时任务,每隔10秒就会扫描⼀次Broker表,查看每一个Broker的最新心跳时间戳距离当前时间是否超过120秒,如果超过,则会判定Broker失效,然后将其从Broker列表中剔除。
- 路由发现:RocketMQ的路由发现采用的是Pull模型。当Topic路由信息出现变化时,NameServer不会主动推送给客户端,而是客户端定时拉取主题最新的路由。默认客户端每30秒会拉取一次最新的路由。
- 客户端NameServer选择策略: 客户端到底连接的是哪个NameServer节点呢?客户端首先会生产一个随机数,然后再与NameServer节点数量取模,此时得到的就是所要连接的节点索引,然后就会进行连接。如果连接失败,则会采用round-robin策略,逐个尝试着去连接其它节点。首先采用的是随机策略进行的选择,失败后采用的是轮询策略。
1.2.4 Broker
- Broker充当着消息中转角色,负责存储消息、转发消息。Broker同时也存储着消息相关的元数据,包括消费者组消费进度偏移offset、主题、队列等。
- Remoting Module:整个Broker的实体,负责处理来自clients端的请求。
- Client Manager:客户端管理器。负责接收、解析客户端(Producer/Consumer)请求,管理客户端。例如,维护Consumer的Topic订阅信息
- Store Service:存储服务。提供方便简单的API接口,处理消息存储到物理硬盘和消息查询功能。
- HA Service:高可用服务,提供Master Broker 和 Slave Broker之间的数据同步功能。
- Index Service:索引服务。根据特定的Message key,对投递到Broker的消息进行索引服务,同时也提供根据Message Key对消息进行快速查询的功能。
- Broker的集群部署:
- Broker一般都是以集群形式出现的。Broker节点集群是一个主从集群,即集群中具有Master与Slave两种角色。Master负责处理读写操作请求,Slave负责对Master中的数据进行备份。当Master挂掉了,Slave则会自动切换为Master去工作。所以这个Broker集群是主备集群。 Master与Slave 的对应关系是通过指定相同的BrokerName、不同的BrokerId 来确定的。**BrokerId为0表 示Master,非0表示Slave。**每个Broker与NameServer集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。
1.3 工作流程
- 启动NameServer,NameServer启动后开始监听端口,等待Broker、Producer、Consumer连接。
- 启动Broker时,Broker会与所有的NameServer建立并保持长连接,然后每30秒向NameServer定时发送心跳包。
- 发送消息前,可以先创建Topic,创建Topic时需要指定该Topic要存储在哪些Broker上,当然,在创建Topic时也会将Topic与Broker的关系写入到NameServer中。不过,这步是可选的,也可以在发送消息时自动创建Topic。
- Producer发送消息,启动时先跟NameServer集群中的其中一台建立长连接,并从NameServer中获取路由信息,即当前发送的Topic消息的Queue与Broker的地址(IP+Port)的映射关系。然后根据算法策略从队选择一个Queue,与队列所在的Broker建立长连接从而向Broker发消息。当然,在获取到路由信息后,Producer会首先将路由信息缓存到本地,再每30秒从NameServer更新一次路由信息。
- Consumer跟其中一台NameServer建立长连接,获取其所订阅Topic的路由信息,然后根据算法策略从路由信息中获取到其所要消费的Queue,然后直接跟Broker建立长连接,开始消费其中的消息。Consumer在获取到路由信息后,同样也会每30秒从NameServer更新一次路由信息。不过不同于Producer的是,Consumer还会向Broker发送心跳,以确保Broker的存活状态。
1.4 Topic的创建模式
手动创建Topic时,有两种模式:
- 集群模式:该模式下创建的Topic在该集群中,所有Broker中的Queue数量是相同的。
- Broker模式:该模式下创建的Topic在该集群中,每个Broker中的Queue数量可以不同。
自动创建Topic时,默认采用的是Broker模式,会为每个Broker默认创建4个Queue。
1.5 读/写队列
读/写队列从物理上来讲,读/写队列是同一个队列。所以,不存在读/写队列数据同步问题。读/写队列是逻辑上进行区分的概念。一般情况下,读/写队列数量是相同的。
- 比如读队列设置4个,写队列数值8个。代表了 写队列的另外4个队列是不会被消费到的。
- 其这样设计的目的是为了,方便Topic的Queue的缩容。
2 集群搭建理念
2.1 数据复制与刷盘策略
- 复制策略
- 复制策略是Broker的Master与Slave间的数据同步方式。分为同步复制与异步复制:
- 同步复制:消息写入master后,master会等待slave同步数据成功后才向producer返回成功ACK
- 异步复制:消息写入master后,master立即向producer返回成功ACK,无需等待slave同步数据成功
- 刷盘策略
- 刷盘策略指的是broker中消息的落盘方式,即消息发送到broker内存后消息持久化到磁盘的方式。分为同步刷盘与异步刷盘:
- 同步刷盘:当消息持久化到broker的磁盘后才算是消息写入成功。
- 异步刷盘:当消息写入到broker的内存后即表示消息写入成功,无需等待消息持久化到磁盘。
2.2 Broker 集群模式
-
单Master
只有一个broker(其本质上就不能称为集群)。存在单点问题。 -
多Master
broker集群仅由多个master构成,不存在Slave。同一Topic的各个Queue会平均分布在各个master节点上。
- 优点:配置简单,在磁盘配置为RAID10时,即使机器宕机不可恢复情况下,由于RAID10磁盘非常可靠,消息也不会丢(异步刷盘丢失少量消息,同步刷盘一条不丢),性能最高;
- 缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅(不可消费),消息实时性会受到影响。
- 以上优点的前提是,这些Master都配置了RAID磁盘阵列。如果没有配置,一旦出现某Master宕机,则会发生大量消息丢失的情况。
- 多Master多Slave模式-异步复制
- broker集群由多个master构成,每个master又配置了多个slave。master与slave的关系是主备关系,即master负责处理消息的读写请求,而slave仅负责消息的备份与master宕机后的角色切换。
+当master宕机后slave能够自动切换为master。不过由于slave从master的同步具有短暂的延迟(毫秒级),所以当master宕机后,这种异步复制方式可能会存在少量消息的丢失问题。
- 多Master多Slave模式-同步双写
- 所谓同步双写,指的是消息写入master成功后,master会等待slave同步数据成功后才向producer返回成功ACK,即master与slave都要写入成功后才会返回成功ACK,也即双写。
- 该模式与异步复制模式相比,优点是消息的安全性更高,不存在消息丢失的情况。但单个消息的RT略高,从而导致性能要略低(大约低10%)。
- 该模式存在一个大的问题:对于目前的版本,Master宕机后,Slave不会自动切换到Master。
- 最佳实践
- 一般会为Master配置RAID10磁盘阵列,然后再为其配置一个Slave。即利用了RAID10磁盘阵列的高效、安全性,又解决了可能会影响订阅的问题。
1)RAID磁盘阵列的效率要高于Master-Slave集群。因为RAID是硬件支持的。也正因为如此, 所以RAID阵列的搭建成本较高。
2)多Master+RAID阵列,与多Master多Slave集群的区别是什么? - 多Master+RAID阵列,其仅仅可以保证数据不丢失,即不影响消息写入,但其可能会影响到 消息的订阅。但其执行效率要远高于多Master多Slave集群
- 多Master多Slave集群,其不仅可以保证数据不丢失,也不会影响消息写入。其运行效率要低于多Master+RAID阵列
2.3、磁盘阵列RAID
RAID原来为廉价冗余磁盘阵列,现在是独立磁盘冗余阵列的意思。
2.4 关键技术
2.4.1 镜像技术
- 镜像技术是一种冗余技术,为磁盘提供数据备份功能,防止磁盘发生故障而造成数据丢失。最典型地的用法就是,同时在磁盘阵列中产生两个完全相同的数据副本,并且分布在两个不同的磁盘上。镜像提供了完全的数据冗余能力,当一个数据副本失效不可用时,外部系统仍可正常访问另一副本。而且,镜像不需要额外的计算和校验,故障修复非常快,直接复制即可。镜像技术可以从多个副本进行并发读取数据,提供更高的读 I/O 性能,但不能并行写数据,写多个副本通常会导致一定的 I/O 性能下降。
- 镜像技术提供了非常高的数据安全性,需要至少双倍的存储空间。高成本限制了镜像的广泛应用,主要应用于至关重要的数据保护,这种场合下的数据丢失可能会造成非常巨大的损失。
2.4.2 数据条带技术
数据条带化技术是一种自动将 I/O操作负载均衡到多个物理磁盘上的技术。更具体地说就是,将一块连续的数据分成很多小部分并把它们分别存储到不同磁盘上。这就能使多个进程可以并发访问数据的多个不同部分,从而获得最大程度上的 I/O 并行能力,极大地提升性能
2.4.3数据校验技术
数据校验技术是指, RAID 要在写入数据的同时进行校验计算,并将得到的校验数据存储在 RAID 成员磁盘中。校验数据可以集中保存在某个磁盘或分散存储在多个不同磁盘中。当其中一部分数据出错时,就可以对剩余数据和校验数据进行反校验计算重建丢失的数据。
数据校验技术相对于镜像技术的优势在于节省大量开销,但由于每次数据读写都要进行大量的校验运算,对计算机的运算速度要求很高,且必须使用硬件 RAID 控制器。在数据重建恢复方面,检验技术比镜像技术复杂得多且慢得多。
2.5 常见RAID等级详解
RAID0
RAID0 是一种简单的、无数据校验的数据条带化技术。
RAID1
RAID1 就是一种镜像技术。应用场景:对顺序读写性能要求较高,或对数据安全性要求较高的场景。
RAID10
RAID10是一个RAID1与RAID0的组合体,所以它继承了RAID0的快速和RAID1的安全。
简单来说就是,先做条带,再做镜像。发即将进来的数据先分散到不同的磁盘,再将磁盘中的数据做镜像。
RAID01
RAID01是一个RAID0与RAID1的组合体,所以它继承了RAID0的快速和RAID1的安全。
简单来说就是,先做镜像再做条带。即将进来的数据先做镜像,再将镜像数据写入到与之前数据不同的磁盘,即再做条带。
2.6 集群搭建注意点
- master broker的配置文件
# 指定整个broker集群的名称,或者说是RocketMQ集群的名称
brokerClusterName=DefaultCluster
# 指定master-slave集群的名称。一个RocketMQ集群可以包含多个master-slave集群
brokerName=broker-a
# master的brokerId为0
brokerId=0
# 指定Name Server的地址
namesrvAddr=192.168.59.164:9876;192.168.59.165:9876
- slave的配置文件
brokerClusterName=DefaultCluster
# 指定这是另外一个master-slave集群
brokerName=broker-b
# slave的brokerId为非0
brokerId=1