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

分类:11.客户端与连接器 | 篇章:05 Go/Rust 连接器
在这里插入图片描述
详情

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

速查表

维度GoRust
包名driver-gotaos / taos-ws
接口database/sqlsqlx / 异步
NativetaosSqltaos (libtaos)
WebSockettaosWStaos-ws
RESTtaosRestfultaos-ws (兼容)
异步goroutinetokio

Go 连接器详解

1. 安装

go get github.com/taosdata/driver-go/v3

2. 三种 Driver

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

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 高性能写入

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 订阅

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. 依赖

[dependencies]
taos = { version = "0.x", features = ["ws"] }
tokio = { version = "1", features = ["full"] }

7. 基本用法

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

// 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 数据采集服务

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 流处理服务

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 性能

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

适用场景

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

FAQ

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TDengine (老段)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值