分类 :17.内部机制 | 篇章 :03 错误处理
错误处理是数据库可靠性的基石。本文讲解 TDengine 的错误码体系、异常传播路径、故障恢复机制。
错误分类速查
| 类别 | 错误码范围 | 例子 |
|---|---|---|
| 通用 | 0x0001~0x00FF | 内存不足 |
| RPC | 0x0100~0x01FF | 连接断开 |
| 客户端 | 0x0200~0x02FF | 无效连接 |
| 服务端通用 | 0x0300~0x03FF | 节点不可用 |
| 元数据 | 0x0400~0x04FF | 表不存在 |
| 查询 | 0x0700~0x07FF | SQL 语法 |
| 同步 | 0x0900~0x09FF | RAFT 错误 |
| TSDB | 0x0B00~0x0BFF | 数据块损坏 |
| 权限 | 0x0E00~0x0EFF | 权限不足 |
详细解析
1. 错误码设计
错误码格式:
uint32_t 32 位
例:0x80000216
高位 0x80000000:表示错误(与 0 区分)
低位 0x216:具体错误
设计原则:
- 全局唯一
- 按模块分段
- 易于排查
- 客户端/服务端一致
典型错误码:
0x00000000 成功
0x80000003 Out of memory
0x80000216 Invalid SQL
0x80000220 Database not exist
0x8000027C Table does not exist
0x80000408 Login disabled
0x80000B07 Disk full
2. 错误传播路径
错误产生 → 包装 → 传播 → 终端处理
例:查询不存在的表
① VNode 查询执行
└─ 表不存在 → ERROR 0x8000027C
② 错误打包到 RPC 响应
└─ 含错误码 + 错误描述
③ 客户端接收
└─ 解包错误
④ 客户端 API 抛异常 / 返回错误
└─ Python: raise exception
└─ Java: throw SQLException
└─ C: 返回非 0
⑤ 应用处理
└─ 重试 / 上报 / 失败
关键设计:
- 错误不被吞掉
- 上下文信息保留
- 链路追踪(QID)
3. 客户端错误处理
python
# Python 异常处理
import taosws
try:
conn = taosws.connect("...")
conn.execute("SELECT * FROM not_exist_table")
except taosws.QueryError as e:
print(f"Query error: {e}")
print(f"Error code: {e.errno}")
except taosws.ConnectionError as e:
print(f"Connection error: {e}")
# 重连逻辑
except Exception as e:
print(f"Other: {e}")
java
// Java
try {
Statement stmt = conn.createStatement();
stmt.execute("SELECT * FROM bad_table");
} catch (SQLException e) {
int errorCode = e.getErrorCode();
String sqlState = e.getSQLState();
if (errorCode == 0x027C) {
// 表不存在
} else if (sqlState.startsWith("08")) {
// 连接相关
reconnect();
}
}
go
// Go
_, err := db.Query("SELECT * FROM bad_table")
if err != nil {
if taosErr, ok := err.(*taosError.Error); ok {
fmt.Printf("TDengine error: %d, %s\n", taosErr.Code, taosErr.Message)
}
}
4. 重试策略
可重试错误:
✓ 网络瞬断
✓ Leader 切换中
✓ 节点临时不可用
✓ 超时
✓ "Sync timeout"
不可重试错误:
✗ SQL 语法错误
✗ 表不存在
✗ 权限不足
✗ 数据类型不匹配
✗ 参数错误
重试模式:
指数退避:
第 1 次:100ms
第 2 次:200ms
第 3 次:400ms
最多 5 次
示例:
delay = 100
for attempt in range(5):
try:
return execute(sql)
except RetryableError:
sleep(delay / 1000)
delay *= 2
raise TimeoutError
5. 服务端故障恢复
节点重启恢复:
① 启动时检查 WAL
- 重放未持久化的写入
- 恢复内存表
② 加入集群
- 注册到 MNode
- 报告状态
③ VNode 副本同步
- RAFT 协议补齐落后日志
- 状态机一致后服务
VNode 故障恢复:
① Leader 失效检测(心跳超时)
② Follower 触发选举
③ 新 Leader 产生
④ 客户端重路由
⑤ 服务恢复(秒级)
数据块损坏:
① 校验失败检测
② 标记损坏
③ 从其他副本恢复
④ 严重情况报警
6. 内存/磁盘异常
OOM 处理:
① 内部限流
- 拒绝新请求
- 释放缓存
② OOM Killer
- 进程被杀
- systemd 重启
③ 重启恢复
- 重放 WAL
- 数据完整
磁盘满:
① 写入预检
- 检测剩余空间
- 不足则拒绝
② 错误码 0x80000B07 Disk full
③ 客户端处理
- 应用降级
- 告警通知运维
④ 运维清理
- 清旧日志
- 数据归档
- 扩容
7. 错误日志
日志位置:
/var/log/taos/taosdlog.0
错误格式:
时间 进程ID 级别 模块 函数 错误码 描述
示例:
2026-06-04 12:00:00 [12345] ERROR VND vnodeOpen
code:0x80000300 desc:vnode not exist
关键字搜索:
grep -i error /var/log/taos/taosdlog.0
grep "0x80000" /var/log/taos/taosdlog.0
调试模式:
ALTER DNODE 1 'debugFlag' '143';
# 临时启用 debug
ALTER DNODE 1 'debugFlag' '131';
# 改回 error+warn
8. 错误码查询
sql
-- 查所有错误码(系统表)
SELECT * FROM information_schema.ins_errors;
-- 部分版本支持
-- 命令行查询
# taos --help | grep error
-- 文档查询
# https://docs.taosdata.com/reference/error-code/
-- 源码定义
# include/util/taoserror.h
# 但本文不深入源码细节
代码示例
健壮的客户端封装
python
import taosws
import time
import logging
class RobustClient:
RETRYABLE_CODES = {
0x80000300, # node not available
0x80000310, # leader switch
0x80000316, # timeout
}
def __init__(self, dsn, max_retries=3):
self.dsn = dsn
self.max_retries = max_retries
self.conn = None
self._connect()
def _connect(self):
self.conn = taosws.connect(self.dsn)
def execute(self, sql):
last_err = None
delay = 0.1
for attempt in range(self.max_retries):
try:
return self.conn.execute(sql)
except taosws.QueryError as e:
last_err = e
if e.errno not in self.RETRYABLE_CODES:
raise # 不可重试
logging.warning(f"Retry {attempt+1}: {e}")
time.sleep(delay)
delay *= 2
except taosws.ConnectionError as e:
last_err = e
logging.warning(f"Reconnecting: {e}")
try:
self._connect()
except:
time.sleep(delay)
delay *= 2
raise last_err
监控错误统计
sql
-- 通过日志聚合(需 ELK 或类似)
-- 或扫描日志文件统计
-- 错误码分布
SELECT error_code, COUNT(*) AS cnt
FROM log_index
WHERE level='ERROR' AND ts > NOW - 1d
GROUP BY error_code
ORDER BY cnt DESC;
-- 客户端错误监控(应用层)
# 应用上报到 Prometheus / log 数据库
COUNTER tdengine_errors_total{code="...", db="..."}
性能考量
错误处理开销
| 场景 | 开销 |
|---|---|
| 正常路径 | 几乎为零 |
| 错误抛出 | 微秒级 |
| 异常解析 | 几十微秒 |
| 重试 + 退避 | 视延迟 |
重试导致放大
重试可能放大问题。建议:
- 限制重试次数
- 退避避免雪崩
- 监控重试率
- 熔断保护下游
FAQ
Q1: 错误码定义在哪里?
服务端:内核内部定义。
客户端:通常通过 SDK 头文件/常量定义获取。
文档:官方错误码列表。
Q2: 怎么区分可重试?
- 网络/超时类:可重试
- 业务错误(SQL/数据):不重试
- 节点状态变化:可重试
Q3: 怎么调试错误?
- 查错误码含义
- 查服务端日志(按时间)
- 启用 debug 日志
- 用 QID 串联客户端到服务端日志
Q4: 客户端连接断开自动恢复吗?
WebSocket 客户端通常内置重连。Native 需应用层处理。
Q5: 写入失败数据丢吗?
视失败时机:
- WAL 写入前失败:丢
- WAL 写入后失败:自动恢复
- 副本未达成共识:可能丢(少见)
建议应用层有写入确认+重试。
参考
系统构架篇
- 01-《TDengine 整体架构全景》
- 02-《集群拓扑深度解析》
- 03-《MNode 内部机制深度解析》
- 04-《RPC 通信层深度解析》
- 05-《VNode 生命周期》
- 06-《RAFT 共识协议》
- 07-《端到端的消息流》
数据模型
- 01-《数据库创建与参数详解》
- 02-《超级表/子表/普通表》
- 03-《支持数据类型深度解析》
- 04-《TDengine Tag 设计哲学与 Schema 变更机制》
- 05-《TDengine 虚拟表实现原理》
存储引擎
- 01-《TDengine 存储引擎概览》
- 02-《TDengine MemTable 深度解析》
- 03-《TDengine WAL 预写日志机制》
- 04-《TDengine 数据文件格式》
- 05-《TDengine Commit 与 Flush 机制 》
- 06-《TDengine Compaction 合并策略 》
- 07-《TDengine 数据保留与 TTL》
- 08-《TDengine 压缩编码机制》
- 09-《TDengine Cache 与 Last 查询加速》
- 10-《TDengine 逻辑计划生成》
查询引擎
- 01-《TDengine 查询引擎概览》
- 02-《TDengine SQL 解析与词法分析》
- 03-《TDengine 语义分析与 AST 重写》
- 04-《TDengine 逻辑计划生成》
- 05-《TDengine 物理计划生成》
- 06-《TDengine 扫描算子》
- 07-《TDengine 聚合算子》
- 08-《TDengine 连接算子》
- 09-《TDengine 排序、填充与投影》
- 10-《TDengine 分布式查询执行》
- 11-《TDengine EXPLAIN 与查询优化》
数据写入
- 01-《TDengine SQL INSERT》
- 02-《TDengine 无模式写入》
- 03-《TDengine STMT 写入》
- 04-《TDengine 写入内部流程》
- 05-《TDengine 数据更新删除》
数据订阅
- 01-《TDengine 数据订阅》
- 02-《TDengine 订阅 vs Kafka》
- 03-《TDengine TMQ 消费流程》
- 04-《TDengine 内部机制》
- 05-《TDengine TMQ 最佳实践》
预聚合
索引
SQL 语句
- 01-《TDengine DDL》
- 02-《TDengine DML SELECT》
- 03-《TDengine DML 函数完整参考》
- 04-《TDengine JOIN 完整语法》
- 05-《TDengine 窗口完整语法》
- 06-《TDengine 操作符与表达式》
- 07-《TDengine 系统表》
- 08-《TDengine SQL 与标准 SQL 差异》
客户端与连接器
- 01-《TDengine 的连接方式》
- 02-《TDengine C/C++ 连接器》
- 03-《TDengine java 连接器》
- 04-《TDengine Python 连接器》
- 05-《TDengine Go 与 Rust 连接器》
- 06-《TDengine Node.js 与 C# 连接器》
运维
- 01-《TDengine 部署指南》
- 02-《TDengine 配置详解》
- 03-《TDengine 监控系统》
- 04-《TDengine 备份与恢复》
- 05-《TDengine 版本升级》
- 06-《TDengine 加密使用指南》
安全
生态
- 01-《TDengine taosAdapter》
- 02-《TDengine taosX 与 Explorer》
- 03-《TDengine Grafana 集成》
- 04-《TDengine 第三方工具》
应用案例
- 01-《TDengine IoT 设备监控》
- 02-《TDengine 工业大数据与智能制造》
- 03-《TDengine 车联网与新能源汽车》
- 04-《TDengine 能源与电力监控》
- 05-《TDengine IT 运维与可观测性》
产品对比
内部机制
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。
