rocketMq

注:异常被捕获者不会进入重试

接收消息通道和发送消息通道名不可以重复。即使destination一样

 

接收消息的时候报如下错误。 Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers

1. 按照消费端的`GroupName`来分组重试队列,如果消费端消费失败,消息将被发往重试队列中,比如图中的`%RETRY%ConsumerGroupA`。
2. 按照消费端的`GroupName`来分组死信队列,如果消费端消费失败,并重试指定次数后,仍然失败,则发往死信队列,比如图中的`%DLQ%ConsumerGroupA`。

选型

https://blog.csdn.net/QGhurt/article/details/114630705

主要用途:提升性能(异步)、系统解耦、流量消峰

RocketMQ: 1、开发语言: java开发 2、性能、吞吐量: 吞吐量高,QPS十万级、性能毫秒级、支持集群部署 3、功能: 支持各种高级功能,比如说 延迟消息、事务消息、消息回溯、死信队列、消息积压等等 4、缺点: 官方文档相对简单可能是RocketMQ目前唯一的缺点 5、应用场景: 适当丢失数据没有关系、吞吐量要求高、不需要太多的高级功能的场景,比如大数据场景。 https://blog.csdn.net/weixin_36279318/article/details/88927326

rocketMq

选型

 

 

主要用途:提升性能(异步)、系统解耦、流量消峰

 

专业术语

 

 

 

Queue 一个topic下,我们可以设置多个queue(消息队列)。当我们发送消息时,需要要指定该消息的topic。RocketMQ会轮询该topic下的所有队列,将消息发送出去。

消息消费状态(TrackType)

  • CONSUMED 代表该消息已经被消费

  • NOT_CONSUME_YET 还没被消费

  • UNKNOW_EXCEPTION 报错了,可以看日志,一般报错内容会紧跟其后,具体很容易排查出来

  • NOT_ONLINE 代表该Consumer并没有运行

  • CONSUMED_BUT_FILTERED 消息已经被投递且被过滤(比如,发布端发布消息topicA,tagA,订阅端订阅topicA,tagB, tagA的消息就被集群消费的消费者忽略掉了;)

  • UNKNOWN 无消费分组 无消费者

  • PULL

RocketMQ 整体架构设计

整体的架构设计主要分为四大部分,分别是:Producer、Consumer、Broker、NameServer。

 

    • Producer:就是消息生产者,可以集群部署。它会先和 NameServer 集群中的随机一台建立长连接,得知当前要发送的 Topic 存在哪台 Broker Master上,然后再与其建立长连接,支持多种负载平衡模式发送消息。

    • Consumer:消息消费者,也可以集群部署。它也会先和 NameServer 集群中的随机一台建立长连接,得知当前要消息的 Topic 存在哪台 Broker Master、Slave上,然后它们建立长连接,支持集群消费和广播消费消息。

    • Broker:主要负责消息的存储、查询消费,支持主从部署,一个 Master 可以对应多个 Slave,Master 支持读写,Slave 只支持读。Broker 会向集群中的每一台 NameServer 注册自己的路由信息。

    • NameServer:是一个很简单的 Topic 路由注册中心,支持 Broker 的动态注册和发现,保存 Topic 和 Borker 之间的关系。通常也是集群部署,但是各 NameServer 之间不会互相通信, 各 NameServer 都有完整的路由信息,即无状态。

 

NameServer

它的特点就是轻量级,无状态。角色类似于 Zookeeper 的情况,从上面描述知道其主要的两个功能就是:Broker 管理、路由信息管理。

总体而言比较简单,我再贴一些字段,让大家有更直观的印象知道它存储了些什么。

 

Producer

Producer 无非就是消息生产者,那首先它得知道消息要发往哪个 Broker ,于是每 30s 会从某台 NameServer 获取 Topic 和 Broker 的映射关系存在本地内存中,如果发现新的 Broker 就会和其建立长连接,每 30s 会发送心跳至 Broker 维护连接。

并且会轮询当前可以发送的 Broker 来发送消息,达到负载均衡的目的,在同步发送情况下如果发送失败会默认重投两次(retryTimesWhenSendFailed = 2),并且不会选择上次失败的 broker,会向其他 broker 投递。

异步发送失败的情况下也会重试,默认也是两次 (retryTimesWhenSendAsyncFailed = 2),但是仅在同一个 Broker 上重试。

Producer 启动流程

