国庆期间闲来无事,写了一个简单的小程序,小程序名称叫做 IT藏经楼。目的是分享这些年自己积累的一些学习材料,方面大家查找使用,包括电子书、案例项目、学习视频、面试题和一些PPT模板。里面所有材料都免费分享。目前小程序中只发布了非常小的一部分,后续会陆续上传分享。当前版本的小程序页面也比较简单,还在逐渐的优化中。
计算机系统的可用性用平均无故障时间来度量,系统的可用性越高,则平均无故障时间越长。高可用性也是分布式中间件的重要特性,RocketMQ的高可用设计主要有四个方面的体现:
重试机制比较简单,在消息发送出现异常时会尝试再次发送,默认最多重试三次。重试机制仅支持同步发送方式,不支持异步和单向发送方式。根据发送失败的异常类型处理策略略有不同。
如果是网络异常RemotingException和客户端异常MQClientException会重试,而Broker服务端异常MQBrokerException和线程中断异常InterruptedException则不会再重试,且抛出异常。
在介绍NameServer时提到,NameServer为了简化和客户端通信,发现Broker故障时并不会立即通知客户端。故障规避机制用来解决当Broker出现故障,Producer不能及时感知而导致消息发送失败的问题。默认是不开启的,如果在开启的情况下,消息发送失败的时候会将失败的Broker暂时排除在队列选择列表外。规避时间是衰减的,如果Broker一直不可用,会被NameServer检测到并在Producer更新路由信息时进行剔除。
在选择查找路由时,选择消息队列的关键步骤如下:
判断消息队列是否可用有两个步骤:
这部分重点在于故障机器FaultItem在什么场景下进入故障列表faultItemTable中,消息发送失败时就可能使机器故障了。
RocketMQ为了提高消息消费的高可用性,避免Broker发生单点故障引起存储在Broker上的消息无法及时消费,同时避免单个机器上硬盘损坏出现消息数据丢失。RocketMQ采用Broker数据主从复制机制,当消息发送到Master服务器后会将消息同步到Slave服务器,如果Master服务器宕机,消息消费者还可以继续从Slave拉取消息。
消息从Master服务器复制到Slave服务器上,有两种复制方式:同步复制SYNC_MASTER和异步复制ASYNC_MASTER。通过配置文件${ROCKETMQ_HOME}/conf/broker.conf里面的brokerRole参数进行设置。
在实际应用中需要结合业务场景,合理设置刷盘方式和主从复制方式。不建议使用SYNC_FLUSH同步刷盘方式,因为它会频繁地触发写磁盘操作,性能下降明显。高性能是RocketMQ的一个明显特点,因此放弃性能是不合适的选择。通常可以把Master和Slave设置成异步刷盘、同步复制,这样即使有一台服务器出现故障,仍然可以保证数据不丢失。
实际业务场景中无法避免消费消息失败的情况,消费失败可能是因为业务处理中调用远程服务网络问题失败,不代表消息一定不能被消费,通过重试可以解决。介绍RocketMQ的消费重试机制之前,需要先了解一下重试队列和死信队列。
通常故障恢复需要一定的时间,如果不间断地重试,重试又失败的情况会占用并浪费资源,所以RocketMQ的消费重试机制采用时间衰减的方式,使用了自身定时消费的能力。首次在10秒后重试消费,如果消费成功则不再重试,如果消费失败则继续重试消费,第二次在30秒后重试消费。以此类推,每次重试的时间间隔都会加长,直到超出最大重试次数(默认为16次),则进入死信队列不再重试。
重试消费过程中的间隔时间使用了定时消息,重试的消息数据并非直接写入重试队列,而是先写入定时消息队列,再通过定时消息的功能转发到重试队列。
RocketMQ支持定时消息(也称延迟消息),延迟消息是指消息发送之后,等待指定的延迟时间后再进行消费。除了支持消息重试机制,延迟消息也适用于一些处理异步任务的场景,例如调用某个服务,调用结果需要异步在一分钟内返回,此时就可以发送一个延迟消息,延迟时间为1分钟,等1分钟后收到该消息去查询上次的调用结果是否返回。
RocketMQ不支持任意时间精确的延迟消息,仅支持1s、5s、10s、30s、1min、2min、3min、4min、5min、6min、7min、8min、9min、10min、20min、30min、1h、2h。
在实际业务场景中,业务应用在消费消息的过程中偶尔会出现一些异常的情况,例如程序发布导致的重启,或者网络突然出现问题,此时正在进行业务处理的消息可能消费完了,也可能业务逻辑执行到一半没有消费完,那么如何去识别这些情况呢?这就需要消息的ACK机制。
广播模式的消费进度保存在客户端本地,集群模式的消费进度保存在Broker上。集群模式中RocketMQ采用ACK机制确保消息一定被消费。在消息投递过程中,不是消息从Broker发送到Consumer就算消费成功了,需要Consumer明确给Broker返回消费成功状态才算。如果从Broker发送到Consumer后,已经完成了业务处理,但在给Broker返回消费成功状态之前,Consumer发生宕机或者断电、断网等情况,Broker未收到返回,则不会保存消费进度。 Consumer重启之后,消息会重新投递,此时也会出现重复消费的场景,这时消息的幂等性需要业务自行保证。
Broker集群部署时消息存储高可用的基本保障,最直接的表现是Broker出现单机故障或重启时,不会影响RocketMQ整体的服务能力。RocketMQ中Broker有四种不同的集群搭建方式:
单Master模式:单Master模式仅部署一台Broker机器,属于非集群模式,这种方式存在单点故障的风险,一旦Broker重启或者宕机,会导致整个服务不可用。不建议生产环境使用,仅可用于本地测试。
多Master模式:一个集群全部都是Master机器,没有Slave机器,属于不配置主从复制的场景,例如2个Master或者3个Master。也不建议生产环境使用,这种模式的优缺点如下:
优点:配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时,即使机器宕机不可用,由于RAID10磁盘非常可靠,消息也不会丢失,性能最高。
缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息的实时性会受到影响。整个缺点是致命的,消息实时性收到影响意味着一段时间内部分消费不可用,违背系统可用性原则。
异步复制的多Master多Slave模式:每个Master配置一个Slave,有多对Master-Slave,主从复制采用异步复制方式,主备有短暂的消息延迟(毫秒级),这种模式的优缺点如下:
优点:即使磁盘损坏,消息丢失非常少,且消息实时性不会受影响,同时Master宕机后,消费者仍然可以从Slave消费,而且此过程对应用透明,不需要人工干预,性能同多Master模式几乎一样。
缺点:在Master宕机且磁盘损坏的情况下可能会丢失少量消息。不过出现这种场景的概率很小,有风险但是很低。
同步复制的多Master多Slave模式:每个Master配置一个Slave,有多对Master-Slave,主从复制采用同步复制方式,即只有主备都写成功,才向应用返回成功。线上推荐使用异步刷盘+同步复制的多Master多Slave模式,这种模式的优缺点如下:
优点:数据与服务都无单点故障,在Master宕机的情况下,消息无延迟,服务可用性与数据可用性都非常高。
缺点:性能比异步复制模式略低(约10%),发送单个消息的RT会略高。