RocketMQ4.3.X笔记(8):可靠性场景

RocketMQ顺序消息与优先级
探讨RocketMQ中全局与部分顺序消息的概念及实现,分析消息重复问题的解决方案,讲解消息优先级处理策略,包括间接优先级处理及动态增减机器的方法。

顺序消息

顺序消息是指消息的消费顺序和产生顺序相同。顺序消息分为全局顺序消息和部分顺序消息,全局顺序消息指某个Topic下的所有消息都要保证顺序;部分顺序消息只要保证每一组消息被顺序消费即可,比如订单消息(订单的生成、付款、发货),只要保证同一个订单ID 的三个消息能按顺序消费即可。

全局顺序

  1. 默认是不保证顺序的。
  • 如创建一个Topic ,默认八个写队列,八个读队列。这时候一条消息可能被写入任意一个队列里;
  • 在数据的读取过程中,可能有多个Consumer ,每个Consumer 也可能启动多个线程并行处理,所以消息被哪个Consumer 消费,被消费的顺序和写人的顺序是否一致是不确定的
  1. 要保证全局顺序消息, 需要先把Topic 的读写队列数设置为一,然后Producer 和Consumer 的并发设置也要是一。简单来说,为了保证整个Topic的全局消息有序,只能消除所有的并发处理,各部分都设置成单线程处理。这时高并发、高吞吐量的功能完全用不上了

部分顺序

  1. 在发送端,要做到把同一业务ID 的消息发送到同一个MessageQueue;在消费过程中,要做到从同一个MessageQueue 读取的消息不被并发处理,这样才能达到部分有序
  2. 具体实现
  • 发送端使用MessageQueueSelector 类来控制把消息发往哪个Message Queue;
  • 消费端通过使用MessageListenerOrderly 类来解决单Message Queue 的消息被并发处理的问题
  1. MessageListenerOrderly 实现:为每个Consumer Queue 加个锁,消费每个消息前,需要先获得这个消息对应的ConsumerQueue 所对应的锁,这样保证了同一时间,同一个ConsumerQueue 的消息不被并发消费,但不同ConsumerQueue 的消息可以并发处理

消息重复问题

  1. RocketMQ 选择了确保一定投递,保证消息不丢失,但有可能造成消息重复。

  2. 消息重复一般情况下不会发生,但是如果消息量大,网络有波动,消息重复就是个大概率事件。比如Producer有个函数setRetryTimesWhenSendFailed,设置在同步方式下自动重试的次数,默认值是2 ,这样当第一次发送消息时,Broker 端接收到了消息但是没有正确返回发送成功的状态,就造成了消息重试

  3. 解决消息重复有两种方法:

  • 第一种方法是保证消费逻辑的幕等性(多次调用和一次调用效果相同);
  • 另一种方法是维护一个巳消费消息的记录,消费前查询这个消息是否被消费过。

消息优先级

RocketMQ 特点

  1. 先入先出的队列,不支持消息级别或者Topic 级别的优先级
  2. 业务中简单的优先级需求,可以通过间接的方式解决

间接的方式的优先级处理

  1. 一个 Topic 里有多种相似类型的消息,如 AA 、AB 、AC
  • 当AB 、AC 的消息量很大,但是处理速度很慢,那么会有堆积,这时少量的 AA 类型(优先级高)就在排在AB 、AC 后面等待
  • 解决方式:分拆到两个Topic 里
    • AA 类型的消息在一个单独的Topic,AB 、AC 类型的消息在另外一个Topic
    • 应用程序创建两个Consumer ,分别订阅不同的Topic
  1. 不同MessageQueue的优先级,固定 MessageQueue 的写入。
  • Producer 根据一定的规则,写入固定的 MessageQueue
  • DefaultMQPushConsumer 默认是采用循环的方式逐个读取一个Topic 的所有MessageQueue ,这样某个MessageQueue 消息数增多,等待时间增长,但不会造成其他MessageQueue等待时间增长
  1. 强优先级。
  • 有一个应用程序同时处理TypeA 、TypeB 、TypeC 三类消息:TypeA 处于第一优先级,要确保只要有TypeA 消息,必须优先处理; TypeB 处于第二优先级; TypeC 处于第三优先级。
  • 解决:自己编码实现优先级控制
    • 三类消息在一个Topic 里,可以使用PullConsumer ,自主控制Mes sag巳Queue 的遍历,以及消息的读取
    • 如果上述三类消息在三个Topic 下,需要启动三个Consumer , 实现逻辑控制三个Consumer 的消费