然后我们再来看看 Producer 的启动流程看看都干了些啥。

 

Producer 发消息流程

我们再来看看发消息的流程,大致也不是很复杂,无非就是找到要发送消息的 Topic 在哪个 Broker 上,然后发送消息。

 

现在就知道 TBW102 是啥用的,就是接受自动创建主题的 Broker 启动会把这个默认主题登记到 NameServer,这样当 Producer 发送新 Topic 的消息时候就得知哪个 Broker 可以自动创建主题,然后发往那个 Broker。

而 Broker 接受到这个消息的时候发现没找到对应的主题,但是它接受创建新主题,这样就会创建对应的 Topic 路由信息。

自动创建主题的弊端

自动创建主题那么有可能该主题的消息都只会发往一台 Broker,起不到负载均衡的作用。

因为创建新 Topic 的请求到达 Broker 之后,Broker 创建对应的路由信息,但是心跳是每 30s 发送一次,所以说 NameServer 最长需要 30s 才能得知这个新 Topic 的路由信息。

假设此时发送方还在连续快速的发送消息,那 NameServer 上其实还没有关于这个 Topic 的路由信息,所以有机会让别的允许自动创建的 Broker 也创建对应的 Topic 路由信息,这样集群里的 Broker 就能接受这个 Topic 的信息,达到负载均衡的目的,但也有个别 Broker 可能,没收到。

如果发送方这一次发了之后 30s 内一个都不发,之前的那个 Broker 随着心跳把这个路由信息更新到 NameServer 了,那么之后发送该 Topic 消息的 Producer 从 NameServer 只能得知该 Topic 消息只能发往之前的那台 Broker ,这就不均衡了,如果这个新主题消息很多,那台 Broker 负载就很高了。

所以不建议线上开启允许自动创建主题,即 autoCreateTopicEnable 参数。

发送消息故障延迟机制

有一个参数是 sendLatencyFaultEnable,默认不开启。这个参数的作用是对于之前发送超时的 Broker 进行一段时间的退避。

发送消息会记录此时发送消息的时间,如果超过一定时间,那么此 Broker 就在一段时间内不允许发送。

 

比如发送时间超过 15000ms 则在 600000 ms 内无法向该 Broker 发送消息。

这个机制其实很关键,发送超时大概率表明此 Broker 负载高,所以先避让一会儿,让它缓一缓,这也是实现消息发送高可用的关键。

 

小结一下

Producer 每 30s 会向 NameSrv 拉取路由信息更新本地路由表,有新的 Broker 就和其建立长连接,每隔 30s 发送心跳给 Broker

不要在生产环境开启 autoCreateTopicEnable。

Producer 会通过重试和延迟机制提升消息发送的高可用。

 

Broker

Broker

Broker 就比较复杂一些了,但是非常重要。大致分为以下五大模块,我们来看一下官网的图。

 

  • Remoting 远程模块,处理客户请求。

  • Client Manager 管理客户端,维护订阅的主题。

  • Store Service 提供消息存储查询服务。

  • HA Serivce,主从同步高可用。

  • Index Serivce,通过指定key 建立索引,便于查询。

 

Broker 的存储

RocketMQ 存储用的是本地文件存储系统,效率高也可靠。

主要涉及到三种类型的文件,分别是 CommitLog、ConsumeQueue、IndexFile。

 

Consumer

消费有两种模式,分别是广播模式和集群模式。

广播模式:一个分组下的每个消费者都会消费完整的Topic 消息。

集群模式:一个分组下的消费者瓜分消费Topic 消息。

一般我们用的都是集群模式。

而消费者消费消息又分为推和拉模式,详细看我这篇文章消息队列推拉模式,分别从源码级别分析了 RokcetMQ 和 Kafka 的消息推拉,以及推拉模式的优缺点。

Consumer 端的负载均衡机制

Consumer 会定期的获取 Topic 下的队列数,然后再去查找订阅了该 Topic 的同一消费组的所有消费者信息,默认的分配策略是类似分页排序分配。

将队列排好序,然后消费者排好序,比如队列有 9 个,消费者有 3 个,那消费者-1 消费队列 0、1、2 的消息,消费者-2 消费队列 3、4、5,以此类推。

所以如果负载太大,那么就加队列,加消费者,通过负载均衡机制就可以感知到重平衡,均匀负载。

 

Consumer 消息消费的重试

