小T导读:在数字化转型加速推进的今天,抽水蓄能电站在智能化建设中面临着数据管理成本高、服务分散、数据孤岛严重、边缘传输受限等一系列挑战。这不仅抬高了企业的运维成本,也阻碍了电厂无人化、智能化的深入发展。为破解难题,南方电网储能股份有限公司信息通信分公司联合华为与涛思数据,共建云边协同数据湖,打造统一的数据平台。本文将聚焦平台的落地建设过程,深入剖析 TDengine 在其中的关键作用,包括数据建模、选型调研、边云同步、接入方式选择等实践亮点。
边云协同的数据湖方案
该数据湖平台以 TDengine 为时序数据底座,支撑了南网储能的抽水蓄能集控系统、智慧储能运营平台、大数据平台、电化学储能安全管理平台、电化学储能电站安全运行管理平台、物联网平台和数字孪生系统等 7 个核心应用系统。目前,平台已接入超 210 万台设备的实时数据,且随着应用的深化建设,接入设备数量将会持续增长。
在主站侧,基于 ROMA 物联网平台与 TDengine 的集成,平台实现了水工水情、设备台账、天气监测等 24 类数据的集中接入,并对外发布了超过 200 个数据接口,支持发电抽水启动次数、储能站充放电量、设备异常与检修等多种业务数据的统一管理。该平台为发电生产日报、智慧园区管理、视频云、基建数据分析、生产运行支持系统等多个场景提供了稳定、高效的数据支撑。
在场站侧,平台部署了华为 FusionCube 超融合一体机,结合 ROMA Site 物联接入组件和 TDengine,实现了现场数据的就地采集与存储,突破了传统边缘数据单向传输的限制。边缘侧数据可同步至主站平台,统一进行分析与应用,有力支持电厂无人化、智能化的建设进程。同时,平台构建了标准化物模型,逐步推动监控系统与原厂数据的解耦,降低了对特定厂商的依赖,增强了系统的灵活性与可扩展性。

整体方案依托华为与涛思数据提供的软硬件平台,构建云边协同的数据湖与级联架构,统一发电物模型与测量模型,不仅大幅节省了硬件资源,还将业务效率提升了一倍,为数字电站提供了快速接入与分析能力,显著提升经济效益。通过 ICT 技术与电力系统的融合,打造智能化、可视化的协同平台,构建标准化的数字生产体系,推动电力系统迈向高效、智能的运行模式,为行业数字化转型提供坚实支撑。
时序数据库选型考虑
在数据湖的底座选型当中,每一个候选产品都很优秀。要从中挑选出最适合我们的时序数据库,可谓是一项“百里挑一”的精细工作—— 既要从数据存储性能、查询效率、集群扩展性、成本适配性、生态兼容性等多个维度抽丝剥茧,又要在“各有所长”的竞争格局中精准锚定与业务场景深度契合的“最优解”;既要避免因功能过剩造成资源浪费,也要防止能力短板埋下性能隐患。恰如在琳琅满目的兵器库中挑选一柄最称手的利刃,必须以“锱铢必较”的严谨态度完成这场技术选型的“大考”。
而 TDengine 作为国内领先的时序数据库,凭借其出色的硬实力与优秀的软素质,最终脱颖而出,成为我们可信赖的重要合作伙伴。下面是 TDengine 与同时参与调研的某时序数据库的对比详情:
| TDengine 时序数据库 | 某时序数据库 | |
| 产品使用情况 | 23.9K 的 Star 和 100w 的运行实例 | 10k 的 Star,运行实例未透露 |
| 读写性能表现 | 10x 于同类数据库的读写性能 | 数倍于传统关系库,具有一定的性能优势 |
| 产品易用性 | 以设备为本的设计,以物建模的建模理念。兼容 SQL 92语法 | 沿用了工控行业的时间线设计类 SQL 方式 |
落地实践
在建设和运维过程中,我们经历了各种挑战与困难。最终,在涛思数据团队的全力协助下,项目顺利落地投入生产,我们也摸索出了一套 TDengine 使用“心法”。在这里与大家一起分享下。
适配多样化业务的实践
在构建以 TDengine 为底座的数据湖的过程中,我们发现数据湖承载的业务纷繁复杂。如果用单一的建模方式来使用,必然会导致后续运维过程中的各种瓶颈。因此我们对业务的数据情况进行了细分梳理,按照以下维度进行区分:
在构建以 TDengine 为底座的数据湖过程中,我们发现数据库所承载的业务场景复杂多样。如果采用单一的建模方式,势必在后续运维中面临性能瓶颈和管理难题。为此,我们对各类业务的数据特征进行了细致梳理,并从以下几个关键维度进行分类:
- 设备数量:该业务接入的设备数,少则几百,多则几万。
- 数据量级:该业务存储的数据量,少则几亿条,多则数千亿条
- 采样频度:时间频度涵盖秒级到分钟级
- 字段长度:字段从单列模型,到几百列的复杂模型
按照以上的情况,结合实际业务需求,我们将场景划分为三类模型:
- 多表中频类型:表量较多,写入频率中等,存储数据量大
- 多表低频类型:表量较多,写入相对低频,存储数据较少
- 少表高频类型:表量较少,高频写入,存储数据量较多

