Apache IoTDB Node.js 客户端

License npm version Node.js Version

用于 Apache IoTDB 的 Node.js 客户端,支持 SessionPool 和 TableSessionPool,提供高效的连接管理和全面的查询功能。

目录

概述

Apache IoTDB Node.js 客户端是一个高性能、功能丰富的客户端库,用于与 Apache IoTDB 交互。Apache IoTDB 是一个专为 IoT 数据管理设计的时序数据库。该客户端提供了树模型(时间序列)和表模型(关系型)API,实现灵活的数据管理策略。

特性

  • 会话管理:支持查询、非查询和 insertTablet 操作的单一会话
  • SessionPool:用于高并发场景的连接池,支持自动负载均衡
  • TableSessionPool:专门用于表模型操作的连接池,支持数据库上下文管理
  • 多节点支持:跨多个 IoTDB 节点的轮询负载均衡和故障转移
  • SSL/TLS 支持:可自定义 SSL 选项和证书验证的安全连接
  • TypeScript 支持:完整的 TypeScript 类型定义和严格的类型检查
  • 构建器模式:用于优雅配置管理的流式 API
  • 内存高效:SessionDataSet 支持延迟加载和分页处理大型结果集
  • 全面测试:包含单元测试、端到端测试和基准测试工具
  • 生产就绪:连接池、空闲清理、健康检查和错误处理

安装

npm install @iotdb/client

环境要求

  • Node.js >= 14.0.0
  • Apache IoTDB >= 1.0.0

快速开始

基本会话使用

import { Session } from '@iotdb/client';

const session = new Session({
  host: 'localhost',
  port: 6667,
  username: 'root',
  password: 'root',
});

await session.open();

// 执行非查询语句
await session.executeNonQueryStatement('CREATE DATABASE root.test');

// 使用 SessionDataSet 执行查询(迭代器模式 - 内存高效)
const dataSet = await session.executeQueryStatement('SELECT * FROM root.test.**');
while (await dataSet.hasNext()) {
  const row = dataSet.next();
  console.log(row.getTimestamp(), row.getFields());
}
await dataSet.close();

// 或使用 toArray() 辅助方法处理小型结果集(将所有数据加载到内存)
const dataSet2 = await session.executeQueryStatement('SHOW DATABASES');
const allRows = await dataSet2.toArray(); // 返回 [[timestamp, ...fields], ...]
console.log('所有行:', allRows);

// 插入 Tablet 数据
await session.insertTablet({
  deviceId: 'root.test.device1',
  measurements: ['temperature', 'humidity'],
  dataTypes: [3, 3], // FLOAT
  timestamps: [Date.now(), Date.now() + 1000],
  values: [
    [25.5, 60.0],
    [26.0, 61.5],
  ],
});

await session.close();

使用构建器模式(推荐)

构建器模式提供更优雅和流畅的配置 API:

import { Session, ConfigBuilder } from '@iotdb/client';

// 构建会话配置
const session = new Session(
  new ConfigBuilder()
    .host('localhost')
    .port(6667)
    .username('root')
    .password('root')
    .fetchSize(1024)
    .timezone('UTC+8')
    .build()
);

await session.open();
// ... 使用会话
await session.close();

SessionPool 使用

import { SessionPool } from '@iotdb/client';

const pool = new SessionPool('localhost', 6667, {
  username: 'root',
  password: 'root',
  maxPoolSize: 10,
  minPoolSize: 2,
  maxIdleTime: 60000,
  waitTimeout: 60000,
});

await pool.init();

// 使用连接池执行查询
const result = await pool.executeQueryStatement('SELECT * FROM root.test.**');

// 执行非查询语句
await pool.executeNonQueryStatement(
  'CREATE TIMESERIES root.test.device1.temperature WITH DATATYPE=FLOAT'
);

