Skip to content

[RIP-79] Route Change Notification - #9549

Merged
RongtongJin merged 22 commits into
apache:feature-reverse-route-updatefrom
saz97:route_change_notification
Oct 28, 2025
Merged

[RIP-79] Route Change Notification#9549
RongtongJin merged 22 commits into
apache:feature-reverse-route-updatefrom
saz97:route_change_notification

Conversation

@saz97

@saz97 saz97 commented Jul 15, 2025

Copy link
Copy Markdown

The ​​route update mechanism in RocketMQ​​ currently relies on a periodic polling approach by Clients and Proxy. This passive update mechanism causes some issues during route events (e.g., master/slave switch, Broker shutdown):

  1. Clients persistently ​​use outdated routing information​​, leading to write failures when sending requests to deactivated Brokers
  2. Connections to destroyed IP addresses result in ​​complete communication breakdown​​
  3. New resources cannot be promptly utilized for ​​load balancing​​
    Fundamentally, operations during polling intervals rely on ​​incorrect routing decisions​​, compromising service high availability.

To address this, I would like to start an email thread to discuss the ​​RIP-79 Route Change Notification​​, reconstructing the route synchronization mechanism to achieve ​​event-driven route state synchronization​​.

The redesigned architecture can resolves ​​untimely route updates​​: Clients no longer connect to invalid nodes, ​​eliminating service interruptions​​ during master/slave switches, and new resources can be ​​immediately discovered and leveraged​​. Additionally, ​​redundant query pressure​​ on NameServer is reduced through merged update requests and a lazy update policy.

Relevant work is already in progress. Proposal documentation is available here:
https://docs.google.com/document/d/1iMQQ0wDO4dULGpjsKyq6kCbcsUL0JjNcii-KbM90a18/edit?usp=sharing

saz97 added 3 commits July 15, 2025 10:23
1. 创建路由事件专用系统Topic
   - 新增TopicValidator.RMQ_ROUTE_EVENT_TOPIC定义
   - 加入系统主题集合(SYSTEM_TOPIC_SET)

2. 实现主备切换事件发送
   - 在changeToMaster()中触发发送操作
1. broker端通知机制
   - 当broker切换为slave时,构造ROUTE_EVENT(299)事件请求
   - 通过remotingServer获取所有活跃连接(activeChannels)
   - 向所有活跃客户端连接发送一次性通知

2. Client路由更新处理
   - ClientRemotingProcessor处理ROUTE_EVENT请求
   - 触发客户端立即更新路由信息(updateTopicRouteInfoFromNameServer)

3. RemotingServer新增
   - 新增getActiveChannels()
   - NettyRemotingServer实现活跃连接维护:
     * 新增activeChannels集合
     * channel激活时自动添加
     * channel关闭时自动移除
1. 新增RouteEventSubscriber订阅路由事件
-创建轻量级消费者监听系统Topic

2.实现缓存失效标记机制
-标记相关Topic缓存为dirtyTopics
-dirtyTopics加入pendingTopics队列

3.路由异步更新机制:
-200ms窗口处理pendingTopics
-使用现有cacheRefreshExecutor线程池并行更新
-失败重试
-保留原有定时刷新作为兜底策略
@ShannonDing
ShannonDing requested a review from RongtongJin July 15, 2025 03:42
@codecov-commenter

codecov-commenter commented Jul 15, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 47.82609% with 108 lines in your changes missing coverage. Please review.
✅ Project coverage is 48.28%. Comparing base (bea086f) to head (e224fdf).
⚠️ Report is 1 commits behind head on feature-reverse-route-update.

