RocketMQ是阿里开源的一款十分优秀的消息队列,rocketMQ具有很多其他消息队列不具有的特性,更重要的是rocketMQ是用java开发的学习成本较低,并且经历了双11的数据洪峰的考验。rocketMQ已经加入了apache,成为apache的顶级项目。
RocketMQ的官网:http://rocketmq.apache.org/
RocketMQ的gitHub:https://github.com/apache/rocketmq
RocketMQ架构分为四个模块:NameServer, Broker,Producer,Consumer
Namesrv 是由阿里云RocketMQ中间件开发团队开发的基于服务注册发现功能的无状态组件,支持独立部署。Namesrv在整个RocketMQ架构体系中,属于重中之重的组件,乃灵魂级组件,统筹全局,可谓之'一家之主'。上可撩得生产者靓妹,下可驾驭消费者御姐,亦可跟broker徐娘亲近。
那么它又是如何工作的呢?
1、生产者从namesrv中获取可用的broker地址,将消息发送至broker。
2、消费者从namesrv中获取可用的broker地址,从broker中拉去消息。
3、broker定时向naemsrv发送心跳信息,维护可用broker地址。
相对来说,nameserver的稳定性非常高。原因有二:
1、 nameserver互相独立,彼此没有通信关系,单台nameserver挂掉,不影响其他nameserver,即使全部挂掉,也不影响业务系统使用,这点类似于dubbo的zookeeper。
2 、nameserver不会有频繁的读写,所以性能开销非常小,稳定性很高。
NameServer类似于SpringCloud中的eureka
Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示 Master,非0表示Slave。Master也可以部署多个。每个Broker与Name Server集群中的所有节点建立长连接,定时注册Topic信息到所有Name Server。
与nameserver关系 :连接 :单个broker和所有nameserver保持长连接
心跳 : 心跳间隔:每隔30秒(此时间无法更改)向所有nameserver发送心跳,心跳包含了自身的topic配置信息。 心跳超时:nameserver每隔10秒钟(此时间无法更改),扫描所有还存活的broker连接,若某个连接2分钟内(当前时间与最后更新时间差值超过2分钟,此时间无法更改)没有发送心跳数据,则断开连接。
断开 :时机:broker挂掉;心跳超时导致nameserver主动关闭连接 ; 动作:一旦连接断开,nameserver会立即感知,更新topc与队列的对应关系,但不会通知生产者和消费者
可用性 :由于消息分布在各个broker上,一旦某个broker宕机,则该broker上的消息读写都会受到影响。所以rocketmq提供了master/slave的结构,salve定时从master同步数据,如果master宕机,则slave提供消费服务,但是不能写入消息,此过程对应用透明,由rocketmq内部解决。 这里有两个关键点: 一旦某个broker master宕机,生产者和消费者多久才能发现?受限于rocketmq的网络连接机制,默认情况下,最多需要30秒,但这个时间可由应用设定参数来缩短时间。这个时间段内,发往该broker的消息都是失败的,而且该broker的消息无法消费,因为此时消费者不知道该broker已经挂掉。 消费者得到master宕机通知后,转向slave消费,但是slave不能保证master的消息100%都同步过来了,因此会有少量的消息丢失。但是消息最终不会丢的,一旦master恢复,未同步过去的消息会被消费掉。
可靠性 :所有发往broker的消息,有同步刷盘和异步刷盘机制,总的来说,可靠性非常高 。同步刷盘时,消息写入物理文件才会返回成功,因此非常可靠 ;异步刷盘时,只有机器宕机,才会产生消息丢失,broker挂掉可能会发生,但是机器宕机崩溃是很少发生的,除非突然断电 。
与nameserver关系 :连接 ,单个生产者者和一台nameserver保持长连接,定时查询topic配置信息,如果该nameserver挂掉,生产者会自动连接下一个nameserver,直到有可用连接为止,并能自动重连。
轮询时间 :默认情况下,生产者每隔30秒从nameserver获取所有topic的最新队列情况,这意味着某个broker如果宕机,生产者最多要30秒才能感知,在此期间,发往该broker的消息发送失败。该时间由DefaultMQProducer的pollNameServerInteval参数决定,可手动配置。
心跳 :与nameserver没有心跳
与broker关系 :连接 :单个生产者和该生产者关联的所有broker保持长连接。
心跳 :默认情况下,生产者每隔30秒向所有broker发送心跳,该时间由DefaultMQProducer的heartbeatBrokerInterval参数决定,可手动配置。broker每隔10秒钟(此时间无法更改),扫描所有还存活的连接,若某个连接2分钟内(当前时间与最后更新时间差值超过2分钟,此时间无法更改)没有发送心跳数据,则关闭连接。
连接断开 :移除broker上的生产者信息
与nameserver关系 :连接 :单个消费者和一台nameserver保持长连接,定时查询topic配置信息,如果该nameserver挂掉,消费者会自动连接下一个nameserver,直到有可用连接为止,并能自动重连。
心跳 :与nameserver没有心跳
轮询时间 :默认情况下,消费者每隔30秒从nameserver获取所有topic的最新队列情况,这意味着某个broker如果宕机,客户端最多要30秒才能感知。该时间由DefaultMQPushConsumer的pollNameServerInteval参数决定,可手动配置。
与broker关系 :连接 :单个消费者和该消费者关联的所有broker保持长连接。
心跳 :默认情况下,消费者每隔30秒向所有broker发送心跳,该时间由DefaultMQPushConsumer的heartbeatBrokerInterval参数决定,可手动配置。broker每隔10秒钟(此时间无法更改),扫描所有还存活的连接,若某个连接2分钟内(当前时间与最后更新时间差值超过2分钟,此时间无法更改)没有发送心跳数据,则关闭连接,并向该消费者分组的所有消费者发出通知,分组内消费者重新分配队列继续消费
断开 :时机:消费者挂掉;心跳超时导致broker主动关闭连接 ;动作:一旦连接断开,broker会立即感知到,并向该消费者分组的所有消费者发出通知,分组内消费者重新分配队列继续消费
负载均衡 :集群消费模式下,一个消费者集群多台机器共同消费一个topic的多个队列,一个队列只会被一个消费者消费。如果某个消费者挂掉,分组内其它消费者会接替挂掉的消费者继续消费。
消费机制 :本地队列 :消费者不间断的从broker拉取消息,消息拉取到本地队列,然后本地消费线程消费本地消息队列,只是一个异步过程,拉取线程不会等待本地消费线程,这种模式实时性非常高。对消费者对本地队列有一个保护,因此本地消息队列不能无限大,否则可能会占用大量内存,本地队列大小由DefaultMQPushConsumer的pullThresholdForQueue属性控制,默认1000,可手动设置。
轮询间隔 :消息拉取线程每隔多久拉取一次?间隔时间由DefaultMQPushConsumer的pullInterval属性控制,默认为0,可手动设置。
消息消费数量 :监听器每次接受本地队列的消息是多少条?这个参数由DefaultMQPushConsumer的consumeMessageBatchMaxSize属性控制,默认为1,可手动设置。
高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。
假设系统一直能够提供服务,我们说系统的可用性是100%。
如果系统每运行100个时间单位,会有1个时间单位无法提供服务,我们说系统的可用性是99%。
很多公司的高可用目标是4个9,也就是99.99%,这就意味着,系统的年停机时间为8.76个小时。
我们都知道,单点是系统高可用的大敌,单点往往是系统高可用最大的风险和敌人,应该尽量在系统设计的过程中避免单点。方法论上,高可用保证的原则是“集群化”,或者叫“冗余”:只有一个单点,挂了服务会受影响;如果有冗余备份,挂了还有其他backup能够顶上。
保证系统高可用,架构设计的核心准则是:冗余。
有了冗余之后,还不够,每次出现故障需要人工介入恢复势必会增加系统的不可服务实践。所以,又往往是通过“自动故障转移”来实现系统的高可用。
将同一个业务部署在多台服务器上,如果主机宕机了,其它服务器可以自动接替主机服务器工作,以实现持续性为客户提供服务,并且处理科研实验以及核处理等大型计算业务,单台大型计算机依然无法胜任,集群可以将一个计算业务交给集群中的多台计算机进行处理。
RocketMQ如何做集群部署来提供系统的吞吐量,以及高可用性?从整体的架构上便可一眼看出,服务注册与发现组件namesrv可以独立部署,且namesrv与namesrv之间并无直接或间接的关联,双方不存在心跳检测,所以namesrv的之间不存在主备切换过程,如果其中一台namesrv宕机后,生产者消费者会直接从另一台namesrv中请求数据。但也正因为namesrv之间不存在心跳检测,主备切换,所以无法支持动态扩容,当机器宕机需要重新部署基于新的ip地址的namesrv需要更新生产者/消费者直连的namesrv地址。
broker支持主从架构
broker支持主从架构模式,但是并非是非常完善的主从架构,据说会在后续版本中优化。
主从架构模式为何会说不是完善的主从架构呢?说到主从 架构模式,大家最熟悉,最耳熟能详的必然是MySQL的主从读写分离模式。主库支持writer,比如insert/update/delete等对数据产生修改的操作,而从库则只支持read操作,这种架构设计是基于目前互联网读多写少的业务模式。
那么RocketMQ又是提供了何种主从读写分离的模式呢?
1、目前它支持master写操作,只有当master读压力高于某个点(master消息拉取出现堆积时),才会将读压力转给salver。
2、无法做到主从切换,master宕机,salver只能提供消息消费,salver不会被选举为master来继续工作。如果master宕机,消息队列整个环境近乎瘫痪。
主从复制
决定rocketmq是否为master还是slaver,是从配置文件中读取设定的,如下:
public enum BrokerRole {
ASYNC_MASTER,
SYNC_MASTER,
SLAVE;
}
ASYNC_MASTER:异步master,也就是新的消息存储时不需要等slave同步好;
SYNC_MASTER:同步master,新消息存现时需要等slave同步好(也就是返回的 Ack Offset >= 当前消息的CommitLog Offset;)
Slave:指该brokder为slaver;
当master启动是,是不会主动向slaver同步数据的。当slaver启动时,会上报当前的commitlog offset偏移值。一般会有两种情况,一种是slaver是全新的机器,commitlog是空的,传递maxPhyOffset=0。一种是master在使用过程中宕机了,经运维人员修复后重启成功,继续工作,master会根据slaver上报的maxPhyOffset的值继续同步。
多master多salver场景
如果用户体量稍微大一些,单master单slaver扛不住,可以采用多master/多slaver部署架构。
broker同步/异步刷盘
前文中我们提到,RocketMQ是基于高性能低延迟的文件储存,为了让用户在使用过程中可以按照自己对消息的丢失容忍程度与性能之间做一个选择,RocketMQ提供了两种方式刷盘方式,即同步刷盘/异步刷盘。顾名思义,同步刷盘指消息投放到broker之后,会在写入文件之后才返回成功,而异步刷盘则指消息投放broker成功后即可返回,同时启动另外的线程来存储消息。
同步刷盘的有点非常明显,可以保证消息可靠性,但是性能上无疑要略逊一筹。
异步刷盘反其道而行之,性能上肯定有了显著提高,但是消息可靠性却无所保证,因为在文件写入过程失败,无法通知生产者重试。
部署方式 | 优点 | 缺点 | 备注 |
---|---|---|---|
单个Master模式 | 一旦Broker重启或者宕机时,会导致整个服务不可用,不建议线上环境使用; | 单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息实时性会收到影响。 | |
多个Master模式 | 配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时,即使机器宕机不可恢复情况下,由于RAID10磁盘非常可靠,消息也不会丢(异步刷盘丢失少量消息,同步刷盘一条不丢),性能最高。 | Master宕机,磁盘损坏情况,会丢失少量信息。 | 当使用多master无slave的集群搭建方式时,master的brokerRole配置必须为ASYNC_MASTER。如果配置为SYNC_MASTER,则producer发送消息时,返回值的SendStatus会一直是SLAVE_NOT_AVAILABLE。 |
多Master多Slave模式——异步复制 | 即使磁盘损坏,消息丢失的非常少,但消息实时性不会受影响,因为Master宕机后,消费者仍然可以从Slave消费,此过程对应用透明,不需要人工干预,性能同多Master模式几乎一样。 | 性能比异步复制模式稍低,大约低10%左右,发送单个消息的RT会稍高,目前主宕机后,备机不能自动切换为主机,后续会支持自动切换功能。 | |
多Master多Slave模式——同步双写 | 数据与服务都无单点,Master宕机情况下,消息无延迟,服务可用性与数据可用性都非常高; |
所以broker的高可用就是:master slave 配合,master 支持读、写,slave 只读,producer 只能和 master 连接写入消息,consumer 可以连接 master 和 slave。
创建 topic 时,把 message queue 创建在多个 broker 组上(brokerName 一样,brokerId 不同),当一个 broker 组的 master 不可用后,其他组的 master 仍然可以用,producer 可以继续发消息。
当 master 不可用或者繁忙时,consumer 会被自动切换到 slave 读。所以,即使 master 出现故障,consumer 仍然可以从 slave 读消息,不受影响。