TDengine 数据订阅 — Topic 与 Consumer 基础

分类 :6.数据订阅 TMQ | 篇章 :01 Topic 与 Consumer

适用版本:TDengine v3.x(v3.3.x / v3.4.x)

TDengine 内置的 TMQ(Time-series Message Queue)让数据库既是存储,也是消息总线。应用通过 Topic 订阅数据变化,无需额外部署 Kafka 即可获得"数据库 + 消息队列"双重能力。

核心概念速查表

概念 说明
Topic 订阅主题(基于 SQL 查询定义)
Consumer 消费者实例
Consumer Group 消费组(同组共享分区)
Offset 消费位点(VGroup 内序号)
Subscribe 订阅一个或多个 Topic
Commit 提交位点(标记已消费)
Rebalance 消费组成员变化时重新分配分区

详细解析

1. Topic 的三种类型

复制代码
① 列订阅(最常用):
   CREATE TOPIC topic_meters AS 
   SELECT ts, current, voltage FROM meters;
   
   - 订阅指定列的所有写入
   - 可附加 WHERE 过滤
   - 可订阅子集


② 超级表订阅:
   CREATE TOPIC topic_all AS STABLE meters;
   
   - 订阅整张超级表所有列
   - 包含所有子表的变化


③ 数据库订阅:
   CREATE TOPIC topic_db AS DATABASE test;
   
   - 订阅数据库内所有表的变化
   - 用于全库同步场景

2. Consumer 模型

复制代码
Consumer 抽象:

  Consumer Group: "etl_workers"
    Consumer-1 ─┐
    Consumer-2 ─┼─→ 共同消费 Topic
    Consumer-3 ─┘
    
  特点:
  - 同组消费者分摊 VGroup 分区
  - 每个 VGroup 同时只能被组内一个 Consumer 消费
  - 跨组互不影响(广播模式)
  
  
分区分配:
  Topic 在 N 个 VGroup 上有数据
  Consumer 组有 M 个成员
  分配:每个 Consumer 拿 N/M 个 VGroup
  
  如果 M > N:多余的 Consumer 空转
  如果 M < N:每个 Consumer 处理多个 VGroup

3. 订阅生命周期

复制代码
Consumer 完整生命周期:

  ① 配置 Consumer 参数:
     - group.id(必须)
     - auto.offset.reset(earliest/latest)
     - enable.auto.commit
     - msg.with.table.name
     
  ② 创建 Consumer 实例
  
  ③ Subscribe 一个或多个 Topic
  
  ④ Poll 循环:
     - 拉取消息
     - 处理业务逻辑
     - Commit Offset
     
  ⑤ Unsubscribe(可选)
  
  ⑥ Close Consumer


关键参数:
  group.id           // 消费组 ID
  auto.offset.reset  // earliest / latest / none
  enable.auto.commit // true / false
  auto.commit.interval.ms
  msg.with.table.name  // 消息中包含表名

4. Offset 与位点管理

复制代码
Offset 概念:

  每个 VGroup 维护一个递增序号
  Consumer 消费后 Commit Offset
  下次启动从 Committed Offset + 1 继续

  
位点策略:
  auto.offset.reset = "earliest"
    → 首次订阅从最早位置开始
    
  auto.offset.reset = "latest"
    → 首次订阅从最新位置开始(之前的数据跳过)
    
  auto.offset.reset = "none"
    → 没有位点则报错


自动 vs 手动 Commit:
  自动:定期自动 Commit(简单但可能丢/重复)
  手动:业务确认后 Commit(精确控制)

5. Rebalance 机制

复制代码
Rebalance 触发场景:
  - 新 Consumer 加入组
  - 现有 Consumer 离开(崩溃/关闭)
  - Topic 分区变化(新增 VGroup)

  
Rebalance 过程:
  ① 协调者检测变化
  ② 通知所有 Consumer 暂停消费
  ③ 重新分配分区
  ④ 各 Consumer 获取新的 VGroup 列表
  ⑤ 从 Committed Offset 继续消费

  
对应用的影响:
  - 短暂停顿(毫秒~秒级)
  - 未 Commit 的消息可能被另一 Consumer 重新处理
  - 建议设计为幂等消费

6. 消息内容