// 插入数据
await pool.insertTablet({
  deviceId: 'root.test.device1',
  measurements: ['temperature'],
  dataTypes: [3], // FLOAT
  timestamps: [Date.now()],
  values: [[25.5]],
});

// 获取连接池统计信息
console.log('连接池大小:', pool.getPoolSize());
console.log('可用连接:', pool.getAvailableSize());

await pool.close();

多节点支持

方法 1:使用字符串格式的 nodeUrls(推荐)

当节点具有不同的 host:port 组合时,使用字符串数组格式的 nodeUrls 配置:

import { SessionPool, PoolConfigBuilder } from '@iotdb/client';

// 使用字符串数组的配置对象(推荐)
const pool1 = new SessionPool({
  nodeUrls: [
    'node1.example.com:6667',
    'node2.example.com:6668',
    'node3.example.com:6669',
  ],
  username: 'root',
  password: 'root',
  maxPoolSize: 15,
  minPoolSize: 3,
});

// 或使用字符串数组的构建器模式
const pool2 = new SessionPool(
  new PoolConfigBuilder()
    .nodeUrls([
      'node1.example.com:6667',
      'node2.example.com:6668',
      'node3.example.com:6669',
    ])
    .username('root')
    .password('root')
    .maxPoolSize(15)
    .minPoolSize(3)
    .build()
);

await pool1.init();
// 连接将使用轮询方式分布在所有节点上

SSL/TLS 支持

import { Session } from '@iotdb/client';
import * as fs from 'fs';

const session = new Session({
  host: 'localhost',
  port: 6667,
  username: 'root',
  password: 'root',
  enableSSL: true,
  sslOptions: {
    ca: fs.readFileSync('/path/to/ca.crt'),
    cert: fs.readFileSync('/path/to/client.crt'),
    key: fs.readFileSync('/path/to/client.key'),
    rejectUnauthorized: true,
  },
});

await session.open();

TableSessionPool 使用

import { TableSessionPool } from '@iotdb/client';

const tablePool = new TableSessionPool('localhost', 6667, {
  username: 'root',
  password: 'root',
  database: 'my_database', // 为表模型设置默认数据库
  maxPoolSize: 10,
  minPoolSize: 2,
});

await tablePool.init();

// 在表模式下执行查询
const result = await tablePool.executeQueryStatement('SHOW DATABASES');

await tablePool.close();

技术架构

概述

IoTDB Node.js 客户端采用三层架构设计,针对单会话和高并发场景进行了优化:

┌─────────────────────────────────────────────────────┐
│  应用层(您的代码)                                 │
└─────────────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────────────┐
│  连接池层                                           │
│  ┌──────────────────┐    ┌──────────────────────┐  │
│  │  SessionPool     │    │ TableSessionPool     │  │
│  │  - 负载均衡      │    │ - 数据库上下文       │  │
│  │  - 连接池管理    │    │ - 连接池管理         │  │
│  └──────────────────┘    └──────────────────────┘  │
└─────────────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────────────┐
│  会话层                                             │
│  ┌──────────────────────────────────────────────┐  │
│  │  Session                                     │  │
│  │  - 查询 / 非查询                             │  │
│  │  - InsertTablet                              │  │
│  │  - 结果解析                                  │  │
│  └──────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────────────┐
│  连接层                                             │
│  ┌──────────────────────────────────────────────┐  │
│  │  Connection (Thrift)                         │  │
│  │  - TCP/SSL 传输                              │  │
│  │  - 会话生命周期                              │  │
│  │  - 低级协议                                  │  │
│  └──────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘
                    ↓
              Apache IoTDB

核心组件

1. 连接层 (src/connection/Connection.ts)

  • 通过 TCP 或 SSL/TLS 管理低级 Thrift 连接
  • 处理会话生命周期(使用 sessionId/statementId 打开/关闭)
  • 实现 TFramedTransport 和 TBinaryProtocol
  • 支持单端点连接
  • 关键模式:一个连接 = 一个 IoTDB 节点端点

