TDengine TSDB 实战排障四(升级与兼容)

TDengine TSDB 实战排障四(升级与兼容)

你要解决的问题:把 TDengine 从一个版本升到另一个版本------该怎么升、要不要停服、升完怎么验证、出问题怎么回退

适用版本 :TDengine TSDB 3.x(3.0 ~ 3.4),社区版与企业版

面向读者 :要交付升级方案的架构师、执行升级的实施与运维人员;被"升级后连不上/订阅失败"困扰的人

文档定位 :这是一篇升级操作指南。第 1~7 章是"怎么做",第 8 章是"出错了怎么办"


1. 先看结论:你该用哪种升级方式

先记住两种方式的分界:

方式 一句话 服务是否中断
滚动升级 一次只停一个节点,升完再动下一个 不中断(集群仍需对外服务)
停服升级 整个集群停下来,全部升完再启动 中断(就是它的代价,也是它的安全来源)

选哪个,由两个条件决定:
#mermaid-svg-TusCAOjnJewJy2Se{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TusCAOjnJewJy2Se .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TusCAOjnJewJy2Se .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TusCAOjnJewJy2Se .error-icon{fill:#552222;}#mermaid-svg-TusCAOjnJewJy2Se .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TusCAOjnJewJy2Se .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TusCAOjnJewJy2Se .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TusCAOjnJewJy2Se .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TusCAOjnJewJy2Se .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TusCAOjnJewJy2Se .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TusCAOjnJewJy2Se .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TusCAOjnJewJy2Se .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TusCAOjnJewJy2Se .marker.cross{stroke:#333333;}#mermaid-svg-TusCAOjnJewJy2Se svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TusCAOjnJewJy2Se p{margin:0;}#mermaid-svg-TusCAOjnJewJy2Se .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TusCAOjnJewJy2Se .cluster-label text{fill:#333;}#mermaid-svg-TusCAOjnJewJy2Se .cluster-label span{color:#333;}#mermaid-svg-TusCAOjnJewJy2Se .cluster-label span p{background-color:transparent;}#mermaid-svg-TusCAOjnJewJy2Se .label text,#mermaid-svg-TusCAOjnJewJy2Se span{fill:#333;color:#333;}#mermaid-svg-TusCAOjnJewJy2Se .node rect,#mermaid-svg-TusCAOjnJewJy2Se .node circle,#mermaid-svg-TusCAOjnJewJy2Se .node ellipse,#mermaid-svg-TusCAOjnJewJy2Se .node polygon,#mermaid-svg-TusCAOjnJewJy2Se .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TusCAOjnJewJy2Se .rough-node .label text,#mermaid-svg-TusCAOjnJewJy2Se .node .label text,#mermaid-svg-TusCAOjnJewJy2Se .image-shape .label,#mermaid-svg-TusCAOjnJewJy2Se .icon-shape .label{text-anchor:middle;}#mermaid-svg-TusCAOjnJewJy2Se .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TusCAOjnJewJy2Se .rough-node .label,#mermaid-svg-TusCAOjnJewJy2Se .node .label,#mermaid-svg-TusCAOjnJewJy2Se .image-shape .label,#mermaid-svg-TusCAOjnJewJy2Se .icon-shape .label{text-align:center;}#mermaid-svg-TusCAOjnJewJy2Se .node.clickable{cursor:pointer;}#mermaid-svg-TusCAOjnJewJy2Se .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TusCAOjnJewJy2Se .arrowheadPath{fill:#333333;}#mermaid-svg-TusCAOjnJewJy2Se .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TusCAOjnJewJy2Se .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TusCAOjnJewJy2Se .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TusCAOjnJewJy2Se .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TusCAOjnJewJy2Se .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TusCAOjnJewJy2Se .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TusCAOjnJewJy2Se .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TusCAOjnJewJy2Se .cluster text{fill:#333;}#mermaid-svg-TusCAOjnJewJy2Se .cluster span{color:#333;}#mermaid-svg-TusCAOjnJewJy2Se div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TusCAOjnJewJy2Se .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TusCAOjnJewJy2Se rect.text{fill:none;stroke-width:0;}#mermaid-svg-TusCAOjnJewJy2Se .icon-shape,#mermaid-svg-TusCAOjnJewJy2Se .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TusCAOjnJewJy2Se .icon-shape p,#mermaid-svg-TusCAOjnJewJy2Se .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TusCAOjnJewJy2Se .icon-shape .label rect,#mermaid-svg-TusCAOjnJewJy2Se .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TusCAOjnJewJy2Se .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TusCAOjnJewJy2Se .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TusCAOjnJewJy2Se :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Major+ / Major(第1、2位)
Feature(第3位)
Maintenance(第4位)
是
否
我要升级
这次升级跨的是哪一位版本号
❌ 不能滚动升级

