推模式与拉模式
数据分发的第一层决策是推(Push)还是拉(Pull)。拉模式下,消费方按需查询时序数据库获取最新数据,查询触发与数据更新解耦。推模式下,存储引擎在数据写入后主动将数据推送至订阅方,消费方被动接收。
工业实时告警场景对延迟敏感,端到端延迟要求通常为秒级以内。拉模式的延迟取决于轮询周期,轮询间隔1秒即引入平均0.5秒延迟,且轮询在高频场景下产生大量空查询(无新数据时的无效请求)。推模式在数据写入后立即分发,延迟主要由网络与序列化决定,通常为数十毫秒。
拉模式并非没有价值。实时看板这类场景,前端页面刷新周期本就为秒级至分钟级,采用拉模式配合增量查询(查询上次读取时间点之后的数据)即可满足,且实现简单、无需维护长连接。当消费方数量大且刷新频率低时,拉模式的服务端压力更可控。
选择的判断依据是延迟要求、消费方数量、数据更新频率三者的组合。低频更新、大量消费方、容忍秒级延迟,拉模式占优;高频更新、中等消费方、要求亚秒级延迟,推模式占优。工业场景往往需要两者并存——告警用推,报表用拉。
消费组与偏移量管理
推模式的分发需要一个可靠的状态跟踪机制,否则消费方重启、断连、重复消费的问题无法定位。核心机制是消费组(Consumer Group)与偏移量(Offset)。
消费组是一组逻辑上等价、共同消费同一数据流的消费者。同一消费组内的多个消费者分摊分区(Partition),每个分区只被组内一个消费者消费,实现并行消费且不重复。不同消费组之间相互独立,各自维护自己的消费进度,同一份数据可被多个消费组重复消费——告警系统与数据同步系统各是一个消费组,互不干扰。
偏移量记录消费组在每个分区上已消费到的位置。偏移量提交(Commit)策略影响可靠性:自动提交按固定间隔提交,实现简单但可能重复消费(提交前崩溃);手动提交由消费方在正确处理数据后提交,可靠性高但需要消费方管理提交时机。工业场景中,告警消费方通常采用手动提交以确保告警不丢失,数据同步消费方可以接受少量重复(幂等写入可消重)。
提交策略 | 可靠性 | 重复风险 | 吞吐影响 | 适用消费方 |
自动提交 | 中 | 提交间隔内崩溃则重复 | 低开销 | 报表、看板 |
手动提交 | 高 | 几乎无丢失 | 略有开销 | 告警、计费 |
事务提交 | 高 | 与外部系统一致 | 开销较高 | 数据同步 |
不提交 | 低 | 每次重启从头或从最新 | 最低 | 一次性任务 |
背压处理
推模式的风险在于生产速率与消费速率失配。当数据写入速率持续高于消费方处理速率时,未处理消息在服务端或消费方内存中堆积,最终导致内存溢出或服务不可用。这就是背压(Back Pressure)问题。
背压的处理策略有三类。丢弃策略在缓冲溢出时丢弃最旧或最新的消息,适用于可容忍丢失的监控数据。限流策略在消费方滞后时降低推送速率,将压力反传给生产侧,适用于数据完整性要求高的场景。缓冲策略扩大队列容量,但这只是推迟问题而非解决,队列不可能无限增长。
消费方滞后的检测依赖消费位点(Lag)监控。Lag等于分区最新偏移量与消费组已提交偏移量之差,持续增长的Lag意味着消费方处理能力不足。运维系统需要对Lag设置告警阈值,及时识别消费瓶颈。
工业场景的背压策略需要按数据等级区分。安全相关的告警数据不能丢弃,应限流并触发告警;常规监测数据可以丢弃最旧数据;诊断数据可以采用缓冲策略。分级策略比单一策略更符合工业场景的数据价值差异。
与消息队列的差异化定位
工业场景已有的分发方案是消息队列——Kafka用于数据管道,EMQX/Mosquitto用于设备侧MQTT通信。数据订阅与消息队列在功能上存在重叠,但定位不同。
消息中间件(Kafka/EMQX)是独立系统,数据需要先写入消息队列再分发,且消息队列本身通常不承担长期存储职责(Kafka可短期存储,但查询能力弱)。数据订阅是时序数据库的内置能力,数据写入数据库后由数据库内部分发,省去了向外部队列同步的环节,同时保留了长期存储与SQL查询能力。
两者的衔接方式是”数据库订阅+消息队列”混合。设备数据经MQTT接入EMQX,EMQX通过桥接(Bridge)写入数据库,应用侧订阅数据库获取实时数据,或从Kafka获取。这一架构中消息队列承担设备接入与协议适配,数据库承担存储与结构化订阅。
维度 | 消息队列(Kafka/EMQX) | 数据库内置订阅 |
定位 | 数据管道/设备接入 | 存储+分发一体化 |
持久化 | 短期/可配置 | 长期结构化存储 |
查询能力 | 弱(仅偏移量读取) | SQL查询+订阅 |
协议适配 | MQTT/Kafka原生 | 数据库协议 |
重复消费 | 多消费组独立 | 多消费组独立 |
部署复杂度 | 独立运维 | 随数据库运维 |
时序数据库的数据订阅能力
TDengine的数据订阅功能(TMQ)提供了数据库内的实时分发机制。数据写入后,订阅方通过消费组接收增量数据流,偏移量由系统管理,支持订阅新写入的数据而非全量历史。
TMQ的订阅粒度可以按超级表、子表或数据库设定。按超级表订阅意味着消费方能收到该类型下所有设备的数据,按子表订阅则精确到单个设备。工业场景中,”订阅某台设备的全部测点”或”订阅某类设备的特定指标”是常见需求,细粒度订阅减少了消费方过滤数据的开销。
与Kafka的定位差异在于TMQ的订阅数据来自数据库内部,省去了入库与分发两套系统的同步。对于已经使用TDengine存储工业数据的场景,采用内置订阅可以简化架构——数据一份写入,存储与分发共用同一份数据,避免了两套系统的偏移量与一致性对齐问题。
结语
数据订阅的价值在于解耦数据生产与消费,让写入端和读取端独立演进。工业场景的选择不是”订阅还是消息队列”的二元问题,而是根据延迟要求、可靠性等级、消费方数量做组合。从架构演进看,数据库内置订阅与消息队列的分工正在清晰化——消息队列负责设备侧的海量接入与协议适配,数据库订阅负责已入库数据的实时分发与结构化查询。TDengine的TMQ能力使工业数据平台在存储与分发之间的边界更模糊,也让一份数据同时服务于告警、看板与同步成为可能。

