2. 会话层 (src/client/Session.ts)

  • 用于数据库操作的高级 API
  • 方法:executeQueryStatement()executeNonQueryStatement()insertTablet()
  • 使用 SessionDataSet 处理查询结果解析
  • 支持可配置 fetchSize 的分页
  • 关键模式:单会话场景使用 nodeUrls 中的第一个节点

3. 连接池层 (src/client/BaseSessionPool.tsSessionPool.tsTableSessionPool.ts)

  • 可配置最小/最大大小的连接池
  • 跨多个端点的轮询负载均衡
  • 自动空闲连接清理(maxIdleTime)
  • 连接池耗尽时的等待队列(waitTimeout)
  • 健康检查和连接回收
  • 关键模式:在 nodeUrls 中的所有节点上分配连接

4. 配置系统 (src/utils/Config.ts)

  • 用于流式配置的构建器模式
  • 支持旧格式(host/port)和新格式(nodeUrls)
  • TypeScript 接口的类型安全
  • 验证和默认值

数据流

查询执行流程

1. 应用调用 pool.executeQueryStatement()
2. 池获取可用的 Session(轮询)
3. Session 通过 Connection 向 IoTDB 发送查询
4. IoTDB 返回带有 queryId 的 SessionDataSet
5. SessionDataSet 批量获取数据(fetchSize)
6. 应用使用 hasNext()/next() 迭代结果
7. Session 释放回池
8. SessionDataSet.close() 释放服务器资源

插入流程

1. 应用调用 pool.insertTablet()
2. 池获取可用的 Session(轮询)
3. Session 按列序列化 Tablet 数据
4. 通过 Connection 将数据发送到 IoTDB
5. IoTDB 确认写入
6. Session 释放回池

线程安全和并发

  • 会话:非线程安全;使用 SessionPool 进行并发
  • SessionPool:线程安全;会话管理的内部锁定
  • 连接生命周期:由池自动管理
  • 负载均衡:会话获取时的轮询分配
  • 空闲清理:后台任务删除空闲连接

Thrift 集成

客户端使用 Apache Thrift 进行 RPC 通信:

  • 生成的代码src/thrift/generated/ 来自 IoTDB 的 .thrift 文件
  • 协议:TBinaryProtocol(紧凑、高效)
  • 传输:TFramedTransport(消息边界)
  • SSL 支持:可配置的 TLS 传输层
  • 版本:兼容 Apache IoTDB 1.0+

内存管理

  • SessionDataSet:延迟加载与分页(默认:1024 行/次)
  • 连接池:有界大小防止资源耗尽
  • 空闲清理:maxIdleTime 后自动连接清理
  • 结果集:必须调用 close() 以释放服务器资源

错误处理

  • 连接错误:使用池中的下一个节点自动重试
  • 超时处理:可配置的查询超时(默认:60秒)
  • 池耗尽:带超时的等待队列
  • Thrift 错误:使用堆栈跟踪包装在 JavaScript 错误中
  • 重定向处理:自动缓存设备到端点映射以优化写入路由

重定向支持 ✅(已实现)

状态:✅ 已完全实现

客户端现在支持多节点 IoTDB 集群的自动写入重定向。当写入操作发送到不拥有设备数据的节点时,服务器会响应重定向建议(状态码 400)。客户端会自动:

  1. 缓存设备→端点映射
  2. 创建/复用到最优端点的连接
  3. 在正确的节点上重试操作
  4. 在未来对同一设备的写入中使用缓存的映射

优势:

  • 通过避免跨节点数据转发,吞吐量提高 30-50%
  • 降低网络延迟
  • 更好的资源利用率

配置:

import { SessionPool, TableSessionPool } from '@iotdb/client';