只能停服升级
❌ 不能滚动升级

只能停服升级(但可回退)
集群是 ≥3 节点 + 三副本吗
§4 停服升级
✅ 可以滚动升级

§5
只能用停服升级

§4

三条硬结论(来自官方版本规则,原文见 §2.1):

  1. 只有第 4 位(Maintenance)变化才支持滚动升级;
  2. 升级默认不可逆 。官方只对 Feature / Maintenance 位标注了"可回退",但那是"版本路径允许",不等于"你随时能退回来"------请按"升上去就回不来"来做方案(原因见 §2.1 的重提示);
  3. 滚动升级的前提是"≥3 节点 + 三副本",单机、双节点、单副本都不行。

2. 升级前必须确认的四件事

2.1 你跨的是哪一位版本号

TDengine 版本号是四段:[Major+].[Major].[Feature].[Maintenance],官方对每一位的定义如下(docs/zh/17-release-history/01-engine.md,原文引用):

位 官方定义 能否滚动升级 官方标注能否回退 备注
Major+ 产品有重大重构,不能直接升级 --- --- 需联系 TDengine 客户支持团队
Major 有重大新特性 ❌ ❌ 不可回退 如 v3.2.3.0 → v3.3.0.0 后不能回退
Feature 有新特性 ❌ ✅ 同 Major 内可回退 如 v3.3.0.0 → v3.3.1.0 后可回到 v3.3.0.0。客户端驱动需同步升级
Maintenance 没有新特性,只有缺陷修复 ✅ ✅ 推荐优先升到该系列最新

滚动升级的官方定义 (同文档):

"由三个或以上节点组成且使用三副本的集群,每次停止一个节点、对其进行升级、然后重新启动,按此过程循环完成对集群中所有节点的升级,在升级期间集群仍然可以对外提供服务。对于不支持滚动升级的版本变化,需要先停止整个集群、升级集群中所有节点、最后启动整个集群,在升级期间集群不能对外提供服务。"

怎么快速判断:把你现在的版本和目标版本对齐,看第几位变了。

例子 变的位 结论
3.3.6.9 → 3.3.6.13 第 4 位 ✅ 可滚动升级;官方标注可回退
3.3.6.13 → 3.3.7.0 第 3 位 ❌ 停服升级;官方标注可回退
3.3.7.0 → 3.4.0.0 第 2 位 ❌ 停服升级;官方标注不可回退

⚠️ 重要:请把"升级不可逆"当作默认假设

上表最后一列写的是官方对版本路径的定义,不是"你升级完随时能退回来"的承诺。三个依据:

1)官方对 v3.4.0.0 权限模型升级明确写了不可降级 (docs/zh/05-tdengine-sql/07-user-and-privilege/02-grant.md:1227):

项目 说明
✓ 自动升级 支持从低版本停机后自动升级到 v3.4.0.0 及之后
✗ 滚动升级 不支持滚动升级,必须停机升级
✗ 版本回退 升级后无法降级到低版本

2)技术根因:元数据版本号只增不减。 每个元数据对象都带一个版本号,读出来后会与当前程序的常量比较,大于就直接报错拒绝加载:

c 复制代码
// source/dnode/mnode/impl/src/mndDb.c:211-215
// mndAcct / mndAnode / mndArbGroup / mndBnode / mndCluster / mndConfig /
// mndConsumer / mndStream ... 每个 SDB 对象都有同一道门
if (sver < 1 || sver > DB_VER_NUMBER) {
  terrno = TSDB_CODE_SDB_INVALID_DATA_VER;      // "Invalid raw data version"
}

