TDengine Go 与 Rust 连接器 — 高性能异步访问

分类 :11.客户端与连接器 | 篇章 :05 Go/Rust 连接器

详情

Go 和 Rust 连接器都是 TDengine 高性能场景的常用选择,常用于编写数据采集网关、流处理服务、TaosX 插件。本文统一讲解两者用法。

速查表

维度 Go Rust
包名 driver-go taos / taos-ws
接口 database/sql sqlx / 异步
Native taosSql taos (libtaos)
WebSocket taosWS taos-ws
REST taosRestful taos-ws (兼容)
异步 goroutine tokio

Go 连接器详解

1. 安装

bash 复制代码
go get github.com/taosdata/driver-go/v3

2. 三种 Driver

go 复制代码
import (
  "database/sql"
  
  // Native
  _ "github.com/taosdata/driver-go/v3/taosSql"
  
  // WebSocket
  _ "github.com/taosdata/driver-go/v3/taosWS"
  
  // REST
  _ "github.com/taosdata/driver-go/v3/taosRestful"
)


// 连接字符串
// Native:    user:pass@tcp(host:6030)/db
// WebSocket: user:pass@ws(host:6041)/db
// REST:      user:pass@http(host:6041)/db


db, err := sql.Open("taosWS", 
  "root:taosdata@ws(localhost:6041)/test")

3. 基本 CRUD

go 复制代码
package main

import (
  "database/sql"
  "fmt"
  "log"
  _ "github.com/taosdata/driver-go/v3/taosWS"
)

func main() {
  db, err := sql.Open("taosWS",
    "root:taosdata@ws(localhost:6041)/")
  if err != nil { log.Fatal(err) }
  defer db.Close()
  
  // DDL
  _, _ = db.Exec("CREATE DATABASE IF NOT EXISTS test")
  _, _ = db.Exec("USE test")
  _, _ = db.Exec(`
    CREATE STABLE IF NOT EXISTS meters (
      ts TIMESTAMP, current FLOAT, voltage INT
    ) TAGS (location VARCHAR(32))
  `)
  
  // INSERT
  _, _ = db.Exec(`
    INSERT INTO d001 USING meters TAGS('Beijing') 
    VALUES (NOW, 25.3, 220)
  `)
  
  // SELECT
  rows, err := db.Query("SELECT * FROM meters LIMIT 10")
  if err != nil { log.Fatal(err) }
  defer rows.Close()
  
  for rows.Next() {
    var ts string
    var current float32
    var voltage int
    var location string
    rows.Scan(&ts, &current, &voltage, &location)
    fmt.Printf("%s %.2f %d %s\n", ts, current, voltage, location)
  }
}

4. STMT2 高性能写入

go 复制代码
import "github.com/taosdata/driver-go/v3/ws/stmt"

config := stmt.NewConfig("ws://localhost:6041/", 0)
config.SetConnectUser("root").SetConnectPass("taosdata")

connector, _ := stmt.NewConnector(config)
stmtH, _ := connector.Init()

stmtH.Prepare("INSERT INTO ? USING meters TAGS(?) VALUES(?, ?, ?)")

// 批量绑定
params := []*stmt.TaosStmt2BindData{...}
stmtH.Bind(params)
stmtH.Exec()
stmtH.Close()

5. TMQ 订阅

go 复制代码
import (
  "github.com/taosdata/driver-go/v3/ws/tmq"
)

config := tmq.NewConfig("ws://localhost:6041/", 0)
config.SetGroupID("my_group")
config.SetAutoOffsetReset("earliest")
config.SetConnectUser("root")
config.SetConnectPass("taosdata")

consumer, _ := tmq.NewConsumer(config)
consumer.Subscribe([]string{"my_topic"})

for {
  msg, _ := consumer.Poll(time.Second)
  if msg == nil { continue }
  
  // 处理消息
  for _, blockInfo := range msg.Data {
    // blockInfo.TableName, blockInfo.Data
  }
  
  consumer.Commit()
}

consumer.Close()

Rust 连接器详解

6. 依赖

toml 复制代码
[dependencies]
taos = { version = "0.x", features = ["ws"] }
tokio = { version = "1", features = ["full"] }

7. 基本用法

rust 复制代码
use taos::*;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // 连接(WebSocket)
    let dsn = "taosws://root:taosdata@localhost:6041/test";
    let taos = TaosBuilder::from_dsn(dsn)?.build().await?;
    
    // DDL
    taos.exec("CREATE DATABASE IF NOT EXISTS test").await?;
    taos.exec("USE test").await?;
    taos.exec(
      "CREATE STABLE IF NOT EXISTS meters \
       (ts TIMESTAMP, current FLOAT, voltage INT) \
       TAGS (location VARCHAR(32))"
    ).await?;
    
    // INSERT
    taos.exec(
      "INSERT INTO d001 USING meters TAGS('Beijing') \
       VALUES (NOW, 25.3, 220)"
    ).await?;
    
    // SELECT
    let rows = taos.query("SELECT * FROM meters LIMIT 10").await?;
    
    use futures::TryStreamExt;
    let mut stream = rows.rows();
    while let Some(row) = stream.try_next().await? {
        for (name, value) in row {
            println!("{}: {:?}", name, value);
        }
    }
    
    Ok(())
}

8. STMT2 与 TMQ

rust 复制代码
// STMT2
use taos::sync::*;

let mut stmt = Stmt2::init(&taos, &Stmt2Option::default())?;
stmt.prepare("INSERT INTO ? USING meters TAGS(?) VALUES(?, ?, ?)")?;