// 带重定向的树模型连接池
const treePool = new SessionPool({
  nodeUrls: ['192.168.1.100:6667', '192.168.1.101:6667', '192.168.1.102:6667'],
  username: 'root',
  password: 'root',
  maxPoolSize: 10,
  enableRedirection: true,        // 启用重定向(默认:true)
  redirectCacheTTL: 300000,       // 缓存 TTL(毫秒)(默认:5 分钟)
});

// 带重定向的表模型连接池
const tablePool = new TableSessionPool({
  nodeUrls: ['192.168.1.100:6667', '192.168.1.101:6667', '192.168.1.102:6667'],
  enableRedirection: true,
});

工作原理:

// 第一次写入设备 - 服务器返回重定向建议
const tablet = {
  deviceId: 'root.sg.device1',
  measurements: ['temperature'],
  dataTypes: [TSDataType.FLOAT],
  timestamps: [Date.now()],
  values: [[25.5]],
};

await pool.insertTablet(tablet);
// → 写入到节点 A(通过轮询)
// → 写入成功!
// → 服务器响应代码 400:"建议未来使用节点 B 处理此设备"
// → 客户端缓存:device1 → 节点 B(为下次写入做准备)

// 第二次写入同一设备 - 使用缓存的端点
await pool.insertTablet({
  deviceId: 'root.sg.device1',
  measurements: ['temperature'],
  dataTypes: [TSDataType.FLOAT],
  timestamps: [Date.now() + 1000],
  values: [[26.0]],
});
// → 客户端检查缓存:device1 → 节点 B
// → 直接写入节点 B
// → 无需重定向!

测试:

重定向支持已通过 1C3D(1 个 ConfigNode,3 个 DataNode)集群配置进行测试。运行 E2E 测试:

# 启动 1C3D 集群
docker-compose -f docker-compose-1c3d.yml up -d

# 运行重定向测试
MULTI_NODE=true npm run test:e2e

实现细节:

详细设计文档请参见 docs/redirection-design.md

API 参考

配置构建器

ConfigBuilder

用于构建 Session 配置的流式 API:

import { ConfigBuilder } from '@iotdb/client';

const config = new ConfigBuilder()
  .host('localhost')
  .port(6667)
  .username('root')
  .password('root')
  .database('mydb')
  .timezone('UTC+8')
  .fetchSize(2048)
  .enableSSL(false)
  .build();

方法:

  • host(host: string): this - 设置主机
  • port(port: number): this - 设置端口
  • nodeUrls(nodeUrls: EndPoint[]): this - 设置多个节点 URL
  • username(username: string): this - 设置用户名
  • password(password: string): this - 设置密码
  • database(database: string): this - 设置数据库
  • timezone(timezone: string): this - 设置时区
  • fetchSize(fetchSize: number): this - 设置获取大小
  • enableSSL(enable: boolean): this - 启用或禁用 SSL
  • sslOptions(sslOptions: SSLOptions): this - 设置 SSL 选项
  • build(): Config - 构建并返回配置

PoolConfigBuilder

用于构建 SessionPool 配置的流式 API(扩展 ConfigBuilder):

import { PoolConfigBuilder } from '@iotdb/client';

const config = new PoolConfigBuilder()
  .host('localhost')
  .port(6667)
  .username('root')
  .password('root')
  .maxPoolSize(20)
  .minPoolSize(5)
  .maxIdleTime(30000)
  .waitTimeout(45000)
  .build();

附加方法:

  • maxPoolSize(size: number): this - 设置最大连接池大小
  • minPoolSize(size: number): this - 设置最小连接池大小
  • maxIdleTime(time: number): this - 设置最大空闲时间(毫秒)
  • waitTimeout(timeout: number): this - 设置等待超时(毫秒)
  • build(): PoolConfig - 构建并返回连接池配置

数据类型

