一、RocketMQ总体架构|参与者如何通信的?

RocketMQ架构详解
本文深入解析RocketMQ的架构设计,包括NameServer集群、Broker集群、生产者与消费者的工作原理及通信机制。阐述了RocketMQ如何确保消息的高可用性和可靠性,尤其是在broker宕机情况下的处理策略。

RocketMQ总体架构

1.各参与者是如何通信的?

  • 一、nameServer集群:
    • 本身的高可用可通过部署多台NameServer服务器来实现,但彼此间互不通信,单台nameserver挂掉,不影响其他nameserver;NameServer服务器之间在某一时刻的数据并不完全相同,但保证多台NameServer的最终一致性;NameServe集群可以理解为无状态的。
    • nameserver不会有频繁的读写,所以性能开销非常小,稳定性很高
  • 二、broker集群:
    • 1.@nameserv关系:
      • 连接:每一台borker会与所有的nameserver保持长连接, 因为每台broker需要向所有的nameserv汇报路由信息
      • 心跳:
        • 心跳间隔:每隔30秒(此时间无法更改)向所有nameserver发送心跳,心跳包含了自身的topic配置信息。
        • 心跳超时:nameserver每隔10秒钟(此时间无法更改),扫描所有还存活的broker连接,若某个连接2分钟内(当前时间与最后更新时间差值超过2分钟,此时间无法更改)没有发送心跳数据,则断开连接。
      • 断开:
        • 时机:broker挂掉;心跳超时导致nameserver主动关闭连接
        • 动作:一旦连接断开,nameserver会立即感知,更新topc与队列的对应关系,但不会通知生产者和消费者
    • 2.Broker集群组成:
      • 每个broker集群有统一的名字,即brokerClusterName,默认是DefaultCluster。一个集群下有多个master,每个master下有多个slave。master和slave算是一组,拥有相同的brokerName, master的brokerId是0,而slave则是大于0。master和slave之间可以进行同步复制或者是异步复制。
    • 3.可用性
      • 一旦某个broker宕机,则该broker上的消息读写都会受到影响。所以rocketmq提供了master/slave的结构,salve定时从master同步数据,如果master宕机,则slave提供消费服务,但是不能写入消息。
      • 一旦某个broker master宕机,生产者和消费者多久才能发现?
        • 受限于Rocketmq的网络连接机制,默认情况下最多需要30秒,因为消费者每隔30秒从nameserver获取所有topic的最新队列情况,这意味着某个broker如果宕机,客户端最多要30秒才能感知。在此期间,消费者会切换到salve上读取消息,若此时消费者消费消息时发生异常,又会怎样?详见https://cloud.tencent.com/developer/news/158048;生产者则通过高可用的的策略解决broker的宕机情况;
      • master恢复恢复后,消息能否恢复。
        • 消费者得到master宕机通知后,转向slave消费,但是slave不能保证master的消息100%都同步过来了,因此会有少量的消息丢失。但是消息最终不会丢的,一旦master恢复,未同步过去的消息会被消费掉。
    • 4.消息清理
      • 文件保留时长
        •  默认72小时,由broker配置参数fileReservedTime决定
      • 清理时机
        • 默认每天凌晨4点,由broker配置参数deleteWhen决定;或者磁盘空间达到阈值
    • 不同broker集群建立相同的topic而言是没问题的。但是如果是不同集群间的brokername有一致的则会有很大的问题。
  • 三、生产者:
    • 1.@nameserv关系
      • 连接:某一时刻只会连接一台namerServer,拉取主题的配置信息;
      • 轮询时间:默认情况下,生产者每隔30秒从nameserver获取所有topic的最新队列情况,这意味着某个broker如果宕机,生产者最多要30秒才能感知,在此期间,发往该broker的消息发送失败。该时间由DefaultMQProducer的pollNameServerInteval参数决定,可手动配置。
      • 心跳:与namerServ没有心跳
    • 2.@Broker关系
      • 连接:生产者与消费服务器(Broker)之间的(所有)Master保持长连接。因为生产者发送消息时,要轮询所有Master上的队列。
      • 心跳:
        • 超时:broker每隔10秒钟(此时间无法更改),扫描所有还存活的连接,若某个连接2分钟内(当前时间与最后更新时间差值超过2分钟,此时间无法更改)没有发送心跳数据,则关闭连接。
        • 间隔:默认情况下,生产者每隔30秒向所有broker发送心跳,该时间由DefaultMQProducer的heartbeatBrokerInterval参数决定,可手动配置。
      • 连接断开:移除broker上的生产者信息
    • 3.负载均衡:每个生产者向broker的所有队列轮询发送消息
  • 四、消费者:
    • 1.@namerserv关系
      • 连接:同一时间与NameServer集群中一台建立长连
      • 接轮询时间:默认情况下,消费者每隔30秒从nameserver获取所有topic的最新队列情况,这意味着某个broker如果宕机,客户端最多要30秒才能感知。该时间由DefaultMQPushConsumer的pollNameServerInteval参数决定,可手动配置
      • 心跳:与nameserver没有心跳
    • 2.@broker关系
      • 连接:单个消费者与所有Broker建立长连接,因为拉取消息可以从主服务器,也可以从服务上拉取。
      • 心跳:
        • 间隔:默认情况下,消费者每隔30秒向所有broker发送心跳,该时间由DefaultMQPushConsumer的heartbeatBrokerInterval参数决定,可手动配置
        • 超时:broker每隔10秒钟(此时间无法更改),扫描所有还存活的连接,若某个连接2分钟内(当前时间与最后更新时间差值超过2分钟,此时间无法更改)没有发送心跳数据,则关闭连接,并向该消费者分组的所有消费者发出通知,分组内消费者重新分配队列继续消费。
      • 断开:
        • 时机:消费者挂掉;心跳超时导致broker主动关闭连接
        • 动作:一旦连接断开,broker会立即感知到,并向该消费者分组的所有消费者发出通知,分组内消费者重新分配队列继续消费