TDengine 作为最佳时序数据存储的最佳实践,在设计上,通过对 database 进行不同的参数设置,来灵活支持不同的业务类型。
作为时序数据存储的最佳实践,TDengine 在设计上通过对 database 进行不同的参数配置,灵活支持多种业务类型。常用参数包括:
- vGroups:数据库中初始 vgroup 的数量
- duration:数据文件存储数据的时间跨度。缺省值为 10d,取值范围 [60m, 3650d]
- minRows:文件块中记录的最小条数,默认为 100 条
- buffer:一个 vnode 写入内存池大小,单位为 MB,默认为 256,最小为 3,最大为 16384。
- stt_trigger:表示落盘文件触发文件合并的个数
- 对于少表高频写入场景,此参数建议使用默认配置;
- 对于多表低频写入场景,此参数建议配置较大的值。
此外,TDengine 还提供更多可调参数,可根据具体需求在官网查阅完整文档:数据库参数。
基于“不同业务使用不同的 database”的设计原则,我们按业务类型进行针对性参数配置,从而实现更高的性能匹配与资源利用效率。

在实际应用中,我们逐步总结出了几条 TDengine 建库的“心法”:
- 表量越大 vgroups 要配的越多
- 写入频率越高 buffer 配置要越大
- 低频写入场景下,需要合理配置 minRows
- 多表+低频场景,建议单独调优 stt_trigger
这些原则并非一蹴而就,而是我们在多次调优、不断实践中摸索出来的经验积累。尤其是在涛思数据架构师肖波老师的专业指导下,我们结合三类业务模型,成功构建并稳定运维了整个数据湖平台。
多业务建模的实践
TDengine 推崇的产品理念——“一个设备一张表”,可谓高度贴合实际的物联网与工业应用场景。在这一理念指导下,建模不仅更贴近数据本质,也带来了诸多优势:
- 同一时间采集的数据可以存入一个宽表,写入效率更高
- 写一个设备就像一个对象实例化,每次实例化就产生一条数据
- 多个设备的查询,可以变成对多个设备对象的查询,无需转换成二维的表格思想
例如我们有一类温湿度传感器设备,设备以批量方式同时上报温度与湿度数据。我们便采用了如下“宽表”的建模方式:
| 列名 | 类型 | 备注 | |
| 采集量列 | co2 | FLOAT | 二氧化碳浓度 |
| pm2_5 | FLOAT | PM2.5 | |
| humidity | FLOAT | 湿度 | |
| temperature | FLOAT | 温度 | |
| 标签列 | device_id | VARCHAR(64) | 设备ID |
| device_name | NCHAR(250) | 设备名称 | |
| device_alias_name | NCHAR(250) | 设备别名 | |
| device_type | VARCHAR(64) | 设备类型 | |
| device_model | NCHAR(64) | 设备型号 | |
| …… | …… | …… | |
| building_name | NCHAR(100) | 所属建筑名称 |
在这类型情况中,因为采集值是同时采集,因此这种情况是100%命中“一个设备一张表”。基于此原则,我们解决了 80% 的建模问题。但是在时间戳不一致(采集值非同时采集)的情况下,这种情况会导致表中的数据出现大量的 NULL 值,这将会在使用上带来:
在这类采集值“同时上报”的场景中,“一个设备一张表”的建模理念可以说是 100% 契合。基于这一原则,我们成功解决了约 80% 的建模需求。但是,在部分采集项的时间戳不一致、即采集值并非同时上报的场景下,若仍使用宽表建模,就会出现大量 NULL 值,带来以下问题:
- 数据质量存在二义性:NULL 值无法确定是采集为 NULL 还是未写入
- 数据处理性能浪费:查询的时候总需要对 NULL 值做 FILL 插值处理,增加额外开销
针对这一问题,我们对“一个设备一张表”的原则进行了细化,提出“同一时间采集一张表”的建模策略。以某业务系统为例,若以宽表建模,该表最多可达 371 列,下面是其中的一部分字段示例:
| 列名 | 类型 | 备注 | |
| 采集量列 | 1Chiller_Chilled_Water_Return_Temperature | FLOAT | 1号冷机冷冻水回水温度 |
| 1Chiller_Chilled_Water_Supply_Temperature | FLOAT | 1号冷机冷冻水供水温度 | |
| 1Chiller_Condensing_Water_Return_Temperature | FLOAT | 1号冷机冷却水回水温度 | |
| 1Chiller_Condensing_Water_Supply_Temperature | FLOAT | 1号冷机冷却水供水温度 | |
| 2Chiller_Chilled_Water_Return_Temperature | FLOAT | 2号冷机冷冻水回水温度 | |
| 2Chiller_Chilled_Water_Supply_Temperature | FLOAT | 2号冷机冷冻水供水温度 | |
| 2Chiller_Condensing_Water_Return_Temperature | FLOAT | 2号冷机冷却水回水温度 | |
| 2Chiller_Condensing_Water_Supply_Temperature | FLOAT | 2号冷机冷却水供水温度 | |
| …… | …… | …… | |
| 标签列 | device_id | VARCHAR(64) | 设备ID |
| device_name | NCHAR(250) | 设备名称 | |
| device_alias_name | NCHAR(250) | 设备别名 | |
| …… | …… | …… |
在该场景中,采集侧数据为分批上报,时间戳并不一致。为了更灵活地适配这类非同步采集的业务,我们将原本的大宽表调整为单列模型,从而有效规避了 NULL 值带来的数据质量与处理性能问题。
这背后也反映了一个常见的使用习惯:大宽表在实际业务中很少直接查询整表。因此我们选择将多个指标按需分表,在多指标分析时通过查询时再进行 Join,用“后期的计算成本”换取“前期的数据写入与管理便利”。
同时,随着 TDengine 对虚拟表的支持愈加完善,后期在需要整合宽表结构时,也可以通过虚拟表实时拼接多个子表,在保持灵活建模的同时,兼顾查询的统一性与实时性。
升级零成本的架构实践
在经历了丰富的使用细节与业务场景后,我们深刻体会到“最佳实践”的妙处。尤其面对业务方各种不同的使用场景,如果缺乏统一的规范和约束,往往会带来性能下降甚至系统不稳定的问题。
TDengine 官方提供了多种连接方式,包括 Native、RESTful 和 WebSocket,各有特点。这里也想和大家分享一下我们在数据湖项目中,关于连接方式选型的一些经验。
Native 方式
Native 连接方式非常适合在建设期使用。只需搭建一个 3 节点的集群,配合 Native 接入方式,就可以实现一个多副本 + 高可用 + 自动切换的生产环境。这为我们在数据湖项目初期的探索提供了极大便利,业务应用几乎无需做额外处理,部署简单,运行稳定,省心高效。

