现象与环境
三节点集群断网测试后,两个在线 DataNode 均可登录、读取表结构,但同一条数据查询在 B 节点成功,在 C 节点持续超时。已确认 C 缓存了过期的 Region 副本顺序;仅重发一次 ConfigNode 当前路由,查询立即恢复。
- IoTDB 2.0.10(BuildInfo
3c26382),Table model;openEuler 24.03 LTS-SP3,Temurin OpenJDK 25.0.3+9-LTS。
- 三台物理机,每台部署一个 ConfigNode 和一个 DataNode。A(DN3)断网,B(DN4)、C(DN5)在线,C 为 ConfigNode Leader。
- ConfigNode / SchemaRegion 使用 Ratis,Schema 副本数 3;DataRegion 使用 IoTConsensus,数据副本数 2。
- 默认参数:
read_consistency_level=strong、enable_topology_probing=false;连接和查询超时均为 60000 ms。
- DataRegion 1 位于 A/C,Leader 为 C;DataRegion 2 位于 A/B,Leader 为 B。每个 Region 均有在线副本,B/C 之间相关内部端口可达。
主机名和库表名已脱敏,Node ID、Region ID 与耗时保留实测值。
现场复现与验证
-
在已有三节点集群中进行网络中断/恢复测试,期间出现 ConfigNode Leader 切换;排查时保持 A 断网。
-
等待集群显示 A 为 Unknown、B/C 为 Running,分别通过 B/C 执行:
SELECT * FROM test_db.test_table LIMIT 5;
SELECT COUNT(*) FROM test_db.test_table;
-
B 正常返回,C 多次约 60 秒后返回 720: Current query is time out。DBeaver 和安装包自带 CLI 均可复现;C 服务端日志显示仍尝试连接离线的 A:
can't execute request on node TEndPoint(ip:node-A, port:10730),
error msg is java.net.SocketTimeoutException: Connect timed out
通过只读 Java Attach 诊断读取现有 JVM 对象,确认差异位于 ClusterPartitionFetcher.partitionCache.groupIdToReplicaSetMap:
| 路由来源 |
DataRegion 2 副本顺序 |
| ConfigNode 当前路由 |
[4, 3],在线 B 优先 |
| B 的 PartitionCache |
[4, 3] |
| C 的 PartitionCache |
[3, 4],离线 A 优先 |
随后读取 ConfigNode 的 getLatestRegionRouteMap(),通过一次 updateRegionCache(TRegionRouteReq) 将其原始时间戳和路由发给 C,返回状态 200。C 的顺序变为 [4, 3],相同查询立即恢复:LIMIT 5 为 0.058 秒,COUNT(*) 为 0.095 秒、返回 40 行。
整个验证期间 A 仍断网,C 的进程未重启,未修改配置或数据库数据。这证明过期路由与本次超时直接相关;重发路由只是临时恢复措施。
关键源码与疑似触发条件
以下链接固定到现场版本提交 3c26382bebee73ec1c9593f836ef4cdcc0376062。
1. 路由广播排除 Unknown 节点,并且依赖优先级发生变化。
RouteBalancer.java,615–653 行 中,仅当新旧优先级不同才设置 needBroadcast;广播目标过滤条件为:
.filterDataNodeThroughStatus(
NodeStatus.Running, NodeStatus.Removing, NodeStatus.ReadOnly)
节点状态变化回调,771–775 行 调用 handleBalanceAction(balanceAllEnabledRegionLeaders()),没有直接向恢复的节点补发路由。若后续权威优先级不变,可能无法再次触发广播。
现场 ConfigNode 日志时间顺序(UTC+8):
09:20:58.106 DN3/4/5:null -> Unknown
09:20:58.111 DataRegion 2:null -> [4,3]
09:20:58.115 DN4/5:Unknown -> Running
因此怀疑:Leader 切换初始化时,C 处于 Unknown 而错过路由,恢复 Running 后未获得补发。尚未捕获当次广播的实际接收者或 RPC 报文,也未在全新集群中稳定复现首次漏发;这个具体触发时序仍是推断。
2. DataNode 命中旧缓存后,不会主动拉取最新路由。
PartitionCache.java,572–619 行 的 getRegionReplicaSet() 先查本地 Map,仅在 result.isEmpty() 时向 ConfigNode 获取路由。该 Map 没有 TTL,因此已有 Region 的旧副本顺序可持续命中。
3. 连接离线副本可能耗尽整个查询时间。
FragmentInstanceDispatcherImpl.java,583–615 行 在连接异常后检查查询截止时间;若已超过,直接返回查询超时。现场连接与查询超时同为 60 秒,与日志中的连接超时后返回 720 一致。
希望确认
预期:集群状态稳定且每个 Region 仍有在线副本时,各在线 DataNode 应最终更新路由,避免持续将查询发往已离线的副本。
现象与环境
三节点集群断网测试后,两个在线 DataNode 均可登录、读取表结构,但同一条数据查询在 B 节点成功,在 C 节点持续超时。已确认 C 缓存了过期的 Region 副本顺序;仅重发一次 ConfigNode 当前路由,查询立即恢复。
3c26382),Table model;openEuler 24.03 LTS-SP3,Temurin OpenJDK 25.0.3+9-LTS。read_consistency_level=strong、enable_topology_probing=false;连接和查询超时均为 60000 ms。主机名和库表名已脱敏,Node ID、Region ID 与耗时保留实测值。
现场复现与验证
在已有三节点集群中进行网络中断/恢复测试,期间出现 ConfigNode Leader 切换;排查时保持 A 断网。
等待集群显示 A 为 Unknown、B/C 为 Running,分别通过 B/C 执行:
B 正常返回,C 多次约 60 秒后返回
720: Current query is time out。DBeaver 和安装包自带 CLI 均可复现;C 服务端日志显示仍尝试连接离线的 A:通过只读 Java Attach 诊断读取现有 JVM 对象,确认差异位于
ClusterPartitionFetcher.partitionCache.groupIdToReplicaSetMap:随后读取 ConfigNode 的
getLatestRegionRouteMap(),通过一次updateRegionCache(TRegionRouteReq)将其原始时间戳和路由发给 C,返回状态 200。C 的顺序变为[4, 3],相同查询立即恢复:LIMIT 5为 0.058 秒,COUNT(*)为 0.095 秒、返回 40 行。整个验证期间 A 仍断网,C 的进程未重启,未修改配置或数据库数据。这证明过期路由与本次超时直接相关;重发路由只是临时恢复措施。
关键源码与疑似触发条件
以下链接固定到现场版本提交
3c26382bebee73ec1c9593f836ef4cdcc0376062。1. 路由广播排除 Unknown 节点,并且依赖优先级发生变化。
RouteBalancer.java,615–653 行 中,仅当新旧优先级不同才设置
needBroadcast;广播目标过滤条件为:节点状态变化回调,771–775 行 调用
handleBalanceAction(balanceAllEnabledRegionLeaders()),没有直接向恢复的节点补发路由。若后续权威优先级不变,可能无法再次触发广播。现场 ConfigNode 日志时间顺序(UTC+8):
因此怀疑:Leader 切换初始化时,C 处于 Unknown 而错过路由,恢复 Running 后未获得补发。尚未捕获当次广播的实际接收者或 RPC 报文,也未在全新集群中稳定复现首次漏发;这个具体触发时序仍是推断。
2. DataNode 命中旧缓存后,不会主动拉取最新路由。
PartitionCache.java,572–619 行 的
getRegionReplicaSet()先查本地 Map,仅在result.isEmpty()时向 ConfigNode 获取路由。该 Map 没有 TTL,因此已有 Region 的旧副本顺序可持续命中。3. 连接离线副本可能耗尽整个查询时间。
FragmentInstanceDispatcherImpl.java,583–615 行 在连接异常后检查查询截止时间;若已超过,直接返回查询超时。现场连接与查询超时同为 60 秒,与日志中的连接超时后返回 720 一致。
希望确认
预期:集群状态稳定且每个 Region 仍有在线副本时,各在线 DataNode 应最终更新路由,避免持续将查询发往已离线的副本。