2.问题

1.当某一个broker发生宕机,namerServer的剔除是120s,有延迟,那么作为客户端的生产者or消费者,是如何保证消息发送or消费的可靠性的?详见生产者 以及 消费者@NamserServer

2.消费者根据队列分配算法,得到本消费者对应的队列。当该主题的多个消费者动态增加或减少时,消费者的队列负载是没30s一次,不能达到实时性,那消费者是如何实时重新分配队列的呢?见消费者的负载均衡;见RocketMQ消息消费总览-问题

3. 断掉broker时,nameServer就感知到了,是不是与nameServer和broker的长连接断掉有关?tcp中断时,会被handler的监听到NettyConnectManageHandler#close,然后调用链:NettyRemotingAbstract#putNettyEvent->NettyEventExecutor#putNettyEvent->NettyEventExecutor#run->BrokerHousekeepingService#onChannelClose->RouteInfoManager#onChannelDestroy

4.生产者分组以及消费者分组,作用?类似jmq的appname。

5. nameserv无法像zk那样实时感知到生产者、消费者、broker的宕机,设计上由客户端来解决

RocketMQ 单条消息的最大字符数(或字节数)取决于其消息体大小的限制,具体规则如下: ### 核心限制参数 1. **默认配置**: - **单条消息最大大小**:4MB(`maxMessageSize=4×1024×1024`字节) - 适用于 RocketMQ 4.x 及 5.x 版本(生产环境推荐值) 2. **关键配置项**: ```properties # broker.conf 配置文件中的参数 maxMessageSize=4194304 # 单位:字节(4MB) ``` - 修改后需重启 Broker 生效 ### 字符数换算规则 1. **UTF-8 编码下**: - 英文字符:1 字节/字符 - 中文字符:3 字节/字符 - **计算示例**: ```text 4MB = 4×1024×1024 = 4,194,304 字节 纯中文消息:最多约 1,398,101 个字符(4,194,304 ÷ 3) 混合内容:实际字符数需根据编码具体计算 ``` 2. **特殊场景**: - 若消息包含**大附件**(如图片、PDF),建议通过以下方式处理: - 使用 RocketMQ 的**消息轨迹**功能追踪大文件 - 将文件存储至 OSS/NAS,消息体仅传递文件 URL ### 版本差异说明 | RocketMQ 版本 | 默认 maxMessageSize | 备注 | |----------------|----------------------|------| | 4.x | 4MB | 稳定版默认值 | | 5.x | 4MB(可配置至 256MB)| 需修改 `broker.conf` 中的 `maxMessageSize` | | 阿里云版 | 64KB~6MB(根据套餐) | 云服务有额外限制 | ### 性能影响建议 1. **大消息优化**: - 超过 1MB 的消息建议拆分为多条 - 使用**事务消息**保证拆分后的原子性 2. **监控指标**: - 通过 `RocketMQ-Console` 监控 `MessageSize` 指标 - 超过 2MB 的消息会触发 Broker 日志警告 ### 代码示例(发送大消息) ```java // 生产者配置(需确保 Broker 的 maxMessageSize ≥ 消息大小) DefaultMQProducer producer = new DefaultMQProducer("producer_group"); producer.setNamesrvAddr("localhost:9876"); producer.start(); // 构造大消息(需注意实际大小限制) Message msg = new Message( "TopicTest", "TagA", "Key1", ("超大消息内容..." + "a".repeat(4_000_000)).getBytes(StandardCharsets.UTF_8) ); // 发送前检查大小(推荐) if (msg.getBody().length > 4_194_304) { throw new IllegalArgumentException("消息超过4MB限制"); } producer.send(msg); ``` ### 常见问题解决方案 1. **消息过大报错**: - 错误日志:`MESSAGE_SIZE_EXCEEDED` - 解决方案: - 拆分消息为多条 - 修改 Broker 配置(需评估网络带宽影响) 2. **生产环境建议**: - 保持默认 4MB 限制(避免影响 Broker 吞吐量) - 大文件通过 FTP/OSS 传输,消息体仅传递文件标识
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值