动态增减机器

动态增减NameServer

有四种方式可设置NameServer 的地址,按优先级由高到低依次介绍:

  1. 编码设置
  • broker 设置,需要在其配置文件中配置
namesrvAddr=name-server-ip1:port;name-server-ip2:port
  • producers 和 consumers 编码
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
consumer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");
  • mqadmin 命令行
sh mqadmin command-name -n name-server-ip1:port;name-server-ip2:port -X OTHER-OPTION
  • 自定义了命令行工具
DefaultMQAdminExt defaultMQAdminExt = new DefaultMQAdminExt("please_rename_unique_group_name");
defaultMQAdminExt.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");
  1. Java 启动参数设置
# 对应的option
rocketmq.namesrv.addr
  1. Linux 环境变量设置
# 环境变量
NAMESRV_ADDR
  1. 通过HTTP 服务来设置(动态设置)
  • 当上述方法都没有使用,程序会向一个HTTP地址发送请求来获取NameServer地址
  • 通过Java option rocketmq.namesrv.domain 参数来覆盖jmenv.tbsite.net
  • 通过Java option rocketmq.namesrv.domain.subgroup 参数来覆盖nsaddr
# 默认地址-淘宝的测试地址
http://jmenv.tbsite.net:8080/rocketmq/nsaddr

通过HTTP 服务方式看似繁琐,但它是唯一支持动态增加NameServer ,无须重启其他组件的方式。使用这种方式后其他组件会每隔2 分钟请求一次该URL ,获取最新的Na meServer 地

动态、增减Broker

动态新增 Broker
  1. 只增加Broker 不会对原有的Topic 产生影响,原来创建好的Topic 中数据的读写依然在原来的那些Broker 上进行
  2. 负载处理
  • 把新建的Topic 指定到新的Broker 机器上,均衡利用资源
  • 通过updateTopic 命令更改现有的Topic 配置,在新加的Broker 上创建新的队列
# TestTopic 是现有Topic名称 ,新增Broker 地址是192.168.0.1:10911
# 结果:在新增的Broker上,为TestTopic 新创建了读写队列。
sh ./bin/mqadmin updateTopic -b 192.168.0.1:10911 -t TestTopic -n 192.168.0.100:9876 
动态减少 Broker
  1. 当一个Topic 只有一个MasterBroker ,停掉这个Broker 后,消息的发送肯定会受到影响,需要在停止这个Broker 前,停止发送消息。
  2. 当某个Topic 有多个Master Broker ,停了其中一个,消息丢失情况如下:
  • 如果使用同步方式send ( msg )发送,在DefaultMQProducer 内部有个自动重试逻辑,其中一个Broker 停了,会自动向另一个Broker 发消息,不会发生丢消息现象。(异步也可以,使用异步重试)
  • 用sendOneWay 方式,会丢失切换过程中的消息

各种故障对消息的影响

建议设置

  1. 多Master ,每个Master 带有Slave;
  2. 主从之间设置成 SYNC_MASTER;
  3. Producer 用同步方式写;
  4. 刷盘策略设置成SYNC FLUSH

就可以消除单点依赖,即使某台机器出现极端故障也不会丢消息。

参考

  1. Apache RocketMQ 官网
  2. Best Practice For NameServer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值