插入 Tablet 时,使用以下常量指定数据类型:

  • 0 - BOOLEAN
  • 1 - INT32
  • 2 - INT64
  • 3 - FLOAT
  • 4 - DOUBLE
  • 5 - TEXT
  • 8 - TIMESTAMP
  • 9 - DATE
  • 10 - BLOB
  • 11 - STRING

完整的数据类型参考,请参见 DATA_TYPES.md

Session

构造函数

选项 1:使用配置对象

new Session(config: Config)

选项 2:使用构建器模式(推荐)

new Session(new ConfigBuilder()...build())

配置必须包括:

  • hostport 用于单节点连接
  • nodeUrls 用于多节点连接(使用第一个节点)

方法

  • async open(): Promise<void> - 打开会话
  • async close(): Promise<void> - 关闭会话
  • async executeQueryStatement(sql: string, timeoutMs?: number): Promise<QueryResult> - 执行带可选超时的查询(默认:60000毫秒)
  • async executeNonQueryStatement(sql: string): Promise<void> - 执行非查询语句
  • async insertTablet(tablet: Tablet): Promise<void> - 插入 Tablet 数据
  • isOpen(): boolean - 检查会话是否打开

SessionPool

构造函数

选项 1:传统 API(向后兼容)

new SessionPool(hosts: string | string[], port: number, config?: Partial<PoolConfig>)

选项 2:使用带 nodeUrls 的配置对象

new SessionPool(config: PoolConfig)

选项 3:使用构建器模式(推荐)

new SessionPool(new PoolConfigBuilder()...build())

方法

连接管理:

  • async init(): Promise<void> - 初始化连接池
  • async close(): Promise<void> - 关闭所有连接

自动会话管理:

  • async executeQueryStatement(sql: string, timeoutMs?: number): Promise<QueryResult> - 执行带可选超时的查询(默认:60000毫秒)
  • async executeNonQueryStatement(sql: string): Promise<void> - 执行非查询语句
  • async insertTablet(tablet: Tablet): Promise<void> - 插入 Tablet 数据

显式会话管理:

  • async getSession(): Promise<Session> - 从池中获取会话(必须释放)
  • releaseSession(session: Session): void - 将会话释放回池

连接池统计:

  • getPoolSize(): number - 获取当前连接池大小
  • getAvailableSize(): number - 获取可用连接
  • getInUseSize(): number - 获取当前正在使用的会话数

TableSessionPool

与 SessionPool 相同,但针对表模型操作进行了优化。配置数据库时自动执行 USE DATABASE。所有查询方法都支持相同的超时参数(默认:60000毫秒)。

开发

前置条件

  • Node.js >= 14.0.0
  • npm >= 6.0.0
  • Apache Thrift 编译器(可选,用于重新生成 Thrift 文件)
  • Git

开发设置

  1. 克隆仓库:
git clone https://github.com/CritasWang/@iotdb/client.git
cd @iotdb/client
  1. 安装依赖:
npm install
  1. 构建项目:
npm run build

构建系统

项目使用两步构建过程:

  1. esbuild:快速 TypeScript 编译

    • esbuild.config.js 中配置
    • src/ 编译到 dist/ 目录
    • 不包含类型声明文件
  2. tsc:类型声明生成

    • 为 TypeScript 支持生成 .d.ts 文件
    • 使用 --emitDeclarationOnly 标志运行
    • 确保消费者的类型安全
  3. copy:thrift:复制生成的 Thrift 文件

    • .js 文件从 src/thrift/generated/ 复制到 dist/thrift/generated/
    • 必需,因为 Thrift 代码使用 require() 语句

构建命令:

npm run build          # 完整构建(esbuild + tsc + copy)
npm run build:esbuild  # 仅 esbuild 编译
npm run build:types    # 仅类型声明

开发工作流

  1. src/ 目录中进行更改
  2. 使用 npm run build 构建
  3. 使用 npm test 测试
  4. 使用 npm run lint 检查代码
  5. 使用 npm run format 格式化

代码风格

  • 使用 TypeScript 严格模式
  • 遵循现有的代码格式(Prettier)
  • 为公共 API 添加 JSDoc 注释
  • 保持函数专注和简洁
  • 使用 async/await 而不是回调
  • 适当处理错误
  • 优先使用显式类型而不是 any

重新生成 Thrift 文件

如果需要更新到 IoTDB 的 Thrift 定义的新版本:

  1. 从 Apache IoTDB 下载最新的 Thrift 文件:
git clone --depth 1 https://github.com/apache/iotdb.git /tmp/iotdb
  1. 复制 Thrift 文件:
cp /tmp/iotdb/iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift thrift/
cp /tmp/iotdb/iotdb-protocol/thrift-commons/src/main/thrift/common.thrift thrift/
  1. 重新生成 Node.js 客户端:
npm run generate:thrift
  1. 彻底测试以确保兼容性

测试

测试结构

tests/
├── unit/           # 单元测试(快速,无外部依赖)
│   ├── Config.test.ts
│   ├── Logger.test.ts
│   └── ...
└── e2e/            # 端到端测试(需要 IoTDB)
    ├── Session.test.ts
    ├── SessionPool.test.ts
    ├── TableSessionPool.test.ts
    └── ...

运行测试

运行所有测试:

npm test

仅运行单元测试:

npm run test:unit

仅运行端到端测试(需要 IoTDB 实例):

export IOTDB_HOST=localhost
export IOTDB_PORT=6667
export IOTDB_USER=root
export IOTDB_PASSWORD=root
npm run test:e2e

端到端测试设置

端到端测试需要运行中的 IoTDB 实例。您可以使用 Docker Compose:

单节点(1c1d):

docker-compose -f docker-compose-1c1d.yml up -d

3节点集群(3c3d):

docker-compose -f docker-compose-3c3d.yml up -d

停止容器:

docker-compose -f docker-compose-1c1d.yml down

测试模式

单元测试示例

describe('ConfigBuilder', () => {
  test('应使用所有选项构建配置', () => {
    const config = new ConfigBuilder()
      .host('localhost')
      .port(6667)
      .username('root')
      .password('root')
      .build();
    
    expect(config.host).toBe('localhost');
    expect(config.port).toBe(6667);
  });
});

端到端测试示例

describe('Session 端到端测试', () => {
  let session: Session;

  beforeAll(async () => {
    session = new Session({
      host: process.env.IOTDB_HOST || 'localhost',
      port: parseInt(process.env.IOTDB_PORT || '6667'),
      username: process.env.IOTDB_USER || 'root',
      password: process.env.IOTDB_PASSWORD || 'root',
    });
    await session.open();
  }, 60000); // 连接60秒超时

  afterAll(async () => {
    if (session?.isOpen()) {
      await session.close();
    }
  });

  test('应执行查询', async () => {
    if (!session.isOpen()) return; // 无连接时跳过
    
    const dataSet = await session.executeQueryStatement('SHOW DATABASES');
    const rows = await dataSet.toArray();
    expect(Array.isArray(rows)).toBe(true);
    await dataSet.close();
  });
});

测试覆盖率

当前测试覆盖:

  • 单元测试:核心工具(Config、Logger、数据序列化)
  • 端到端测试:Session、SessionPool、TableSessionPool
  • 同时测试所有数据类型
  • 测试多节点场景
  • 测试连接池行为(大小限制、超时、清理)

调试测试

调试单个测试:

npm run test:debug

调试端到端测试:

npm run test:e2e:debug

检查未关闭的句柄:

npm run test:e2e:check-handles

性能测试

benchmark/ 目录中提供了全面的基准测试工具,用于性能测试和优化。

概述

  • 树模型基准测试:使用 insertTablet API 测试时间序列数据模型
  • 表模型基准测试:使用 insertTablet API 测试关系数据模型
  • 预生成数据:消除测试期间的数据生成开销
  • 并发客户端:模拟真实世界的高并发场景
  • 详细指标:吞吐量、延迟、百分位数(P50、P90、P95、P99)

快速开始

测试基准测试基础设施(不需要 IoTDB):

node benchmark/test-benchmark.js

运行树模型基准测试:

CLIENT_NUMBER=10 DEVICE_NUMBER=100 node benchmark/benchmark-tree.js

运行表模型基准测试:

CLIENT_NUMBER=10 DEVICE_NUMBER=100 node benchmark/benchmark-table.js

关键配置参数

参数默认值描述
CLIENT_NUMBER10并发客户端数
DEVICE_NUMBER100要模拟的设备数
SENSOR_NUMBER10每个设备的传感器数
BATCH_SIZE_PER_WRITE100每次写入操作的数据行数
TOTAL_DATA_POINTS100000要生成的总数据点
POOL_MAX_SIZE20连接池中的最大连接数

示例:高并发测试

CLIENT_NUMBER=50 \
DEVICE_NUMBER=1000 \
SENSOR_NUMBER=10 \
BATCH_SIZE_PER_WRITE=1000 \
TOTAL_DATA_POINTS=1000000 \
node benchmark/benchmark-tree.js

性能指标

基准测试报告:

  • 执行时间:总测试时长
  • 操作:总操作数、成功、失败、成功率
  • 数据点:写入的总数据点
  • 吞吐量:操作数/秒、数据点数/秒
  • 延迟:最小、最大、平均、P50、P90、P95、P99

示例输出

================================================================================
基准测试结果
================================================================================

[执行时间]
  时长:                  45.23秒 (45234毫秒)

[操作]
  总操作数:              1000
  成功:                  998
  失败:                  2
  成功率:                99.80%

[数据点]
  写入的总数据点:        100,000

[吞吐量]
  操作数/秒:             22.11
  数据点数/秒:           2,210

[延迟 (毫秒)]
  最小:                  15.23毫秒
  最大:                  1250.45毫秒
  平均:                  45.23毫秒
  P50 (中位数):          42.15毫秒
  P90:                   78.45毫秒
  P95:                   95.23毫秒
  P99:                   125.67毫秒
================================================================================

性能调优技巧

  1. 优化批量大小:测试不同的值(100-1000行)
  2. 调整并发:从10-20个客户端开始,根据结果调整
  3. 使用连接池:设置适当的 POOL_MIN_SIZEPOOL_MAX_SIZE
  4. 预生成数据:使用缓存数据以获得准确结果
  5. 监控资源:监视 CPU、内存、磁盘 I/O 和网络

完整文档请参见 benchmark/README.md

示例

有关更多使用示例,请参见 examples/ 目录:

  • examples/basic-session.ts - 基本会话使用
  • examples/session-pool.ts - SessionPool 使用
  • examples/table-session-pool.ts - TableSessionPool 使用
  • examples/multi-node.ts - 多节点配置
  • examples/ssl-connection.ts - SSL/TLS 连接

文档

docs/ 目录中提供了全面的文档:

用户指南

技术文档

贡献者文档

其他资源

贡献

我们欢迎社区贡献!无论您是修复错误、添加功能、改进文档还是报告问题,我们都非常感谢您的帮助。

如何贡献

  1. 在 GitHub 上 Fork 仓库
  2. main 创建功能分支
  3. 遵循我们的代码风格指南进行更改
  4. 为新功能添加测试
  5. 根据需要更新文档
  6. 提交包含清晰描述的 Pull Request

开发指南

  • 遵循现有的代码风格和约定
  • 编写清晰、简洁的提交消息
  • 为新功能添加单元测试
  • 确保在提交 PR 之前所有测试通过
  • 为显著更改更新 CHANGELOG.md
  • 保持 PR 专注于单个功能或修复

代码审查流程

