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 提供实时分析、可视化、事件管理与报警等功能。

相关推荐
努力的小雨26 分钟前
KES 开启 SSL 前,证书、端口和客户端要一起验
数据库
DevOps老兵36 分钟前
AI全栈知识07:向量数据库 - Milvus/Chroma实战
数据库·ai·milvus
这个DBA有点耶40 分钟前
当数据库从“存储”走向“决策”:金仓数据库的融合架构之路
数据库·架构·aigc
五度易链-区域产业数字化管理平台42 分钟前
WorkBuddy 实战:将带 MD5 签名的第三方 API 封装为 MCP 服务(企业模糊搜索接口案例)
大数据·人工智能·mcp
编程令我快乐1 小时前
模型配置及使用ccSwich管理
大数据·elasticsearch·搜索引擎
大大大大晴天1 小时前
StarRocks 集群架构部署选型与优化实践
大数据
xushichang123_1 小时前
企业降本刚需下,云上模型蒸馏与轻量化部署怎么选?AWS“大模型教研+小模型推理” 路径
大数据·人工智能
Hello_Damon_Nikola1 小时前
INMP441从入门到精通
单片机·嵌入式硬件·物联网
ttwuai2 小时前
Go 后台接入 SSO 后菜单正常但接口 403,怎么排查权限链路?
开发语言·后端·golang
意疏2 小时前
2026年远控软件安全横评:六款主流工具逐项核查——官方文档、一手实测与安全事件,全摊开
大数据·前端·数据库