复制代码
消费到的消息结构:

  Message {
    topic: "topic_meters",
    vgroup_id: 3,
    offset: 12345,
    table_name: "d001",   // 若启用 msg.with.table.name
    columns: ["ts", "current", "voltage"],
    rows: [
      [T1, 25.3, 220],
      [T2, 25.5, 221],
      ...
    ]
  }

  
消息特点:
  - 一次 Poll 可返回多行(批量)
  - 同一消息内可能来自不同子表
  - 已写入 WAL 的数据才可订阅
  - 时间顺序按写入顺序(非业务 ts)

7. 与 Kafka 的对比

特性 TDengine TMQ Kafka
数据来源 数据库写入直接产生 应用显式 produce
数据保留 与数据库共用存储 独立 Topic 文件
过滤能力 Topic SQL 内置过滤 应用层过滤
Schema 强类型 字节流
部署 数据库内置,无额外组件 独立集群
适用 时序数据 ETL/CDC 通用消息

8. 应用场景

复制代码
① 数据 ETL:
   订阅原始数据 → 清洗 → 写入下游
   
② 实时计算:
   订阅指标数据 → 聚合 → 报警
   
③ 数据同步:
   订阅整库 → 同步到异地灾备
   
④ 数据归档:
   订阅冷数据 → 备份到对象存储
   
⑤ 流计算上游:
   流计算引擎订阅 Topic 作为输入源

代码示例

Python 消费者

python 复制代码
from taos.tmq import Consumer

consumer = Consumer({
    "group.id": "etl_group",
    "auto.offset.reset": "earliest",
    "td.connect.user": "root",
    "td.connect.pass": "taosdata",
    "enable.auto.commit": "false",
})
consumer.subscribe(["topic_meters"])

try:
    while True:
        msg = consumer.poll(timeout=1.0)
        if msg is None:
            continue
        for block in msg:
            for row in block:
                print(row)
        consumer.commit()
finally:
    consumer.close()

Java 消费者

java 复制代码
Properties props = new Properties();
props.setProperty(TMQConstants.BOOTSTRAP_SERVERS, "127.0.0.1:6030");
props.setProperty(TMQConstants.GROUP_ID, "etl_group");
props.setProperty(TMQConstants.ENABLE_AUTO_COMMIT, "false");

try (TaosConsumer<Meter> consumer = new TaosConsumer<>(props)) {
    consumer.subscribe(Collections.singletonList("topic_meters"));
    while (running) {
        ConsumerRecords<Meter> records = consumer.poll(Duration.ofMillis(1000));
        for (ConsumerRecord<Meter> r : records) {
            process(r.value());
        }
        consumer.commitSync();
    }
}

管理 Topic

sql 复制代码
-- 创建
CREATE TOPIC topic_meters AS SELECT ts, current FROM meters;

-- 查看
SHOW TOPICS;

-- 查看 Consumer Group 状态
SELECT * FROM information_schema.ins_subscriptions;

-- 删除
DROP TOPIC topic_meters;

性能考量

消费性能

因素 影响
单 Consumer 拉取批量 大批量提升吞吐
并发 Consumer 数 与 VGroup 数匹配最优
处理逻辑耗时 直接限制吞吐
Commit 频率 频繁 Commit 影响性能

配置建议

场景 配置
低延迟实时 poll 短间隔 + 频繁 commit
高吞吐 ETL 大批量 + 异步 commit
严格一次 手动 commit + 业务幂等

FAQ

Q1: 订阅历史数据吗?

可以。设置 auto.offset.reset=earliest 从 WAL 中可保留范围的最早数据开始消费。但 WAL 有保留期限。

Q2: 一个 Topic 能多少 Consumer 同时消费?

同组内最多 = VGroup 数。再多的 Consumer 会空闲。跨组(不同 group.id)则无限制。

Q3: 消费失败如何重试?

不 Commit Offset 即可。下次 Poll 仍能拿到该消息。注意:业务必须幂等。

Q4: Topic 删除后消费者会怎样?

Poll 返回错误。需要重新订阅其他 Topic 或关闭 Consumer。

Q5: TMQ 与流计算关系?

流计算本质上是"内置消费 + 计算 + 写入"。可以用 Topic 作为流计算的输入,实现外部应用可见的中间数据。

参考

系统构架篇

数据模型

存储引擎

查询引擎

数据写入

关于 TDengine

TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。