Files with missing lines Patch % Lines
...ketmq/proxy/service/route/RouteChangeNotifier.java 41.86% 46 Missing and 4 partials ⚠️
...pache/rocketmq/broker/route/RouteEventService.java 53.65% 31 Missing and 7 partials ⚠️
...ocketmq/proxy/service/route/TopicRouteService.java 12.50% 7 Missing ⚠️
...a/org/apache/rocketmq/broker/BrokerController.java 50.00% 1 Missing and 2 partials ⚠️
...ache/rocketmq/broker/topic/TopicConfigManager.java 66.66% 2 Missing and 1 partial ⚠️
.../java/org/apache/rocketmq/common/BrokerConfig.java 25.00% 3 Missing ⚠️
.../org/apache/rocketmq/proxy/config/ProxyConfig.java 50.00% 2 Missing ⚠️
...che/rocketmq/broker/route/RouteEventConstants.java 0.00% 1 Missing ⚠️
...ache/rocketmq/container/InnerBrokerController.java 50.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@                        Coverage Diff                         @@
##             feature-reverse-route-update    #9549      +/-   ##
==================================================================
- Coverage                           48.41%   48.28%   -0.13%     
+ Complexity                          12255    12242      -13     
==================================================================
  Files                                1314     1318       +4     
  Lines                               93668    93875     +207     
  Branches                            12011    12040      +29     
==================================================================
- Hits                                45347    45331      -16     
- Misses                              42733    42917     +184     
- Partials                             5588     5627      +39     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@yx9o

yx9o commented Jul 16, 2025

Copy link
Copy Markdown
Contributor

Hi @saz97 , is this all submitted? I understand that when the master switches, the client will be notified to re-acquire the route. Will the client's method of obtaining the route regularly be retained? I think the server should generally rely on the client as little as possible.

@saz97

saz97 commented Jul 16, 2025

Copy link
Copy Markdown
Author

Hi @saz97 , is this all submitted? I understand that when the master switches, the client will be notified to re-acquire the route. Will the client's method of obtaining the route regularly be retained? I think the server should generally rely on the client as little as possible.

The PR hasn't been fully submitted yet—the current commits are just a demo.
Regarding whether to retain the client's periodic route-pulling mechanism, this is open for discussion. After all, scheduled pulling and server-side notifications aren't mutually exclusive. Keeping it as a fallback mechanism shouldn't be an issue.

@yx9o

yx9o commented Jul 16, 2025

Copy link
Copy Markdown
Contributor

Hi @saz97 , is this all submitted? I understand that when the master switches, the client will be notified to re-acquire the route. Will the client's method of obtaining the route regularly be retained? I think the server should generally rely on the client as little as possible.

The PR hasn't been fully submitted yet—the current commits are just a demo. Regarding whether to retain the client's periodic route-pulling mechanism, this is open for discussion. After all, scheduled pulling and server-side notifications aren't mutually exclusive. Keeping it as a fallback mechanism shouldn't be an issue.

If the scheduled pull is not retained, this method strongly relies on the client, and the client and server must be upgraded together. In fact, in actual production applications, many client and server versions are inconsistent, because the cost of upgrading the client is very high. Is compatibility considered in this way?

@saz97

saz97 commented Jul 16, 2025

Copy link
Copy Markdown
Author

If the scheduled pull is not retained, this method strongly relies on the client, and the client and server must be upgraded together. In fact, in actual production applications, many client and server versions are inconsistent, because the cost of upgrading the client is very high. Is compatibility considered in this way?

​​Thank you for your valuable insights and the practical perspective from production environments!​
I’ll ​​retain the client’s periodic route-pulling mechanism​​ as a ​​fallback​​, ensuring compatibility across different client/server versions.

1. Broker事件发布机制:
   - 在BrokerController添加`publishRouteEvent`方法
   - Broker启动/关闭/时发送事件到`RMQ_ROUTE_EVENT_TOPIC`
2. Proxy事件订阅机制:
   - 创建RouteEventSubscriber消费路由事件
   - 实现事件处理流水线:
     * 订阅系统Topic `RMQ_ROUTE_EVENT_TOPIC`
     * 提取受影响Topic列表
     * 调用markCacheDirty标记脏数据
   - 向namesrv获取新路由

测试了单副本Broker的IP变更场景,Proxy端能及时感知,并更新路由。
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
​​Broker 层事件发布重构​​
1. 移除原有 publishRouteEvent()方法及其硬编码逻辑。
-引入新的 RouteEventService类,专门负责将 Broker 的生命周期事件(暂时是启动和关闭)发布到系统Topic (RMQ_ROUTE_EVENT_TOPIC)。
-用RouteEventType枚举替代原有的。