新版本一旦写入过新版本特有的元数据(建库、建表、改权限、加流、加用户...),老版本就读不了 → 降级后根本起不来。

3)所以工程上的结论是:

  • 把备份当作唯一的退路,而不是把"装回旧版本"当作退路;
  • 真要尝试装回旧版本,只能用于 Maintenance 位小版本、且升级后没做过任何 DDL 与写入的场景,并且必须经技术支持确认该版本对没有提升元数据版本号。

2.2 客户端驱动必须同步升级

这是最容易事后踩坑的一条,务必在变更单里单列:

连接校验的规则是"版本号前三段必须一致,且社区版/企业版不能混用":

客户端 服务端 结果
3.3.6.13 3.3.6.9 ✅ 兼容(前三段 3.3.6 一致,第 4 位不同不影响)
3.0.7.0 3.2.3.0 ❌ Version not compatible
3.4.2.5(社区版驱动) 3.4.2.5(企业版服务端) ❌ Edition not compatible

要做的事:

  1. 升级前清点全部客户端:JDBC / Python / Go / C# / Node.js / ODBC / taosdump / taosBenchmark / Grafana 插件 / taosX;
  2. 升级中 如果无法一次升完所有客户端,用 WebSocket 连接(6041)作为过渡------官方对 WebSocket 提供兼容性保证,比原生连接更耐跨版本;
  3. 升级后把所有客户端驱动升到与服务端前三段一致。

原生驱动的版本要求最严:官方明确"强烈不建议高版本驱动连接低版本服务端"。

顺带一句原理 (不影响操作,知道就行):版本号前三位相同即可通行,第 4 位(维护号)会被忽略;社区版/企业版是靠版本串末尾的版本档位标识 区分的。官方口径是自 v3.4.0.0 起两者不完全兼容。

2.3 社区版与企业版不能混用

自 v3.4.0.0 起,社区版与企业版不完全兼容。服务端是企业版,客户端驱动就必须是企业版;反之亦然。

混用的报错是 Edition not compatible,它不会因为你把版本号升成一样就消失。

2.4 把"特殊能力"单独过一遍

这几项升级风险最高,必须在升级前逐条确认:

你用了什么 升级前要确认什么 官方口径
共享存储 3.3.7.0 的共享存储与旧 S3 对象存储不兼容,需手工处理;Azure Blob 用户建议暂缓 docs/zh/.../02-operations/07-multi.md:18,202
存储加密 v3.3 是库级 ENCRYPT_ALGORITHM,v3.4 改为 taosk 分级密钥,有专门升级路径 docs/zh/11-security-guide/06-data-security.md:23
流计算 / 订阅 跨版本可能存在行为差异(历史上有过"滚动升级后流任务无法启动"的缺陷),升级后必须实测消费 各版本 Release Notes
虚拟表 依赖服务端版本能力,旧服务端 + 新驱动会报"版本不兼容"而不是语法错误 ---
数据目录来自 2.x 不能原地升级 。taosd 检测到 2.x 数据目录会拒绝启动,必须用 taosdump 导出再导入(见第 05 篇) dmEnv.c:167-176

3. 升级前的准备(两种方式都要做)

这一章照搬业界通行做法:备份 → 兼容性确认 → 定窗口 → 先演练。

3.1 备份(不可跳过)

bash 复制代码
# 全量导出(详见第 05 篇)
taosdump -h <host> -D <db> -M all -o /root/backup_before_upgrade/

# 至少导出 schema 作为兜底
taosdump -h <host> -D <db> -s -o /root/backup_schema/

企业版还可以用 Explorer 的备份功能做增量备份。

注意两点:

  1. taosdump 默认 -M basic 不包含虚拟表、流、Topic ,升级前的备份请显式加 -M all;
  2. 这份备份大概就是你唯一的退路 ------ TDengine 升级不可逆(§2.1),不要指望"装回旧版本"能救回来。

3.2 兼容性与风险确认

确认项 怎么做
升级路径合法 对照 §2.1 的四段规则;Major+ 位变化必须先联系技术支持
客户端可同步升级 列出清单与负责人,确认能否在同一维护窗口完成
数据目录可复用 检查是否 2.x 遗留:ls /var/lib/taos/dnode/dnodeCfg.json
特殊能力已评估 走一遍 §2.4 的表
磁盘余量 升级过程需要额外空间,参考第 09 篇的七类占用口径

