feat: 内置 TDengine 时序库,自动建库建表
此前编排不含时序库,首页流量/用量图表、单卡流量历史等依赖时序数据的功能 不可用。现补上: - 新增 tdengine 服务(镜像 iotlcm/iotlcm:tdengine-3.3.6.13) 端口 6041(taosAdapter/WebSocket,应用用这个)+ 6030,数据卷 ./data/tdengine - 新增 tdengine-init 一次性服务:等 tdengine 健康后建库建表,并校验超级表存在, 缺表则以非零码退出 - 建库建表 SQL 取自生产环境 SHOW CREATE STABLE(仅结构无数据): iotlcm_daily DURATION 7d KEEP 1095d ms -> t_sim_card_usage_daily iotlcm_monthly DURATION 30d KEEP 1095d ms -> t_sim_card_usage_monthly - 三个服务的 tsdb.tdengine 配置指向 tdengine:6041(admin-svr / app-server / worker-svr) 踩坑记录:taos -f 是按行执行语句的,多行 CREATE STABLE 会报 Incomplete SQL statement,因此 SQL 必须单行;且 taos 出错时退出码仍为 0, 故 run.sh 额外做超级表校验。 已验证:初始化 4 条语句全部 Create OK、0 error;按 worker 的 INSERT 形式 (USING ... TAGS)写入成功、按 admin 的查询形式(SELECT ts,usage_mb,package_code,iccid) 可读回;整栈 15 个服务全 Up,admin-svr/openapi/sms/docs 均 200,worker 无时序库报错。
This commit is contained in:
@@ -62,7 +62,7 @@ tag 格式统一为 **`<服务名>-<版本>`**。
|
||||
|
||||
| 类别 | 服务 |
|
||||
| --- | --- |
|
||||
| 基础组件 | MySQL、Redis、RabbitMQ、Consul |
|
||||
| 基础组件 | MySQL、Redis、RabbitMQ、Consul、TDengine(流量历史) |
|
||||
| 业务服务 | admin-svr(管理端后端)、admin-ui(管理端前端)、openapi(对外 API)、app-server(小程序后端)、app-web(小程序前端)、upstream-chan(运营商对接)、upstream-proxy(通道缓存转发)、worker-svr(异步任务)、sms(短信)、docs(文档站) |
|
||||
| 可选 | onelink-mock(运营商接口挡板)、bot(飞书通知)、nginx(反向代理) |
|
||||
|
||||
@@ -82,13 +82,23 @@ iotlcm-deploy/
|
||||
│ ├── upstream-chan/config.yaml
|
||||
│ ├── upstream-proxy/config.yaml
|
||||
│ └── worker-svr/config.yaml
|
||||
├── schema/init.sql # 数据库初始化(单文件,首次启动自动执行)
|
||||
├── schema/init.sql # MySQL 初始化(单文件,首次启动自动执行)
|
||||
├── tdengine-init/ # TDengine 建库建表(首次启动自动执行)
|
||||
└── data/ # 运行数据(首次启动自动创建,不入版本库)
|
||||
```
|
||||
|
||||
全新初始化生成 95 张业务表(原有 91 张 + worker 异步恢复所需 4 张);已部署旧库不会自动执行新增迁移,见 `schema/README.md`。
|
||||
|
||||
本编排不包含 TDengine。默认配置中的时序库名称留空,因此首页流量/用量图表等依赖时序数据的功能不能仅靠上述容器完整展示;需要自行部署 TDengine,并在相关服务的 `config.yaml` 中配置连接及数据库名称。管理端登录、菜单、卡信息筛选不依赖这项配置。
|
||||
编排已内置 TDengine(流量历史库),由 `tdengine-init` 服务在 TDengine 健康后自动建库建表:
|
||||
|
||||
| 库 | 分片 | 保留 | 超级表 |
|
||||
| --- | --- | --- | --- |
|
||||
| `iotlcm_daily` | 7 天 | 3 年 | `t_sim_card_usage_daily` |
|
||||
| `iotlcm_monthly` | 30 天 | 3 年 | `t_sim_card_usage_monthly` |
|
||||
|
||||
结构取自生产环境,`tdengine-init` 会校验建表结果,缺表则报错退出。业务代码只读写不建表,因此这一步不能跳过。
|
||||
|
||||
TDengine 版本为 `3.3.6.13`(公开镜像可得),生产用的是 `3.4.0.9`。两者在流量历史的读写上一致;如需与生产完全对齐,可自行构建镜像并替换 `docker-compose.yml` 里的 tag。
|
||||
|
||||
## 上线前必改
|
||||
|
||||
|
||||
@@ -179,10 +179,13 @@ tsdb:
|
||||
database: "TdEngine"
|
||||
tdengine:
|
||||
type: "taosWS"
|
||||
dsn: ":@ws(:)/"
|
||||
dbName: ""
|
||||
dailyDbName: ""
|
||||
monthlyDbName: ""
|
||||
# TDengine 3.x WebSocket 地址(容器内服务名 tdengine,端口 6041)
|
||||
# 口令为 TDengine 默认 root/taosdata;改过口令需同步改这里
|
||||
dsn: "root:taosdata@ws(tdengine:6041)/"
|
||||
# dbName 只是连接池键名与兜底值,不决定实际访问哪个库
|
||||
dbName: "iotlcm_daily"
|
||||
dailyDbName: "iotlcm_daily"
|
||||
monthlyDbName: "iotlcm_monthly"
|
||||
maxOpenConns: 100
|
||||
maxIdleConns: 10
|
||||
|
||||
|
||||
@@ -197,10 +197,13 @@ tsdb:
|
||||
database: "TdEngine"
|
||||
tdengine:
|
||||
type: "taosWS"
|
||||
dsn: ":@ws(:)/"
|
||||
dbName: ""
|
||||
dailyDbName: ""
|
||||
monthlyDbName: ""
|
||||
# TDengine 3.x WebSocket 地址(容器内服务名 tdengine,端口 6041)
|
||||
# 口令为 TDengine 默认 root/taosdata;改过口令需同步改这里
|
||||
dsn: "root:taosdata@ws(tdengine:6041)/"
|
||||
# dbName 只是连接池键名与兜底值,不决定实际访问哪个库
|
||||
dbName: "iotlcm_daily"
|
||||
dailyDbName: "iotlcm_daily"
|
||||
monthlyDbName: "iotlcm_monthly"
|
||||
maxOpenConns: 100
|
||||
maxIdleConns: 10
|
||||
|
||||
|
||||
@@ -121,11 +121,13 @@ tsdb:
|
||||
database: "TdEngine"
|
||||
tdengine:
|
||||
type: "taosWS"
|
||||
dsn: ":@ws(:)/"
|
||||
# TDengine 3.x WebSocket 地址(容器内服务名 tdengine,端口 6041)
|
||||
# 口令为 TDengine 默认 root/taosdata;改过口令需同步改这里
|
||||
dsn: "root:taosdata@ws(tdengine:6041)/"
|
||||
# dbName 只是连接池键名与兜底值,不决定实际访问哪个库
|
||||
dbName: ""
|
||||
dailyDbName: ""
|
||||
monthlyDbName: ""
|
||||
dbName: "iotlcm_daily"
|
||||
dailyDbName: "iotlcm_daily"
|
||||
monthlyDbName: "iotlcm_monthly"
|
||||
maxOpenConns: 100
|
||||
maxIdleConns: 10
|
||||
|
||||
|
||||
@@ -91,6 +91,42 @@ services:
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
# 时序数据库:存流量历史(daily / monthly),worker-svr 全量同步写这里
|
||||
tdengine:
|
||||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:tdengine-3.3.6.13'
|
||||
container_name: iotlcm-tdengine
|
||||
restart: always
|
||||
ports:
|
||||
- "${TDENGINE_PORT:-6041}:6041" # taosAdapter(WebSocket,应用用这个)
|
||||
- "${TDENGINE_NATIVE_PORT:-6030}:6030"
|
||||
environment:
|
||||
TZ: '${TZ:-Asia/Shanghai}'
|
||||
volumes:
|
||||
- ./data/tdengine/data:/var/lib/taos
|
||||
- ./data/tdengine/log:/var/log/taos
|
||||
networks:
|
||||
- iotlcm-network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://127.0.0.1:6041/-/ping || exit 1"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
|
||||
# 建库建表:业务代码不负责建 TDengine 库表,由本服务在 tdengine 健康后执行一次
|
||||
tdengine-init:
|
||||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:tdengine-3.3.6.13'
|
||||
container_name: iotlcm-tdengine-init
|
||||
restart: "no"
|
||||
entrypoint: ["sh", "/init/run.sh"]
|
||||
volumes:
|
||||
- ./tdengine-init:/init:ro
|
||||
depends_on:
|
||||
tdengine:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- iotlcm-network
|
||||
|
||||
consul:
|
||||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:consul-1.22'
|
||||
container_name: iotlcm-consul
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
-- ============================================================
|
||||
-- TDengine 初始化:流量历史库与超级表
|
||||
--
|
||||
-- 结构取自生产环境(SHOW CREATE STABLE 导出),仅结构、无数据。
|
||||
-- 由 compose 的 tdengine-init 服务在 tdengine 健康后执行。
|
||||
--
|
||||
-- 注意:`taos -f` 是**按行**执行语句的,每条 SQL 必须写在一行内,
|
||||
-- 跨行会被判为 "Incomplete SQL statement"。改本文件时务必保持单行。
|
||||
--
|
||||
-- 业务代码(worker-svr / admin-svr)只连接读写,不负责建库建表,
|
||||
-- 因此这一步必须在首次启动时完成,否则单卡流量重试写入会报库表不存在。
|
||||
-- ============================================================
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS iotlcm_daily PRECISION 'ms' KEEP 1095d DURATION 7d;
|
||||
CREATE DATABASE IF NOT EXISTS iotlcm_monthly PRECISION 'ms' KEEP 1095d DURATION 30d;
|
||||
CREATE STABLE IF NOT EXISTS iotlcm_daily.t_sim_card_usage_daily (ts TIMESTAMP, usage_mb DOUBLE, package_code VARCHAR(128)) TAGS (iccid VARCHAR(64));
|
||||
CREATE STABLE IF NOT EXISTS iotlcm_monthly.t_sim_card_usage_monthly (ts TIMESTAMP, usage_mb DOUBLE, package_code VARCHAR(128)) TAGS (iccid VARCHAR(64));
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
# ============================================================
|
||||
# TDengine 初始化执行脚本
|
||||
#
|
||||
# 由 compose 的 tdengine-init 服务调用,在 tdengine 健康后执行一次。
|
||||
# 做三件事:
|
||||
# 1. 过滤掉 init.sql 里的注释与空行(taos -f 会逐行执行,
|
||||
# 注释行会被当成不完整 SQL 报错)
|
||||
# 2. 执行建库建表
|
||||
# 3. 校验超级表确实存在,缺表则以非零码退出(让 compose 暴露失败)
|
||||
# ============================================================
|
||||
set -eu
|
||||
|
||||
echo "[tdengine-init] 准备 SQL(过滤注释与空行)"
|
||||
grep -vE '^[[:space:]]*(--|$)' /init/init.sql > /tmp/init.sql
|
||||
echo "[tdengine-init] 待执行语句数:$(wc -l < /tmp/init.sql)"
|
||||
|
||||
echo "[tdengine-init] 执行建库建表"
|
||||
taos -h tdengine -f /tmp/init.sql
|
||||
|
||||
echo "[tdengine-init] 校验超级表"
|
||||
missing=0
|
||||
for pair in "iotlcm_daily:t_sim_card_usage_daily" "iotlcm_monthly:t_sim_card_usage_monthly"; do
|
||||
db=${pair%%:*}
|
||||
stable=${pair##*:}
|
||||
if taos -h tdengine -s "show ${db}.stables;" 2>/dev/null | grep -q "$stable"; then
|
||||
echo " OK ${db}.${stable}"
|
||||
else
|
||||
echo " MISS ${db}.${stable}"
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$missing" -ne 0 ]; then
|
||||
echo "[tdengine-init] 失败:超级表缺失,请检查 taos 输出"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[tdengine-init] 完成"
|
||||
Reference in New Issue
Block a user