2.修改 BrokerController:
-在启动 (start()) 和关闭 (shutdown()) 流程中调用 RouteEventService发布相应事件。

Proxy 层事件消费与缓存刷新重构​​
1.移除 ClusterTopicRouteService中直接启动和关闭 RouteEventSubscriber的逻辑(该职责移至基类)。

2.重构 TopicRouteService:
-引入 RouteCacheRefresher组件,专门负责管理代理层的路由缓存失效与刷新策略。
-维护broker-topic的映射,用于确定affectedTopic

3.将路由功能收敛到工具类
-RouteEventSubscriber​​仅负责​​订阅 Broker 发布的事件,提取 affectedTopics并通知 RouteCacheRefresher将这些 Topic 标记为“脏数据”。
-RouteCacheRefresher​​负责​​维护脏数据队列、执行异步批量刷新任务(使用专用线程池 cacheRefreshExecutor)、处理刷新超时(超时后重回队列重试)以及更新缓存状态。
-删除原有的 batchRefreshRoutes, refreshSingleRoute以及基于 dirtyTopics/pendingTopics/lazyUpdateExecutor的刷新逻辑,全部由 RouteCacheRefresher接管。

4. 简化 ClusterTopicRouteService实现,仅保留与集群路由获取相关的基类逻辑。

5.​​移除冗余功能​​
-删除 ReplicasManager中试图直接通知客户端连接关于主从切换的逻辑 (buildNotify, activeChannels通知等),其功能已被事件机制替代。
-删除client修改,将修改集中于Proxy修改
saz97 added 2 commits August 13, 2025 14:50
1.在Broker端,当Topic配置发生变化:
-通过RouteEventService发布TOPIC_CHANGE事件
-事件携带受影响的主题名称(AFFECTED_TOPIC)

2.Proxy端重构逻辑:
-增强维护brokerToTopics映射关系

3.增强时效性检查:
-消息携带时间戳字段
-暂定延迟超过1分钟的事件将被丢弃,避免处理陈旧事件造成的无效刷新

4.完善路由刷新机制:
-刷新前检查topicCache是否存在对应主题
-无缓存主题时跳过刷新操作
@saz97
saz97 force-pushed the route_change_notification branch from bbd9807 to 7efc56e Compare August 21, 2025 01:12
1. 移除错误的checkRefreshStatus
   - 原 checkRefreshStatus 方法通过 topicCache.getIfPresent 检测刷新完成不可靠
   - 该方法错误地将缓存存在视为刷新完成,导致状态误判

2. 重构状态确认
   - 新增 markCompleted/markRetry 方法在 reload 回调中精确更新状态
   - 在 processDirtyTopics 中增加超时检测,避免无限重试

3. 优化错误处理流程
   - 刷新失败时通过 markRetry 重新加入队列
   - 超时topic直接标记完成并报出错误日志,避免阻塞
@saz97
saz97 force-pushed the route_change_notification branch from 7efc56e to 8139467 Compare August 21, 2025 01:16

@RongtongJin RongtongJin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议增加一些单测

Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
saz97 and others added 3 commits August 26, 2025 14:16
本次提交在Broker和Proxy模块为新增的路由事件通知功能引入了可配置的开关。

1.Broker端修改:
- 在 BrokerConfig 中新增 routeEventServiceEnable,用于控制RouteEventService 的初始化
- 修改 BrokerController,使其根据配置值有条件地初始化RouteEventService
- 在流程中增加空指针检查

2.Proxy端修改:
- 在ProxyConfig中新增 brokerRouteEventServiceEnable
- 修改 TopicRouteService,使其根据配置初始化 RouteEventSubscriber 和 RouteCacheRefresher