let tbnames = vec!["d001"];
let tags = vec![vec![Value::VarChar("Beijing".into())]];
let cols = vec![vec![
    ColumnView::Timestamps(vec![1717488000000].into()),
    ColumnView::Floats(vec![25.3].into()),
    ColumnView::Ints(vec![220].into()),
]];

stmt.bind(&tbnames, &tags, &cols)?;
stmt.execute()?;


// TMQ
use taos::tmq::*;

let tmq = TmqBuilder::from_dsn(
    "taosws://root:taosdata@localhost:6041?group.id=my_group"
)?.build().await?;

tmq.subscribe(["my_topic"]).await?;

while let Some(message) = tmq.recv().await? {
    println!("{:?}", message);
    tmq.commit(message).await?;
}

代码示例

Go 数据采集服务

go 复制代码
package main

import (
  "database/sql"
  "log"
  "time"
  
  _ "github.com/taosdata/driver-go/v3/taosWS"
)

type DataPoint struct {
  Device   string
  Ts       time.Time
  Current  float32
  Voltage  int
}

func main() {
  db, _ := sql.Open("taosWS",
    "root:taosdata@ws(localhost:6041)/iot")
  defer db.Close()
  
  // 准备 schema
  setupSchema(db)
  
  // 接收数据并写入
  dataChan := make(chan DataPoint, 10000)
  go collectData(dataChan)
  
  batch := make([]DataPoint, 0, 1000)
  ticker := time.NewTicker(time.Second)
  
  for {
    select {
    case point := <-dataChan:
      batch = append(batch, point)
      if len(batch) >= 1000 {
        flushBatch(db, batch)
        batch = batch[:0]
      }
    case <-ticker.C:
      if len(batch) > 0 {
        flushBatch(db, batch)
        batch = batch[:0]
      }
    }
  }
}

func flushBatch(db *sql.DB, batch []DataPoint) {
  // 用 STMT2 写入
  // ...
}

Rust 流处理服务

rust 复制代码
use taos::*;
use futures::StreamExt;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let dsn = "taosws://root:taosdata@localhost:6041/iot";
    let taos = TaosBuilder::from_dsn(dsn)?.build().await?;
    
    // 订阅原始数据
    let tmq = TmqBuilder::from_dsn(
        "taosws://root:taosdata@localhost:6041?group.id=processor"
    )?.build().await?;
    tmq.subscribe(["raw_data"]).await?;
    
    while let Some(msg) = tmq.recv().await? {
        // 处理数据:聚合、过滤、转换
        let processed = process(msg);
        
        // 写入下游表
        taos.exec(&format!(
            "INSERT INTO processed VALUES ({}, {})",
            processed.ts, processed.value
        )).await?;
        
        tmq.commit(msg).await?;
    }
    
    Ok(())
}

性能考量

Go vs Rust 性能

维度 Go Rust
启动速度 极快
单线程吞吐 极高
内存占用 极低
并发模型 goroutine tokio task
学习曲线 平缓

适用场景

场景 推荐
Web 服务 Go
数据采集网关 Go / Rust
极致性能 Rust
TaosX 插件 Rust
K8s Operator Go

FAQ

Q1: Go 连接池怎么配?

go 复制代码
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(time.Hour)

Q2: Rust async 必须用 tokio?

主要支持 tokio。其他 runtime 需自行适配。

Q3: Go 用 GORM 吗?

可以,但 GORM 对时序数据库的高级特性支持有限。推荐直接 database/sql。

Q4: Rust 编译慢怎么办?

  • 用 sccache 缓存
  • release 模式只在最终构建用
  • 拆分 crate 利用增量编译

Q5: 静态链接 libtaos?

Go Native:CGO_ENABLED=1,需 libtaos

Go WebSocket:纯 Go,可静态链接

Rust:features = "ws" 不依赖 libtaos

参考

系统构架篇

数据模型

存储引擎

查询引擎

数据写入

数据订阅

预聚合

索引

SQL 语句

客户端与连接器

关于 TDengine

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

相关推荐
湘美书院--湘美谈教育2 小时前
湘美谈教育互联网逻辑:AI时代的社会学猜想
大数据·人工智能·深度学习·机器学习·生活
东方佑2 小时前
MA-RMSNorm:打破“缩放换智能”的魔咒,大模型归一化的一次范式革命!
数据库·人工智能·计算机视觉
云和恩墨2 小时前
「云帆计划·长沙站」活动成功举办,云和恩墨与紫薇垣和湖南金悦科技分别签约并授牌,本地伙伴生态建设加速
数据库·科技
易观Analysys3 小时前
中国AI健康管理应用发展报告2026
大数据·人工智能
阿里技术3 小时前
面向复杂业务场景的智能分析 Skills 架构设计与演进实践
大数据
老孙讲技术3 小时前
做过安防后端的人都懂:别把「云录像留证」和「告警外呼叫醒」拆成两套台账——分层搭重大事件触达
物联网·安全
千维百策6663 小时前
如何管理错误预算:提升服务可靠性与 SLO 达成率的实践经验
服务器·网络·数据库
科技圈快迅3 小时前
在机场与高铁站:智能服务机器人正在深度对接业务系统,实现从信息孤岛到移动服务窗口的转变
大数据·人工智能·机器人
魔力女仆4 小时前
【RUST AI】把 TTS 搬进浏览器:kokoroi-rs 的 WASM 实践
人工智能·rust·wasm