3.3 先定维护窗口

方式 窗口要求
滚动升级 不需要停服窗口,但仍建议安排在业务低峰------期间会有秒级抖动(见 §5.5)
停服升级 必须申请明确的中断窗口,时长以测试环境实测为准

3.4 先在测试环境演练一遍(强烈建议)

不要在生产环境做第一次尝试。 两个手段:

① 用官方验证工具先跑一次

TDengine 开源了一个升级兼容性验证工具 compat-check,能在一台机器上起 3 节点集群,模拟一次冷升级或滚动升级,并校验数据与资源完整性:

bash 复制代码
cd source/taos-community/test/tools/compat-check

# 滚动升级模式(-r);不带 -r 则是停服升级
python -m run.main -F /opt/td/3.3.8.0 -T /opt/td/3.4.0.8 -r

# 快速冒烟(100 子表 × 1000 行、30 秒观察窗口)
python -m run.main -F /opt/td/3.3.8.0 -T /opt/td/3.4.0.8 -r -q

# 顺便比对系统表结构变化
python -m run.main -F /opt/td/3.3.8.0 -T /opt/td/3.4.0.8 -r -S

它会检查:升级期间持续写入/查询/订阅是否正常、订阅消费行数是否等于写入行数、Tag Index / TSMA / RSMA / Stream / 用户权限是否保持、系统表有无意外变化。

它同时给出了滚动升级的"合格线",可以直接写进你的验收标准:

指标 合格线
写入延时 ≤ 2 秒
查询延时 ≤ 2 秒
订阅消息间隔 ≤ 2 秒

② 在等价环境演练:用与生产同构的机器(节点数、副本数、数据量级)跑一遍完整流程,把实际耗时记下来,写进变更单。

3.5 官方对升级工具的如实提示

TDengine 官方安装工具 taosinstall 的文档里有这样一段风险提示,照实转达:

"由于客户现场环境复杂,在启停服务过程可能遇到不可预期的问题,目前升级功能仅推荐在测试环境使用,比如验证版本升级。若在业务环境使用需要提前评估其风险。"

它的含义不是"不能用",而是:升级脚本只负责流程编排,出问题的判断还是得靠人------所以 §7 的验证清单和 §8 的报错速查才是这篇文章真正要你看的部分。


4. 方式一:停服升级(冷升级)

4.1 什么情况选它

场景 说明
跨 Major / Feature 位升级 官方定义就不支持滚动升级,只能用这个
集群不是"≥3 节点 + 三副本" 单机、双节点、单副本都没有滚动升级的条件
想拿到"最干净"的结果 全部节点同版本再一起启动,不存在新旧版本混跑窗口
想留一条简单的回退路 回退就是"再停一次、装回旧版本、再启动"

4.2 优缺点

优点

  • 兼容风险最低:不存在新旧版本同时提供服务的窗口;
  • 出问题时止损最快:全集群一起停,不会出现"一半新版本、一半旧版本"的尴尬中间态;
  • 对客户端最友好:客户端遇到的是"连不上→稍后重试",不会遇到"部分请求成功、部分失败"的中间态;
  • 不依赖客户端驱动与服务端严格同版本,因为不存在混跑窗口。

注意:"止损快"不等于"能回退"。能不能装回旧版本,取决于升级后有没有产生新版本的元数据------见 §4.4。

缺点

  • 服务真的中断,中断时长 = 全部节点装包 + 全部节点启动;
  • 停机时长随节点数增加而增加;
  • 需要申请明确的业务中断窗口;
  • 数据量大时启动耗时长(vnode 恢复、日志重放)。

4.3 完整步骤

官方安装工具的顺序是 firstEp → secondEp → dnode3 → ... ,八个步骤(docs/zh/.../03-taosinstall.md):

步 动作
1 复制安装包到集群各节点
2 停止服务 :taosd、taosadapter、taoskeeper、taosx、taos-explorer
3 更新版本:安装新版本包
4 启动 taosd
5 启动 taosadapter
6 启动 taoskeeper
7 启动 taosx
8 启动 taos-explorer

用官方工具一条命令即可(前提是节点间配置好 SSH 免密):

bash 复制代码
./taosinstall upgrade -m ssh

手工执行则每个节点重复下面这一段:

bash 复制代码
# ① 停服(注意顺序:先停依赖方,再停 taosd)
systemctl stop taos-explorer
systemctl stop taosx
systemctl stop taoskeeper
systemctl stop taosadapter
systemctl stop taosd

# ② 替换程序包(数据目录与配置不会被覆盖,见下方说明)
# ...安装新版本包...

# ③ 启动(顺序与停服相反)
systemctl start taosd
systemctl start taosadapter
systemctl start taoskeeper
systemctl start taosx
systemctl start taos-explorer

数据与配置会不会丢? 不会。升级安装复用已有安装目录、不重建数据目录 ,也不会覆盖 /etc/taos/taos.cfg(packaging/tools/install.sh:482 有明确注释)。但务必仍然先备份。

全部节点升完后,做一次集群收尾(见 §7)。

4.4 回退:请按"升级不可逆"来规划

先记住结论:把"升上去就回不来"当作默认情况。

你以为的回退 实际情况
装回旧版本包就能恢复 只有"升级后没产生新版本元数据"时才可能成功
官方说 Feature / Maintenance 可回退 那是"版本路径允许",不是"随时能退"(§2.1)
数据还在磁盘上就没事 元数据版本号只增不减,老版本读到更新的版本号会报 Invalid raw data version 并拒绝启动
✅ 可靠的退路:备份,而不是降级
bash 复制代码
# 升级前的这份备份,就是你的回退方案
# (详见第 05 篇;注意必须加 -M all,否则不含虚拟表/流/Topic)
taosdump -h <host> -D <db> -M all -o /root/backup_before_upgrade/

回退动作 = 在旧版本集群上导入这份备份,而不是把程序装回去。

⚠️ 如果确实要尝试"装回旧版本"

仅适用于:Maintenance 位小版本,且升级后没有做过任何 DDL 与写入。

bash 复制代码
# ① 先让技术支持确认:这个版本对是否提升了元数据版本号
#    (没有提升,才有降级的可能)

# ② 全集群停机(不要在部分节点还运行的状态下开始)
systemctl stop taosd

# ③ 逐节点装回旧版本包
# ...安装旧版本包...

# ④ 启动后立即检查是否被元数据版本拦住
sql 复制代码
select id, endpoint, status, note from information_schema.ins_dnodes;
结果 含义 下一步
节点全部 ready 降级成功(该版本对未提升元数据版本) 立即验证数据与订阅
启动报 Invalid raw data version(0x80000328) 元数据已被新版本改写 只能回到备份重建(第 05 篇)
节点起不来且无明确报错 情况不明 停止操作、保留现场、联系技术支持

踩坑提示 :官方安装工具与安装脚本都不会拦你降级------它们不管你装的是比当前更新还是更旧的包。所以"能装上"并不代表"能跑起来"。


5. 方式二:滚动升级

5.1 什么情况选它:两个硬性前提

前提一:版本变化限于第 4 位(Maintenance)

前提二:集群由 ≥3 个节点组成且使用三副本

为什么第二条是硬要求 :副本同步走 Raft,写入需要多数派 确认(quorum = 副本数 / 2 + 1)。

拓扑 停 1 台后 能否继续服务
3 节点 + 三副本 剩 2 个副本,满足 quorum = 2 ✅
2 节点 + 双副本 剩 1 个副本,凑不够 quorum = 2 ❌ 无法写入
单节点 / 单副本 直接不可用 ❌

换句话说:"三副本"的真正价值不是多存两份数据,而是让你可以一台一台地维护。

5.2 优缺点

优点

  • 服务不中断:升级期间集群仍可读写,业务感知很小;
  • 不需要申请停机窗口,可以安排在业务低峰慢慢做;
  • 每个节点的风险被隔离------升一个、验一个、再动下一个;
  • 出问题时影响面限于单个节点(该节点离线,其余节点继续服务)。

缺点

  • 存在新旧版本混跑的窗口:升级过程中集群里同时有新老两个版本的 taosd 在运行;
  • 会有秒级抖动:停节点时,该节点上的 leader 要重新选举,客户端需要重试(见 §5.5);
  • 回退基本不可行:混跑期间同时在持续写入,新版本的元数据极可能已经落盘,降级没有回头路(见 §5.6);
  • 对前提条件敏感:只要节点数或副本数不满足,就完全做不了;
  • 升级周期长(节点数 × 单节点耗时),期间需要持续盯着集群。

5.3 节点升级顺序:官方给了一个明确顺序

官方工具的顺序是(docs/zh/.../03-taosinstall.md):

text 复制代码
非 mnode 所在节点  →  mnode 为 follower 的节点  →  mnode 为 leader 的节点

这个顺序的道理和 MongoDB 先升 secondary、最后升 primary 完全一样:

  1. 先动"最不关键"的节点------纯数据节点,它下线不影响元数据服务;
  2. 再动 mnode 的 follower------mnode 仍有多数派,元数据服务不受影响;
  3. 最后才动 mnode 的 leader------把它放到最后,前面所有节点都已经是新版本,选举到新版本节点不会出现"新 leader + 全部老成员"的组合。

升级前先把 vgroup leader 从待升级节点上迁走,能显著减少抖动:

sql 复制代码
-- 看每个 vgroup 的 leader 落在哪个节点
select vgroup_id, db_name, v1_dnode, v1_status, v2_dnode, v2_status, v3_dnode, v3_status
from information_schema.ins_vgroups;

-- 把 leader 统一迁走(或只迁某个节点上的)
balance vgroup leader;

先迁 leader 再停机,和 MongoDB 的 rs.stepDown() 是同一个思路:主动触发一次可控的切换,好过让集群在停机时被动发现。

5.4 单个节点的完整步骤

sql 复制代码
-- ① 确认该节点上没有 leader(上一步已经迁走)
select vgroup_id, v1_dnode, v1_status, v2_dnode, v2_status, v3_dnode, v3_status
from information_schema.ins_vgroups;
bash 复制代码
# ② 停服
systemctl stop taos-explorer
systemctl stop taosx
systemctl stop taoskeeper
systemctl stop taosadapter
systemctl stop taosd
sql 复制代码
-- ③ 确认集群已经把该节点标记为不可用,再动包
select id, endpoint, status, note from information_schema.ins_dnodes;

这一步不能省。集群要靠心跳超时(默认 5 秒)才发现节点离线;不等它确认就换包启动,容易出现"新旧版本同时在线"的窗口。

bash 复制代码
# ④ 替换程序包
# ...安装新版本包...
bash 复制代码
# ⑤ 启动
systemctl start taosd
systemctl start taosadapter
systemctl start taoskeeper
systemctl start taosx
systemctl start taos-explorer
sql 复制代码
-- ⑥ 等状态回到 ready,才动下一个节点
select id, endpoint, status, note from information_schema.ins_dnodes;

判据是 status 列等于 ready ,不是"进程起来了"。②~⑥ 循环,直到所有节点完成。

用官方工具则是一条命令(-r 即 rolling upgrade):

bash 复制代码
./taosinstall upgrade -m ssh -r

5.5 升级期间,你的应用会经历什么(这一节最重要)

很多人不敢做滚动升级,是因为不知道"业务到底会不会受影响"。实际情况是:

现象 原因 你需要做什么
秒级写入/查询失败或重试 停节点时该节点上的 leader 重新选举,客户端拿到"非 leader"响应后会重试 应用侧必须开启重试 ;客户端参数 maxRetryWaitTime 默认 20000 ms
查询延迟短暂升高 请求被重定向到其他节点 建议放在业务低峰做
TMQ 订阅可能短暂中断 消费的 vgroup leader 切换 消费者要能自动重连;升级后核对"消费行数 == 写入行数"
DDL 可能失败 元数据服务(mnode)在切换 升级期间不要做 DDL(建库/建表/改结构)
show dnodes 短暂查不到 leader mnode 正在选举 属正常现象,等几秒再看

官方验证工具把这些量化成了合格线(§3.4):写入延时 ≤ 2 秒、查询延时 ≤ 2 秒、订阅间隔 ≤ 2 秒。

一句话给业务方 :滚动升级期间会有秒级的抖动,不会中断服务;但应用必须有重试,且升级窗口内不要做建表建库这类操作。

5.6 回退:滚动升级几乎没有回头路

滚动升级的混跑窗口同时也是持续写入的窗口 ------ 这意味着新版本很可能已经写下了新版本的元数据,降级的可行性比停服升级更低。

退路 可行性
逐节点装回旧版本 ❌ 极低。混跑 + 持续写入下,元数据版本极可能已前进;老版本读到会报 Invalid raw data version
从升级前的备份重建 ✅ 唯一可靠(第 05 篇)

所以滚动升级前的那份备份不是"以防万一",而是必需的。

万一必须止损:把集群回到"统一版本"优先于"回到旧版本"------

  1. 不要在"部分节点新、部分节点旧"的状态下反复重启,那更容易把元数据搞乱;
  2. 先把已升级的节点继续升完(保证全集群同版本、集群可用),再评估业务能否接受;
  3. 若不能接受,走备份重建。

6. 两种方式对比总表

对比项 滚动升级 停服升级
适用版本变化 仅第 4 位(Maintenance) 任意(Major+ 需先联系技术支持)
适用拓扑 ≥3 节点 + 三副本 任意(含单机)
服务中断 不中断(秒级抖动) 完全中断
升级期间新旧版本混跑 有 无
业务侧要求 应用必须有重试;窗口内不做 DDL 需要停机窗口
单节点耗时 停服 + 装包 + 启动 + 等 ready 同上,但全集群一起做
总耗时 较长(节点数 × 单节点耗时) 较短(可并行装包)
回退可行性 ❌ 极低(混跑 + 持续写入,元数据已前进) ⚠️ 仅在"Maintenance 位 + 未做任何 DDL 与写入"时才可能
可靠退路 升级前的全量备份(必需) 升级前的全量备份(必需)
风险点 leader 切换抖动、混跑窗口 停机时长、一次性风险集中
官方工具命令 taosinstall upgrade -m ssh -r taosinstall upgrade -m ssh

一句话选择建议:

  • 第 4 位变化 + 集群满足三副本 → 选滚动升级,把窗口放在低峰;
  • 跨 Feature / Major,或拓扑不满足 → 只能停服升级,务必先演练;
  • 两种方式都要先做一件事 :升级前的全量备份------它是唯一的退路(§2.1)。

7. 升级后验证清单

按顺序做完,别跳:

# 检查项 命令 / SQL 期望
1 所有节点在线且版本一致 select id, endpoint, status, note from information_schema.ins_dnodes; 全部 ready,note 无异常
2 客户端能连上 taos -h <host> -s "select server_version()" 返回目标版本
3 每个 vgroup 都有 leader select vgroup_id, v1_status, v2_status, v3_status from information_schema.ins_vgroups; 每个 vgroup 至少 1 个 leader
4 集群整体可用性 show cluster alive; 返回 1(完全可用)
5 leader 分布归位 balance vgroup leader; 再查第 3 项,分布均匀
6 数据一致性 scan; 然后 show scans; 无异常
7 流任务与订阅 show streams;、show topics; + 真实消费验证 消费行数 == 写入行数
8 权限与用户 select * from information_schema.ins_users; 与升级前一致
9 业务功能抽测 各业务自己跑一遍关键 SQL 结果与升级前一致
10 所有客户端驱动已升级 逐个确认版本 与服务端前三段一致

第 5 项的 balance vgroup leader 在滚动升级后必做:升级过程中 leader 会漂移,最后统一归位。


8. 升级中的报错怎么办

8.1 症状速查