难免会遇到消息消费失败的情况,所以需要提供消费失败的重试,而一般的消费失败要么就是消息结构有误,要么就是一些暂时无法处理的状态,所以立即重试不太合适。

RocketMQ 会给每个消费组都设置一个重试队列,Topic 是 %RETRY%+consumerGroup,并且设定了很多重试级别来延迟重试的时间。

为了利用 RocketMQ 的延时队列功能,重试的消息会先保存在 Topic 名称为“SCHEDULE_TOPIC_XXXX”的延迟队列,在消息的扩展字段里面会存储原来所属的 Topic 信息。

delay 一段时间后再恢复到重试队列中,然后 Consumer 就会消费这个重试队列主题,得到之前的消息。

如果超过一定的重试次数都消费失败,则会移入到死信队列,即 Topic %DLQ%" + ConsumerGroup 中,存储死信队列即认为消费成功,因为实在没辙了,暂时放过。

然后我们可以通过人工来处理死信队列的这些消息。

 

消息的全局顺序和局部顺序

全局顺序就是消除一切并发,一个 Topic 一个队列,Producer 和 Consuemr 的并发都为一。

局部顺序其实就是指某个队列顺序,多队列之间还是能并行的。

可以通过 MessageQueueSelector 指定 Producer 某个业务只发这一个队列,然后 Comsuer 通过MessageListenerOrderly 接受消息,其实就是加锁消费。

在 Broker 会有一个 mqLockTable ,顺序消息在创建拉取消息任务的时候需要在 Broker 锁定该消息队列,之后加锁成功的才能消费。

而严格的顺序消息其实很难,假设现在都好好的,如果有个 Broker 宕机了,然后发生了重平衡,队列对应的消费者实例就变了,就会有可能会出现乱序的情况,如果要保持严格顺序,那此时就只能让整个集群不可用了。

 

 

RocketMQ 的最佳实践

这些最佳实践部分参考自官网。

Tags**的使用**

建议一个应用一个 Topic,利用 tages 来标记不同业务,因为 tages 设置比较灵活,且一个应用一个 Topic 很清晰,能直观的辨别。

Keys**的使用**

如果有消息业务上的唯一标识,请填写到 keys 字段中,方便日后的定位查找。

 

RocketMQ Consumer Properties

下面的这些配置是以 spring.cloud.stream.rocketmq.bindings..consumer. 为前缀的 RocketMQ Consumer 相关的配置。

  • enable

    是否启用 Consumer。默认值: true.

  • tags

    Consumer 基于 TAGS 订阅,多个 tag 以 || 分割。默认值: empty.

  • sql

    Consumer 基于 SQL 订阅。默认值: empty.

  • broadcasting

    Consumer 是否是广播消费模式。如果想让所有的订阅者都能接收到消息,可以使用广播模式。默认值: false.

  • orderly

    Consumer 是否同步消费消息模式。默认值: false.

  • delayLevelWhenNextConsume

    异步消费消息模式下消费失败重试策略:-1,不重复,直接放入死信队列0,broker 控制重试策略>0,client 控制重试策略默认值: 0.

  • suspendCurrentQueueTimeMillis

    同步消费消息模式下消费失败后再次消费的时间间隔。默认值: 1000.

RocketMQ Provider Properties

下面的这些配置是以 spring.cloud.stream.rocketmq.bindings..producer. 为前缀的 RocketMQ Producer 相关的配置。

  • enable

    是否启用 Producer。默认值: true.

  • group

    Producer group name。默认值: empty.

  • maxMessageSize

    消息发送的最大字节数。默认值: 8249344.

  • transactional

    是否发送事务消息。默认值: false.

  • sync

    是否使用同步得方式发送消息。默认值: false.

  • vipChannelEnabled

    是否在 Vip Channel 上发送消息。默认值: true.

  • sendMessageTimeout

    发送消息的超时时间(毫秒)。默认值: 3000.

  • compressMessageBodyThreshold

    消息体压缩阀值(当消息体超过 4k 的时候会被压缩)。默认值: 4096.

  • retryTimesWhenSendFailed

    在同步发送消息的模式下,消息发送失败的重试次数。默认值: 2.

  • retryTimesWhenSendAsyncFailed

    在异步发送消息的模式下,消息发送失败的重试次数。默认值: 2.

  • retryNextServer

    消息发送失败的情况下是否重试其它的 broker。默认值: false.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A-ezra

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值