
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):
- 只有第 4 位(
Maintenance)变化才支持滚动升级; - 升级默认不可逆 。官方只对
Feature/Maintenance位标注了"可回退",但那是"版本路径允许",不等于"你随时能退回来"------请按"升上去就回不来"来做方案(原因见 §2.1 的重提示); - 滚动升级的前提是"≥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 |
要做的事:
- 升级前清点全部客户端:JDBC / Python / Go / C# / Node.js / ODBC / taosdump / taosBenchmark / Grafana 插件 / taosX;
- 升级中 如果无法一次升完所有客户端,用 WebSocket 连接(6041)作为过渡------官方对 WebSocket 提供兼容性保证,比原生连接更耐跨版本;
- 升级后把所有客户端驱动升到与服务端前三段一致。
原生驱动的版本要求最严:官方明确"强烈不建议高版本驱动连接低版本服务端"。
顺带一句原理 (不影响操作,知道就行):版本号前三位相同即可通行,第 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 的备份功能做增量备份。
注意两点:
taosdump默认-M basic不包含虚拟表、流、Topic ,升级前的备份请显式加-M all;- 这份备份大概就是你唯一的退路 ------ 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 完全一样:
- 先动"最不关键"的节点------纯数据节点,它下线不影响元数据服务;
- 再动 mnode 的 follower------mnode 仍有多数派,元数据服务不受影响;
- 最后才动 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 篇) |
所以滚动升级前的那份备份不是"以防万一",而是必需的。
万一必须止损:把集群回到"统一版本"优先于"回到旧版本"------
- 不要在"部分节点新、部分节点旧"的状态下反复重启,那更容易把元数据搞乱;
- 先把已升级的节点继续升完(保证全集群同版本、集群可用),再评估业务能否接受;
- 若不能接受,走备份重建。
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 |