所有提交在合并前都需要审查:

  1. 自动化测试必须通过(CI/CD)
  2. 维护者进行代码审查
  3. 文档审查(如适用)
  4. 最终批准和合并

报告问题

报告错误时,请包括:

  • Node.js 版本
  • IoTDB 版本
  • 操作系统
  • 重现步骤
  • 预期行为与实际行为
  • 错误消息和堆栈跟踪

有关详细的贡献指南,请参见 CONTRIBUTING.md

发布流程

本项目遵循语义化版本控制(SemVer)并维护定期发布周期。

版本编号

给定版本号 MAJOR.MINOR.PATCH

  • MAJOR:破坏性 API 更改
  • MINOR:新功能,向后兼容
  • PATCH:错误修复,向后兼容

发布工作流

1. 发布前准备

更新版本和更新日志:

# 更新 package.json 中的版本
npm version [major|minor|patch] --no-git-tag-version

# 使用发布说明更新 CHANGELOG.md
# - 新功能
# - 错误修复
# - 破坏性更改
# - 弃用

2. 测试

运行全面测试:

# 单元测试
npm run test:unit

# 端到端测试(需要 IoTDB)
export IOTDB_HOST=localhost
export IOTDB_PORT=6667
npm run test:e2e

# 代码检查
npm run lint

# 构建验证
npm run build

3. 版本标记

创建并推送版本标签:

# 提交版本更新
git add package.json CHANGELOG.md
git commit -m "chore: bump version to X.Y.Z"

# 创建标签
git tag -a vX.Y.Z -m "Release vX.Y.Z"

# 推送到远程
git push origin main
git push origin vX.Y.Z

4. 发布到 npm

构建和发布:

# 构建生产资源
npm run build

# 发布到 npm(需要 npm 帐户)
npm publish

# 对于 beta/RC 版本
npm publish --tag beta

5. GitHub 发布

创建 GitHub 发布:

  1. 转到 GitHub 发布页面
  2. 点击“创建新发布”
  3. 选择版本标签
  4. 添加发布标题:v X.Y.Z - 发布名称
  5. 将更新日志条目复制到发布说明
  6. 附加构建工件(如适用)
  7. 发布版本

发布检查清单

  • [ ] 所有测试通过
  • [ ] CHANGELOG.md 已更新
  • [ ] package.json 中的版本已更新
  • [ ] 文档已更新
  • [ ] 破坏性更改已记录
  • [ ] 迁移指南(用于主要版本)
  • [ ] Git 标签已创建
  • [ ] npm 包已发布
  • [ ] GitHub 发布已创建
  • [ ] 发布公告(如果是主要版本)

发布计划

  • 补丁版本:根据关键错误需要
  • 次要版本:每月或功能准备就绪时
  • 主要版本:需要破坏性更改时

Beta/RC 版本

稳定版本发布前的测试:

# 创建 beta 版本
npm version 1.2.0-beta.1 --no-git-tag-version

# 使用 beta 标签发布
npm publish --tag beta

# 安装 beta 版本
npm install @iotdb/client@beta

热修复流程

对于关键生产问题:

  1. 从发布标签创建热修复分支
  2. 修复问题
  3. 增加补丁版本
  4. 立即标记和发布
  5. 合并回 main

发布后任务

  • 更新文档站点(如适用)
  • 在项目频道上宣布
  • 监控问题和反馈
  • 准备下一个发布里程碑

许可证

Apache License 2.0

版权所有 © 2024 Apache IoTDB

根据 Apache 许可证 2.0 版(“许可证”)许可; 除非遵守许可证,否则您不得使用此文件。 您可以在以下地址获取许可证副本:

http://www.apache.org/licenses/LICENSE-2.0

除非适用法律要求或书面同意,否则根据许可证分发的软件 按“原样”分发,不提供任何明示或暗示的保证或条件。 有关许可证下的特定权限和限制,请参见许可证。

参考资料