测试新增:
- 新增 RouteEventServiceTest 用于测试Broker端的事件发布
- 新增 RouteEventSubscriberTest 用于测试Proxy端的事件处理
- 新增 RouteCacheRefresherTest 用于测试Proxy端的缓存刷新机制
Comment thread common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java Outdated
Comment thread common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java Outdated
Comment thread proxy/src/main/java/org/apache/rocketmq/proxy/config/ProxyConfig.java Outdated
Comment thread proxy/src/main/java/org/apache/rocketmq/proxy/config/ProxyConfig.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java Outdated
1. 修改Broker端触发逻辑
   - 移除putTopicConfig和removeTopicConfig方法的事件触发
   - 在Topic创建/删除的方法中触发

2. 修改开关命名
   - 将routeEventServiceEnable更名为enableRouteChangeNotification

3. 调整开关逻辑
   - 事件发布时检查enableRouteChangeNotification开关

4. 删除Proxy端重试逻辑
   - 删除RouteCacheRefresher中的markRetry方法
   - 失败时不再重试,依赖基础定时更新
@saz97
saz97 force-pushed the route_change_notification branch from fc9a83f to 2d2c1fb Compare September 10, 2025 08:48
1.broker侧
  - 在BrokerController的start中调用publishevent,发送START事件
2.proxy侧
  - 增加对START事件的处理,逻辑和TOPIC_CHANGE一致,即更新受影响的topic路由
@saz97
saz97 force-pushed the route_change_notification branch from 758c181 to 13bc8ff Compare September 12, 2025 06:16
Comment thread broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java Outdated
1. 收敛重复代码:
   - 提取公共事件发布逻辑到统一方法
   - 消除TopicConfigManager中各操作点的重复事件发布代码

2. 实现事件分块发送:
   - 当topic数量超过阈值时自动分块发送
   - 新增partitionTopics方法处理主题分批
   - 支持MAX_TOPICS_PER_EVENT配置控制批量大小
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/route/RouteEventService.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java Outdated
Comment thread broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java Outdated
- 将BrokerController中的START事件发布时机移至Broker registerBrokerAll后执行
- 在发送START和SHUTDOWN事件前,增加enableRouteChangeNotification配置检查
- 将RouteEventService中MAX_TOPICS_PER_EVENT批次大小从100调整为5000
- 在TopicConfigManager中新增带publishEvent参数的deleteTopicConfig重载方法
- 修改SlaveSynchronize在同步操作时调用publishEvent=false的deleteTopicConfig方法
- 将TOPIC_CHANGE逻辑统一收敛到registerBrokerData方法中
- 在RouteEventSubscriber构造函数中设置消费位点为CONSUME_FROM_LAST_OFFSET
Comment thread broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java Outdated
1. 将RouteEventSubscriber和RouteCacheRefresher合并为RouteChangeNotifier
2. 简化BrokerController中事件发布代码,改为直接调用routeEventService封装方法
3. 在RouteEventService中添加publishEvent重载方法
4. 更新相关测试代码适应新的类结构
- 移除向本地store写入的逻辑
- 基于RMQ_ROUTE_EVENT_TOPIC的路由信息,向其他相关的远端Broker发送实现消息
- 添加Broker名称去重处理,避免重复发送
- 使用putMessageToRemoteBroker进行跨Broker消息传输
Comment thread broker/src/main/java/org/apache/rocketmq/broker/route/RouteEventService.java Outdated
- 增加在broker侧TOPIC_CHANGE事件的发送逻辑:直接写入本地store
- 重构向远端broker发送消息的逻辑:由向全部broker发送改为只向一个broker发送
- 修改RouteChangeNotifier的线程池配置,单独使用独立线程池
Comment thread broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java Outdated
Comment thread common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java Outdated
saz97 and others added 2 commits September 24, 2025 09:30
- 把开关enableRouteChangeNotification设置为常闭
- 把RouteEventService的初始化放在BrokerController的初始化里
- 在InnerBrokerController也添加START的publish event
@RongtongJin
RongtongJin changed the base branch from develop to feature-reverse-route-update October 27, 2025 08:07
@RongtongJin RongtongJin added the ha label Oct 27, 2025
@RongtongJin
RongtongJin merged commit b4cff03 into apache:feature-reverse-route-update Oct 28, 2025
20 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants