influx2tsdb
pg addon install influx2tsdb 以受管容器方式运行 influx2tsdb-proxy 1.3.2——
一个 InfluxDB 1.x HTTP API 适配器(Line Protocol 写入、InfluxQL 查询),数据落到
启用了 TimescaleDB 扩展的 PostgreSQL。镜像由 pgcli 自建:
ghcr.io/mars-base/pgcli/pgcli-influx2tsdb。与 InfluxDB 插件 不同,
这里没有 TSM 引擎:每个数据点都存进 TimescaleDB hypertable,代理本身无状态。
本插件仅支持 Linux/amd64(镜像为单架构,基于上游发行版二进制 + debian:12-slim)。
代理容器可以随时重建,数据因存放在 PostgreSQL 中而不会丢失。
HTTP API 没有认证。 上游代理只提供明文 HTTP、绑定所有网卡,且不校验 InfluxDB 凭据。需要 TLS 和访问控制时用 nginx 插件 前置,或直接 防火墙隔离端口。不可在不可信网络上使用。
适用场景与取舍
原生 InfluxDB 1.x 使用自己的内存索引 + TSM 文件,直接服务 InfluxQL。 influx2tsdb 则把每个请求翻译成 SQL,把数据行存进 PostgreSQL/TimescaleDB。这层 翻译加上关系型存储引擎会带来吞吐和延迟开销:纯时序写入/查询负载下,原生 InfluxDB 比本代理更快,差距在大范围聚合扫描和高基数场景下更明显。
换来的好处是时序数据变成了普通的数据库数据:
- ACID 事务与一致性。 数据点与关系数据处于同一个事务存储中;批量写入要么 整体提交、要么失败,时序数据可以与业务表在一条 SQL 里 join。
- SQL 生态。 TimescaleDB 把 hypertable 暴露成普通表:join、视图、CTE、窗口 函数、ORM 和 BI 工具都能用。InfluxQL 只是写入/查询入口,不是封闭的孤岛。
- 成熟的备份、PITR、复制与 HA。
pg_dump/pgBackRest、WAL 归档、流复制、 Patroni 等 PostgreSQL 运维手段原样适用——不需要再维护第二套存储和灾备流程。 - 统一的运维、认证与审计。 用户、角色、TLS、监控和合规控制都复用 PostgreSQL,不必额外加固一个数据库。
- 灵活的数据生命周期。 保留与压缩是 TimescaleDB 原生策略(见下文),同时
仍可对任意行
UPDATE/DELETE、做 schema 迁移和表结构重塑。 - 复用现有 PostgreSQL 基础设施与 DBA 技能。 如果 PostgreSQL 本来就有专业 运维,新增一个时序负载的边际成本很低。
如果最看重 InfluxQL/TSM 性能和忠实还原 InfluxDB 1.x 行为,选 InfluxDB 插件;如果首要目标是把一切留在 PostgreSQL 里,选 influx2tsdb。
前置条件
-
目标 PostgreSQL 数据库已安装 TimescaleDB 扩展。代理启动时会尝试
CREATE EXTENSION IF NOT EXISTS timescaledb,但实例中必须有可安装的扩展包。 pgcli 实例上执行: -
目标必须在代理启动前处于运行状态。本地目标会预先检查 (
pg start -i tsdb);PostgreSQL 不可达时代理会立即退出。
安装
本地目标——DSN 在每次启动时从 pgcli 实例重新推导,端口和密码变化会自动同步:
远程或非受管目标——传完整 DSN:
DSN(含密码)会存入 pg.yaml,同时出现在容器命令行里,可通过
podman inspect 看到;请保护配置文件,并使用只授权目标数据库的最小权限角色。
第二个实例会从 influx2tsdb_start_port(默认 8087)起自动分配下一个空闲端口:
不带 --force 重复 install 是幂等空操作。--force 会重写目标/端口设置并重建
容器;代理无数据,因此不影响任何已存数据。
参数
| 参数 | 默认值 | 说明 |
|---|---|---|
--name |
influx2tsdb |
实例名(配置 map 键) |
--pg-name |
— | 使用本地受管 pgcli 实例作为目标;与 --dsn 互斥 |
--dsn |
— | 远程/非受管 PostgreSQL/TimescaleDB 的完整 DSN |
--database |
目标库名 | 默认 InfluxDB 数据库(代理 -db);对应一个 PostgreSQL schema |
--port |
自动(基址 8087) | InfluxDB 协议 HTTP 宿主端口;0 = 自动分配 |
--pool-size |
10 |
PostgreSQL 连接池大小(-pool) |
--verbose |
false | 输出翻译后的 SQL 和查询细节(-verbose) |
--version |
1.3.2 |
固定的镜像发行版 |
--force |
false | 重写设置并重建无状态容器 |
没有 --data-dir 和 --listen:代理不保留本地状态,使用 host 网络,且始终
绑定所有网卡。
数据模型
每个 InfluxDB 数据库对应目标库中的一个 PostgreSQL schema:
CREATE DATABASE "demo"→CREATE SCHEMA "demo"- measurement 变成该 schema 下的 TimescaleDB hypertable
- tag 变成文本列;field 变成带类型的列;
time是 hypertable 的分区列 - 代理元数据位于目标库的
publicschema:_influx_databases、_influx_meta、_retention_policy
数据就是普通 PostgreSQL 数据,可以直接用 pg exec 查看和 join:
写入与查询
API 遵循 InfluxDB 1.x:写入成功返回 204,非法 line protocol 返回 400。
当前版本支持的常用语句:
| 类别 | 语句 |
|---|---|
| 数据库 | CREATE DATABASE、DROP DATABASE、SHOW DATABASES |
| 保留策略 | CREATE / ALTER / DROP / SHOW RETENTION POLICIES |
| 写入/删除 | line protocol 写入、DELETE FROM、DROP MEASUREMENT |
| 元数据 | SHOW MEASUREMENTS / TAG KEYS / TAG VALUES / FIELD KEYS(后三者需带 FROM <measurement>) |
| 查询 | 带 tag/time 过滤的 SELECT、mean/sum/min/max/count、first/last、GROUP BY time(...) 与 tag、子查询 |
使用 InfluxDB 1.x 命令行客户端
官方 influx CLI(1.13.1)可以直接操作代理。pgcli 通过一次性容器运行它,
remote 模式指向代理即可(代理无认证,无需用户名密码):
数据库与保留策略:
写入(line protocol):
查询与元数据:
删除与输出格式:
批量导入(influx 1.x import 格式):
实测可用:数据库与保留策略 DDL、INSERT(line protocol)、SELECT(含
GROUP BY time(...)、tag/time 过滤和 -format column/csv/json)、
SHOW MEASUREMENTS、带 FROM 的 SHOW TAG KEYS / FIELD KEYS / TAG VALUES、
DELETE、DROP MEASUREMENT 以及 -import。
与原生 InfluxDB 的差异:
- 元数据命令必须带
FROM <measurement>:SHOW TAG KEYS、SHOW FIELD KEYS和SHOW TAG VALUES不带FROM会返回missing FROM clause(原生 InfluxDB 允许省略);WITH KEY =~ /regex/也不支持。 - 不支持
SHOW SERIES(返回unsupported query: SHOW SERIES)。 - 默认保留策略不能直接
DROP(与原生 InfluxDB 一致),先把另一个策略设为DEFAULT。 -precision的ns/u/ms/s/m/h都生效;rfc3339不生效,仍输出纳秒整数。
时间精度注意事项
-
时间戳一律按纳秒解释。 在 E2E 实测中,当前版本忽略
/write的precision=查询参数;请发送纳秒时间戳(InfluxDB 默认精度),避免数据时间 偏移。 -
时间字面量两种写法都可用。 实测中,
WHERE time ...既接受'YYYY-MM-DD HH:MM:SS',也接受 RFC3339(如'2023-11-14T22:13:20Z',含 毫秒或+08:00时区偏移);Grafana 经$timeFilter插值出的 epoch 毫秒 形式(如1793083539315ms)同样可用: -
now() - 1d这类表达式可用。
已知上游问题:DROP MEASUREMENT 元数据缓存
执行 DROP MEASUREMENT 后,代理会删除 _influx_meta 中该 measurement 的行,
但保留内存中的 schema 缓存。之后用相同名字重新创建 measurement 时,元数据
不会被重新插入,SHOW MEASUREMENTS / SHOW TAG KEYS / SHOW FIELD KEYS 可能
为空,而 SELECT 仍然可用。自动化中请使用每次唯一的 measurement 名,或在删除
并重建后重启代理。仓库自带测试脚本采用前者。
Grafana 集成
Grafana 内置的 InfluxDB 数据源可以直接接入本代理(已在 Grafana 13.2.4 上 端到端验证):数据源类型选 InfluxDB,Query Language 选 InfluxQL (不是 Flux),URL 指向代理,即可查询底层 TimescaleDB 中的 hypertable。
| 字段 | 值 |
|---|---|
| Type | InfluxDB |
| Query Language | InfluxQL |
| URL | http://<proxy-host>:8087 |
| Database | tsdb_db(或你的默认库) |
| User / Password | 留空 |
| HTTP Method | GET(默认) |
数据源的 “Save & test” 健康检查可用;Grafana 查询编辑器和面板生成的请求
($timeFilter、epoch=ms、fill(null)、GROUP BY time)已实测返回正确的
时间序列,SHOW MEASUREMENTS / TAG KEYS / TAG VALUES / FIELD KEYS 也受支持,
因此查询构建器里的 measurement/tag/field 下拉框可正常使用。
注意事项:
- 代理无认证、无 TLS;Grafana 与代理不在可信网络时用 nginx 插件 前置。
- 只支持 InfluxQL 子集;不支持的表达式可能返回错误或空结果,也不支持 Flux (Flux 依赖 InfluxDB v2 API,本代理不提供)。
- 代理忽略写入的
precision=参数;Grafana 用epoch=ms读取,展示不受 影响。
通过 Grafana HTTP API 集成
自动化场景不必点 Web UI:Grafana 的 HTTP API 可以直接创建数据源,并验证 “代理写入 → Grafana API 读取”的完整链路(以下命令已在 Grafana 13.2.4 上 实测)。
写入返回 204;第 4 步返回该 measurement 的 last(value),time 列为
epoch 毫秒(与 epoch=ms 一致)。
要点:
access: "proxy"让 Grafana 服务端转发查询,浏览器不直连代理,也不涉及 CORS。jsonData中的version: "InfluxQL"和httpMode: "GET"与面板查询使用 的模式一致,创建时显式给出。- 删除数据源:
curl -u "admin:$GRAFANA_PW" -X DELETE "$G/api/datasources/uid/$UID"(返回200)。
保留策略、压缩与 TimescaleDB 任务
支持 InfluxDB 语义的 CREATE / ALTER / DROP RETENTION POLICY(按数据库隔离、
只有一个默认策略、最短 15m、INF/0s 表示无限)。在存储层,代理会立即对该
数据库 schema 中的每个 hypertable 调用 TimescaleDB 自带的策略函数:
清理本身是自动的,不需要 pg_cron。 任务运行在 TimescaleDB 自带的后台
job scheduler 中,可在 timescaledb_information.jobs 查看:
一个 1 天保留策略会产生类似这样的任务:
运维要点:
- 调度器不是代理。 真正执行任务的是 TimescaleDB;只要 PostgreSQL 在运行, 停止或删除代理容器并不会停止数据过期清理。反之,代理停机期间新建的 hypertable 会在下一次同步时补上策略。
- 同步节奏。
CREATE / ALTER / DROP RETENTION POLICY会立即触发一次同步; 另有后台循环每 5 分钟对所有 hypertable 重新下发策略(覆盖新表,以及因锁 超时被跳过的 DDL)。 - 任务节奏。 代理会按推导值设置调度间隔:保留策略小于 24h 时请求每 5 分钟、
否则每小时;压缩小于 24h 时请求每分钟、否则每小时。但上游 1.3.2 存在已知
quirk:选择间隔时会遍历所有数据库的策略,且结果受 map 遍历顺序影响,多库
部署下实际间隔可能与推导值不同(实测 1h 保留策略的 retention 任务被排成
1 小时)。需要精确节奏时以
timescaledb_information.jobs.schedule_interval为准;代理每次同步都会重新下发推导出的间隔。 - 只有默认策略会真正生效。 schema 内所有 hypertable 都使用该数据库默认策略
的时长(若没有默认策略,则取第一个有限时长的策略)。非默认策略只是元数据;
代理不会按策略拆分 schema,也不会按 measurement 单独保留。没有有限时长策略
(或默认策略为
INF)时数据会持续增长。 - 删除以 chunk 为粒度。 TimescaleDB 整块删除 chunk,因此过期数据最多会多留
一个 chunk 间隔,稳态数据量约为「保留时长 + 最多一个 chunk 间隔」,之后不再
无限增长。chunk 间隔来自
SHARD DURATION或按保留时长推导(最小 1h, retention/24,上限 1 天)。 - 把策略改成
INF会在下次同步时移除 TimescaleDB 保留任务,数据不再过期。 - 压缩自动启用。 tag 作为
compress_segmentby,时间倒序作为compress_orderby;compress_after由保留时长推导(retention/4,上限 1 天, 最小15m)。
在 PostgreSQL 侧核查:
安全与暴露面
- 代理没有任何凭据;能连到端口的人就能读写目标 DSN 暴露的所有数据库。
- 只绑可信网络,或用 nginx 插件 前置做 TLS 与 IP/Basic Auth 限制。 代理端口本身没有 TLS。
- PostgreSQL 密码会出现在
pg.yaml和容器 argv 中。请使用仅授权目标库的专用 角色,并保护配置文件。
生命周期与开机自启
remove 从不删除数据:数据在 PostgreSQL 里。--clean-data 为与其他插件保持
一致而接受,但没有可删除的内容。
开机自启会重建无状态代理。本地目标会先启动实例,再重新推导 DSN:
备份、恢复与 HA
代理侧没有需要备份的内容,直接使用 PostgreSQL 的常规工具:
pg backup <instance>/ pgBackRest /pg_dump——所有 schema、hypertable 以及public._influx_*元数据表都会包含在内。- PITR / WAL 归档 / 流复制 / Patroni——原样适用。故障切换或迁移后,把代理指向
新主库(
--dsn)并重建;本地实例则在实例 DSN 变化后重启代理。
代理容器是一次性的:pg addon install influx2tsdb --force 用同一目标重建即可。
测试脚本
test/addon/test_influx2tsdb.sh 覆盖常用时序操作:ping、单点/批量写入(含 tag
和多种 field 类型)、count、时间范围与 tag 过滤、mean/sum/min/max、
GROUP BY time() 与 tag、first/last、SHOW 元数据、可选的 PostgreSQL
行数/hypertable 检查、DELETE、DROP MEASUREMENT、数据库生命周期、保留策略
CRUD,以及非法写入的处理。
由于上述 DROP MEASUREMENT 元数据缓存问题,脚本使用每次运行唯一的 measurement
和数据库名。
test/addon/test_influx2tsdb_retention.sh 专门验证保留策略的自动化,覆盖:
- 自动创建
policy_retention/policy_compression任务,drop_after/compress_after与 RP 推导一致; CALL run_job(<id>)真正删除过期 chunk,新数据保留;- 停掉代理后直接向 PostgreSQL 插入过期行,任务仍能删除(证明调度不依赖代理);
- 默认 RP 切到
INF后保留任务消失、压缩任务保留并回退到 1 天; DROP DATABASE后该 schema 的任务全部清理;- 目标库未安装
pg_cron。
脚本通过 pg exec 访问目标 PostgreSQL,因此需要 --instance 或 --pg-dsn;
它会在运行中停止并重启本地代理(除非 --skip-proxy-stop)。
限制
- 仅 Linux/amd64。
- 代理无认证、无 TLS;请用 nginx 前置或做网络隔离。
- InfluxQL 子集。 当前版本只实现上文列出的语句,不是完整 InfluxQL;例如
SHOW SERIES不支持,SHOW TAG KEYS / FIELD KEYS / TAG VALUES必须带FROM。不支持的语法会返回错误或空结果。不支持 Flux。 - 时间戳按纳秒解释;当前版本忽略写入的
precision=参数。查询输出精度由epoch=ms控制(Grafana 即使用该参数)。 - 仅支持按数据库的保留策略。 一个默认策略作用于 schema 内所有 hypertable。
- 时序负载性能低于原生 InfluxDB(见上文)。
- 代理的元数据表(
_influx_databases、_influx_meta、_retention_policy)位于 目标库的publicschema。
CLI 参数参考
pg addon install influx2tsdb
| 参数 | 默认值 | 说明 |
|---|---|---|
--name NAME |
influx2tsdb |
实例名 |
--pg-name NAME |
— | 本地 pgcli 实例作为目标;与 --dsn 互斥 |
--dsn DSN |
— | postgres://user:pass@host:port/db 目标;与 --pg-name 互斥 |
--database DB |
目标库名 | 默认 InfluxDB 数据库(-db) |
--port N |
自动(基址 8087) |
HTTP 宿主端口;0 = 自动分配 |
--pool-size N |
10 |
PostgreSQL 连接池大小 |
--verbose |
false | 输出翻译后的 SQL |
--version V |
1.3.2 |
固定的镜像发行版 |
--force |
false | 重写设置并重建容器 |
pg addon start|stop|remove influx2tsdb
| 命令 | 参数 | 说明 |
|---|---|---|
pg addon start influx2tsdb |
--name NAME |
启动(重建)容器;本地目标会先做运行检查 |
pg addon stop influx2tsdb |
--name NAME |
停止容器 |
pg addon remove influx2tsdb |
--name NAME、--clean-data |
删除容器与配置条目;数据留在 PostgreSQL |
pg addon influx2tsdb status
| 参数 | 默认值 | 说明 |
|---|---|---|
--name NAME |
influx2tsdb |
要查看的实例(状态、ping、目标、数据库、端口) |
pg logs addon influx2tsdb
| 参数 | 默认值 | 说明 |
|---|---|---|
--name NAME |
influx2tsdb |
要查看容器日志的实例 |
-n N、--tail N |
50 |
行数 |
-f、--follow |
false | 持续跟踪 |
pg autostart enable|disable
| 参数 | 说明 |
|---|---|
--influx2tsdb |
选择该代理插件 |
--name NAME |
要切换的实例(默认 influx2tsdb) |
全局参数
| 参数 | 说明 |
|---|---|
-c, --config FILE |
配置文件(默认 ~/.pgcli/pg.yaml) |
-o, --output FILE |
输出配置路径 |
-i, --instance NAME |
PostgreSQL 实例选择器——此处不使用;请用 --name |