但随着接入的数据源和业务方不断增加,数据湖进入试运营阶段,系统稳定性和升级成本逐渐成为新的主要矛盾,而集群搭建的便利性则退居其次。在这个阶段,我们开始重新思考连接方式的选择,并探索更适合大规模接入与运维的方案。
RESTful 方式
在 WebSocket 支持推出之前,RESTful 是我们看到的最优选择。
由于多个上游业务方要求 7×24 小时连续运行,数据湖也必须具备同样的服务能力。然而,任何系统都不可避免地需要升级维护,我们既希望系统稳定,又希望具备高可用性,这对架构提出了更高要求。
TDengine 支持在三位版本号一致的情况下滚动升级,客户端可不升级;但若版本号前三位不一致,就必须停机升级,并同步更新应用端的 taosc。为了解决这一问题,我们将接入方式从 Native 切换为 RESTful,并通过负载均衡器转发请求。这样一来,在跨版本升级时也无需修改应用端配置,故障切换也交由负载均衡器处理,既保障了系统的可用性,又保持了应用端开发的简洁性。

在逐步演进为以 RESTful 为主的访问方式后,我们的大多数 bug 修复场景都可以通过服务端滚动升级完成,无需改动应用端代码,大大降低了业务方的使用和维护成本。这种“零成本升级”的方式,对接入方来说极为友好。随着业务进入齐头并进的发展阶段,多个场站陆续接入并投入运行,系统对稳定性与升级灵活性的需求也持续增长。
不过,受历史因素影响,仍有部分应用采用 Native 接入方式。为此,TDengine 在 3.3.6.x 版本中专门推出了一个新特性:通过 C/C++ WebSocket 进行“mock”升级,实现零代码平滑迁移到 WebSocket,彻底实现了客户端零成本升级。
WebSocket 方式
WebSocket 是目前官方最推荐的访问方式,兼顾了版本兼容性与高性能,尤其适用于需要长期演进和灵活运维的业务系统。
在我们的实践中,WebSocket 的主要作用是替代原有的 Native 接入方式。下面,我们将分享这一替代方案的核心原理,供大家参考使用。
首先来看依赖关系:我们的部分应用是通过 Python 和 C++ 调用 TDengine 的 Native 接口,依赖结构如下:

通过 libtaos.so 的多层软链机制,应用程序最终调用的是版本号为 libtaos.so.3.3.4.7 的动态链接库(其中 3.3.4.7 为当前使用的 TDengine 版本),并通过 TCP 协议与集群进行通信。
而在 TDengine 3.3.6.x 版本中,官方做了一项特别的设计,让我们能够在无需更改 API 调用逻辑的前提下,就可以将连接方式从 Native 切换为 WebSocket。其底层依赖原理如下:

在原本的 libtaos.so 中,官方新增了一个判断机制,使得只要满足以下任一条件,底层调用就会从原本的 libtaosnative.so(Native)切换为 libtaosws.so(WebSocket):
- 条件 1:在初始化阶段增加调用 taos_options(
TSDB_OPTION_DRIVER, "websocket“) - 条件 2:如果之前在调用
taos_connect() 函数传入的port值为0时,则不用修改;如果传入的 port 值为 6030 时,修改成 6041 或 0
满足上述任意一条后,重新编译并链接引用库,即可实现无感切换为 WebSocket 接入。
通过这一机制,我们在升级到 TDengine 3.3.6.x 版本后,原有的 Native 应用也顺利过渡为基于 HTTP 协议的 WebSocket 访问方式,实现了真正意义上的客户端零代码升级。
写在最后
回顾过去一年多的数据湖建设历程,TDengine 的表现无疑验证了当初的正确选型。在可预见的发展路径中,我们也将从多个维度继续与 TDengine 深度合作,共同探索更多可能:
- 在应用上探索更多 AI 零门槛的落地策略,赋能业务部门探索时序数据的价值
- 在架构上探索更加稳定的架构方案,实现线上零故障、零升级、零运维的数据湖时序数据库底座
我们相信,TDengine 不仅是当前的选择,更是未来可持续发展的关键一环。
关于南网储能通信分公司
南方电网储能股份有限公司信息通信分公司是南方电网储能股份有限公司的分公司,专注于软件和信息技术服务领域。信息通信分公司作为南网储能的重要组成部分,承担着推动储能行业数字化转型的使命。公司专注于开发和应用先进的信息技术,为储能电站和新型储能站的建设、运营提供技术支持和服务。其业务涉及通信运行管控系统的开发,包括综合监视及资源管理模块的建设,以实现信息、通信和机房管控的全面融合。
作者:南网储能公司


