# 报错 / 现象 错误码 真实原因 处理
1 Version not compatible 0x8000011E 客户端与服务端版本号前三段不一致 把驱动升到与服务端前三段一致(§2.2)
2 DND ERROR Version not compatible, client: 3000700, server: 3020300 0x8000011E 服务端拒绝了 RPC(3.0.7.0 连 3.2.3.0) 同上
3 Edition not compatible 0x80000140 社区版/企业版混用 换成对应对的驱动(§2.3)
4 Invalid client version 0x80000204 连接响应解析失败,典型版本错配 同上
5 节点 status 变 offline,note 提示版本不匹配 --- 该节点上报的版本与集群期望不一致 确认该节点装的是不是目标版本
6 启动报 "contains old data of tdengine 2.x" 0x80000132 2.x 遗留数据目录 不能原地升级,改用 taosdump 导出导入
7 启动报 Repeat initialization 0x80000123 同一进程重复初始化 检查是否有残留进程
8 Invalid raw data version 0x80000328 元数据版本高于当前程序支持的上限------降级时会撞到它 说明元数据已被更新的版本写过;只能从备份重建(§4.4)
9 升级后某条 SQL 报 Version not compatible 0x8000011E 用了新语法但服务端版本偏低 升服务端,或改用兼容写法(§8.2)
10 升级后流任务/订阅不工作 --- 版本间行为差异 查该版本 Release Notes,重建任务
11 升级后 leader 分布不均 --- 升级过程 leader 漂移 balance vgroup leader;
12 安装时报不兼容 --- 安装包里的最小兼容版本门禁 见 §8.3

8.2 为什么有些 SQL 突然报"版本不兼容"

新客户端 + 老服务端 时,部分新语法的报错是 Version not compatible,而不是"语法错误"。

官方对此的建议是:低版本驱动可以连高版本服务端(但不推荐),强烈不建议高版本驱动连接低版本服务端。

所以升级顺序是"先服务端、后客户端"------反过来的话,窗口期内会看到一批莫名其妙的"版本不兼容"。

8.3 安装报"不兼容"可能不是版本号写错了

安装包里有一道最小兼容版本门禁 :安装脚本会读包内的 driver/vercomp.txt,如果当前已装驱动的版本低于它记录的 min_compatible_version,就直接判定不兼容。

该文件的默认值是 3.0.0.0 (打包时可用 -m 覆盖)。所以:

  • 从 3.x 往上升,通常不会触发;
  • 从很老的版本往上跨时,可能被这道门禁拦住------这时应先按官方路径逐级升级。

9. 五个最常见的误区

# 误区 事实
1 "三副本可以挂两台" quorum = 副本数/2 + 1,三副本只能挂一台。这也正是滚动升级要求三副本的原因
2 "小版本升级随便回退" 升级默认不可逆 。元数据版本号只增不减,新版本写过之后老版本读到会直接拒绝启动;官方对 v3.4.0.0 升级也明写"升级后无法降级到低版本"。备份才是退路
3 "客户端不用动,服务端升了就行" 兼容要求是"前三段一致 + 版本档位一致";不正确升级驱动会直接连不上
4 "直接从 2.x 升到 3.4 就行" 2.x 数据目录 taosd 会拒绝加载,必须 taosdump 导出导入
5 "滚动升级业务完全无感" 有秒级抖动:leader 重选举、客户端重试、订阅短暂中断。应用必须有重试,窗口内不要做 DDL

相关推荐
nhdh1 小时前
SpringAI与SpringAIAlibaba:标准与生态的完美互补
java·人工智能·spring
小小龙学IT1 小时前
Go 泛型(Generics)深度解析:从类型参数到生产实践
开发语言·数据库·golang
这个DBA有点耶1 小时前
分区表深入:分区裁剪失效的6种场景、分区锁机制与维护实战
数据库·mysql·dba
蓝速科技2 小时前
政务自助终端信创选型与无人值守落地方案
android·大数据·数据库·人工智能·科技·技术分享·政务
不会写DN2 小时前
Go日志库工程选型与逃逸分析评测报告
java·服务器·golang
粤鼎恒业2 小时前
惠州工厂电子料回收厂家推荐:从交接单反推筛选标准
大数据·数据库·算法·硬件架构·硬件工程·pcb工艺·材料工程
SL_staff2 小时前
合规性折旧:当知识资产因主权缺位在审计中‘功能性清零’
java·设计模式·开源
wzq11_6662 小时前
Kubernetes集群——基础篇(基础知识与搭建步骤一遍过!!!)
java·容器·kubernetes
ShineWinsu2 小时前
对于Redis:Redis的认识以及分布式系统的解析
linux·数据库·c++·redis·缓存·消息队列·分布式架构