tdengine结合物联网平台落地
约 2124 字大约 7 分钟
2025-03-03
物联网平台一旦进入真实设备规模,时序数据就会立刻变成核心问题。
系统每天面对的不只是设备当前状态,还包括:
- 属性历史
- 行为上报
- 调试日志
- 在线状态变化
- 统计查询
如果这些数据全部压在传统关系库里,写入压力、查询成本和存储结构都会越来越难看。
所以联犀当前把 TDengine 作为时序数据核心执行层来使用。
这篇文章重点讨论两个问题:
- 物模型怎样映射到 TDengine。
- 高并发设备上报下,如何把写入成本压下来。
TDengine 在联犀里扮演什么角色
先说一个很重要的前提。
TDengine 在联犀里不是“另一套业务主库”,而是围绕时序数据承担专门职责。
它主要服务于:
- 设备属性历史
- 各类设备日志
- 时序统计查询
而设备主数据、产品定义、用户关系、项目关系这类强事务、强关系数据,仍然更适合放在关系型数据库中。
这也是为什么联犀不是把所有 IoT 数据都塞进时序库,而是让关系库和时序库按职责分工。
当前的宿主边界已经变了
早期很多物联网平台喜欢把网关、设备服务、时序写入拆成多个松散宿主。
联犀现在的 things 侧已经不再这么描述。
当前更准确的说法是:dmsvr 是设备管理、设备网关、MQTT 宿主和时序仓储的统一宿主。
这点很关键,因为它意味着:
- 设备接入主链路和时序落库距离更近
- 设备消息处理和属性历史写入可以在同一宿主内完成协同
- 不需要为了“把时序数据写入另一个服务”增加额外跳转
这并不是否认服务边界,而是承认高耦合、高吞吐链路放在一个宿主里更合理。
物模型为什么是时序设计的起点
物联网平台做时序设计,最容易走的弯路是先想数据库表,再想设备模型。
联犀的顺序正好反过来:先从物模型出发,再决定如何映射到时序结构。
原因很简单。
设备最终上报和查询的,是“属性”。
而属性本身就决定了数据是:
- 单值
- 结构体
- 数组
不同类型如果混成一种表结构,后续查询和扩展都很容易变得拧巴。
联犀当前的三种核心映射方式
1. 简单类型
像布尔、整数、浮点、枚举、时间戳、字符串这类简单属性,联犀当前采用“单值列 + 超级表模板”的方式。
这种设计的好处是:
- 一类属性结构足够稳定
- 写入成本低
- 查询时也容易做统一格式化
对设备侧来说,它上报的是一个属性值;
对时序库来说,则是写入到对应类型的超级表和子表中。
2. 结构体类型
有些属性天然包含多个字段,比如经纬度、复合环境状态等。
如果仍然强行拆成多个独立简单属性,业务理解和查询语义都会被破坏。
所以联犀当前对结构体类型采用“一个属性对应多列”的方式映射。
这样做的好处是:
- 字段语义清晰
- 查询时不需要再二次拼装多个属性
- 对整体属性的读写更自然
3. 数组类型
数组是最特殊的一类。
如果把整个数组直接作为一个不可拆的大值存储,会出现两个问题:
- 单个元素变化时也得整体重写。
- 想按某一位做查询或处理会很别扭。
联犀当前采用的是“数组元素拆位”的思路,也就是额外记录下标维度。
这样做以后,数组不再只是一个黑盒,而是可以按位置进行处理。
这类设计不是为了炫技,而是为了更贴近真实设备控制场景。
很多设备并不是整组状态一起变化,而是某个元素独立变化。
为什么会选择超级表思路
联犀当前选择超级表,不只是因为 TDengine 提供了这个能力,而是因为它非常适合“同类结构、大量实例”的物联网属性场景。
在一个产品下:
- 属性结构是稳定的
- 设备数量可能很多
- 每台设备都在写同类数据
这正适合“一个模板,多台设备实例化”的思路。
这样带来的直接收益包括:
- 表结构管理清晰
- 可以按产品、设备、属性类型组织数据
- 便于批量写入和统一查询
高并发写入的难点不只是数据库本身
很多人讲 TDengine 性能时,喜欢把重点全放在数据库吞吐能力上。
但平台真正跑起来以后,问题往往在链路的整体设计上。
设备高频上报时,真正的瓶颈通常来自:
- 单条同步写入过多
- 每次写入都走完整调试链路
- 大量小 SQL 无法合批
- 上游业务线程被数据库阻塞
所以联犀当前做的优化重点,并不是“换个驱动就结束”,而是把写入流程整体改成异步批量模式。
当前写入策略:taosWS + 异步批量聚合
联犀当前 TDengine 客户端默认使用 taosWS。
这只是第一步。
真正关键的是后面的两件事:
1. 单条写入先入队
业务侧先生成写入片段,放入异步通道,而不是立即同步提交到数据库。
2. 后台批量聚合
后台协程按时间窗口和数量阈值,把多条写入拼成批量 insert into 提交。
这个策略的价值非常明显:
- 降低了单条写入的固定成本
- 减少业务线程被数据库阻塞
- 更适合设备高频、分散上报的场景
对于物联网平台来说,这种优化往往比单纯讨论某个 SQL 的极限性能更有现实意义。
为什么还要区分调试日志与普通写入
物联网平台里时序数据不只有属性历史。
还有一类非常容易把系统拖重的数据,就是各类调试日志和链路日志。
联犀当前在异步写入层做了进一步分流,把普通写入和关闭 debug 的写入区分开。
它的意义在于:
- 日志量大时不至于继续放大调试开销
- 关键数据和低价值噪音数据可以走不同通道
- 让“为了观察系统”不至于反过来拖慢系统
查询侧为什么也要纳入统一体系
如果 TDengine 只是一个写入终点,那它迟早会变成孤岛。
联犀当前没有这么做。
除了设备仓储层直接查时序数据以外,datasvr 也已经开始承接 TDengine 查询执行能力。
这意味着:
- 时序查询不必永远靠专门仓储手写
- 可配置查询可以逐步覆盖时序场景
- 权限过滤模型可以继续复用
这一步很重要。
因为一个平台一旦把“关系库查询”和“时序库查询”做成完全不同的两套世界,后面维护成本会很高。
总结
联犀当前 TDengine 落地的核心,不是“会建几张超级表”,而是围绕物联网平台的真实约束做了一整套取舍:
- 从物模型出发设计时序映射,而不是先拍脑袋定表结构。
- 把简单类型、结构体、数组拆成不同映射策略。
- 让
dmsvr作为统一宿主,缩短设备链路到时序落库的距离。 - 用
taosWS + 异步批量聚合控制高并发写入成本。 - 让时序查询逐步进入统一的数据服务体系。
这套设计的目的从来不是“把 TDengine 用得最花”,而是让它真正成为物联网平台稳定、可维护、可扩展的一部分。
更新日志
2026/5/18 10:48
查看所有更新日志
43ef3-docs(blog): 新增后端与架构系列技术博客 18 篇,更新原有 7 篇于d4fa0-doc: 更换皮肤到最新版于ed359-doc于fcf7d-doc: 完善文档于f4017-doc: 完善文档于a6605-初始化于56ee0-初始化于
