Files
lingniu-vehicle-ingest/docs/operations/vehicle-ingest-tdengine-verification.md
lingniu f00d851f2a
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
perf: cache mysql vehicle identity lookups
2026-06-29 17:00:54 +08:00

11 KiB
Raw Blame History

Vehicle Ingest TDengine 链路验收手册

这份手册用于验收当前 32960/JT808 接入重构链路:

  1. 协议 App 接收 TCP 报文。
  2. 协议 App 归档原始帧元数据,并把事件信封发布到 Kafka。
  3. vehicle-history-app 消费 Kafka。
  4. history 写入 raw、location、telemetry field 到 TDengine。
  5. Swagger/API 通过 TDengine 做历史分页查询。

每一步都必须执行命令并检查输出后,才能标记为已验证。

必需运行参数

启动服务前先设置:

export KAFKA_BROKERS=114.55.58.251:9092
export TDENGINE_HISTORY_ENABLED=true
export TDENGINE_JDBC_URL='jdbc:TAOS-RS://<tdengine-host>:6041/vehicle_history'
export TDENGINE_USERNAME=root
export TDENGINE_PASSWORD='<tdengine-password>'
export TDENGINE_MIN_IDLE=0
export TDENGINE_MAX_POOL_SIZE=32

TDENGINE_MIN_IDLE=0 用于减少冷启动时 TDengine 连接重试日志。TDengine 地址稳定后,再按生产并发调大连接池。

构建

mvn -pl modules/apps/jt808-ingest-app,modules/apps/gb32960-ingest-app,modules/apps/vehicle-history-app -am package -DskipTests

预期产物:

  • modules/apps/jt808-ingest-app/target/jt808-ingest-app.jar
  • modules/apps/gb32960-ingest-app/target/gb32960-ingest-app.jar
  • modules/apps/vehicle-history-app/target/vehicle-history-app.jar

启动 JT808 接入服务,监听 808 端口

HTTP_PORT=20400 \
JT808_PORT=808 \
KAFKA_CONSUMER_ENABLED=false \
java -jar modules/apps/jt808-ingest-app/target/jt808-ingest-app.jar

验证:

curl -sS http://127.0.0.1:20400/actuator/health
lsof -nP -iTCP:808 -sTCP:LISTEN

预期:健康检查为 UP,并且 Java 进程监听 TCP 808

启动 GB32960 接入服务

HTTP_PORT=20100 \
GB32960_PORT=32960 \
KAFKA_CONSUMER_ENABLED=false \
java -jar modules/apps/gb32960-ingest-app/target/gb32960-ingest-app.jar

验证:

curl -sS http://127.0.0.1:20100/actuator/health
lsof -nP -iTCP:32960 -sTCP:LISTEN

启动 TDengine 版历史服务

HTTP_PORT=20200 \
KAFKA_CONSUMER_ENABLED=true \
EVENT_FILE_STORE_ENABLED=true \
EVENT_FILE_STORE_PATH=./target/tdengine-verification/event-store \
SINK_ARCHIVE_PATH=./target/tdengine-verification/archive \
java -jar modules/apps/vehicle-history-app/target/vehicle-history-app.jar

验证:

curl -sS http://127.0.0.1:20200/actuator/health
curl -sS http://127.0.0.1:20200/v3/api-docs \
  | grep -E '/api/event-history/jt808/locations|/api/event-history/telemetry/fields'

预期:健康检查为 UPOpenAPI 中包含这两个 TDengine 查询接口。

本机 launchctl 部署

当前本机生产验证建议使用仓库模板生成 plist

deploy/local/launchctl/

关键约束:

  • jt808-ingest-app 监听 TCP 808HTTP 20482
  • gb32960-ingest-app 监听 TCP 32960HTTP 20100
  • vehicle-history-app 监听 HTTP 20200
  • 三个服务必须共用同一个 SINK_ARCHIVE_PATH,否则 TDengine 中的 raw_uri 能入库,但 history API 无法按 archive://... 读取原始帧。
  • 替换 jar 前先 launchctl bootout,再复制 jar 和 launchctl bootstrap,避免 KeepAlive 在 jar 拷贝中途重启。

JT808 注册身份绑定:

  • 默认可以使用 VEHICLE_IDENTITY_STORE=filememory
  • 生产需要把 0x0100 注册信息维护到 MySQL 时,设置 VEHICLE_IDENTITY_STORE=mysql
  • 需要提供 VEHICLE_IDENTITY_MYSQL_JDBC_URLVEHICLE_IDENTITY_MYSQL_USERNAMEVEHICLE_IDENTITY_MYSQL_PASSWORD
  • 服务启动时自动创建 vehicle_identity_binding 表,按 protocol + identifier_type + identifier_value 维护 VIN 绑定。
  • MySQL 绑定在启动时加载到内存索引,注册/补写时写穿 MySQL 并刷新内存索引;帧解析热路径只查内存,不按帧访问 MySQL。
  • 绑定类型包括 PHONEDEVICE_IDPLATE;后续同一终端上报 raw/event 时会优先解析成已绑定 VIN。

健康检查:

curl -sS http://127.0.0.1:20482/actuator/health
curl -sS http://127.0.0.1:20100/actuator/health
curl -sS http://127.0.0.1:20200/actuator/health

Swagger

  • JT808 ingest: http://127.0.0.1:20482/swagger-ui/index.html
  • GB32960 ingest: http://127.0.0.1:20100/swagger-ui/index.html
  • History query: http://127.0.0.1:20200/swagger-ui/index.html

Kafka Topic 验证

历史服务必须消费事件 topic 和 raw topic

  • vehicle.event.gb32960.v1
  • vehicle.raw.gb32960.v1
  • vehicle.event.jt808.v1
  • vehicle.raw.jt808.v1

使用 Kafka CLI 或管理工具检查 topic 是否存在,并确认 vehicle-history consumer group 在测试流量后没有持续堆积。

JT808 实时转发验收

如果外部平台已经把 JT808 报文转发到本机 TCP 808,至少观察 60 秒日志和 Kafka 数据。

必须拿到以下证据:

  • jt808-ingest-app 日志显示接入连接或解析到上游消息 ID。
  • Kafka 的 vehicle.event.jt808.v1vehicle.raw.jt808.v1 有新增记录。
  • vehicle-history-app 日志没有持续出现 consumer 或 TDengine 写入失败。

消费完成后,使用已知终端手机号查询:

curl -sS 'http://127.0.0.1:20200/api/event-history/jt808/locations?phone=<phone>&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&limit=10'

预期:响应包含 items,并且每条记录包含 eventTimephonelongitudelatitudespeedKmhrawUrimetadataJson

Telemetry Field 查询验收

查询 GB32960 字段历史:

curl -sS 'http://127.0.0.1:20200/api/event-history/telemetry/fields?protocol=GB32960&vin=<vin>&fieldKey=<field-key>&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&limit=10'

查询 JT808 字段历史。没有 VIN 映射时,优先使用 phone

curl -sS 'http://127.0.0.1:20200/api/event-history/telemetry/fields?protocol=JT808&phone=<phone>&fieldKey=location.speed_kmh&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&limit=10'

预期:响应包含 items,可能包含 nextCursor。下一页使用 nextCursor 里的 cursorTscursorId 查询。

TDengine 直接检查

使用 TDengine CLI 或 JDBC 客户端检查超级表和子表是否创建:

USE vehicle_history;
SHOW STABLES;
SELECT COUNT(*) FROM raw_frames;
SELECT COUNT(*) FROM vehicle_locations;
SELECT COUNT(*) FROM telemetry_fields;

预期:

  • raw_framesvehicle_locationstelemetry_fields 存在。
  • 有实时流量后,计数持续增加。

失败语义

  • TDengine 不可达时TDengine 查询接口应该返回 HTTP 503,消息类似 tdengine history query failed
  • TDengine 未启用时TDengine 专属接口不应该出现在 OpenAPI 中。
  • 路径不存在时API 层应该返回 HTTP 404,而不是泛化的存储失败。

2026-06-29 本机实时链路验证结果

运行服务:

  • com.lingniu.jt808.808: jt808-ingest-appTCP 808HTTP 20482
  • com.lingniu.gb32960.32960: gb32960-ingest-appTCP 32960HTTP 20100
  • com.lingniu.vehicle-history.jt808: vehicle-history-appHTTP 20200

健康检查已确认三个服务均返回 {"status":"UP"}

JT808 真实转发链路已验证:

  • 本机 TCP 808 有外部平台持续发送 JT808 报文。
  • vehicle.raw.jt808.v1vehicle.event.jt808.v1 被 history 消费。
  • raw_framesprotocol='JT808' 的真实行数已超过 6000
  • vehicle_locationsprotocol='JT808' 的位置行数已超过 1900
  • telemetry_fieldsprotocol='JT808' 的字段行数已超过 15000
  • 最新样例包含终端号 13079963310、消息 ID 512archive://2026/06/29/JT808/... 原始帧引用。
  • 合成 0x0100 注册帧终端号 13079969999 已验证TCP 808 返回 0x8100 注册 ACKraw_frames.metadata_json 包含 jt808.register.provincejt808.register.cityjt808.register.makerjt808.register.deviceTypejt808.register.deviceIdjt808.register.plateColorjt808.register.plate,对应 raw archive 文件存在。

复查 SQL

USE vehicle_ts;
SELECT COUNT(*) FROM raw_frames WHERE protocol = 'JT808';
SELECT COUNT(*) FROM vehicle_locations WHERE protocol = 'JT808';
SELECT COUNT(*) FROM telemetry_fields WHERE protocol = 'JT808';
SELECT event_time, vehicle_key, phone, message_id, raw_uri
  FROM raw_frames
  WHERE protocol = 'JT808'
  ORDER BY event_time DESC
  LIMIT 5;
SELECT ts, frame_id, phone, message_id, metadata_json, raw_uri
  FROM raw_frames
  WHERE protocol = 'JT808' AND phone = '13079969999' AND message_id = 256
  ORDER BY ts DESC
  LIMIT 3;

复查 API

curl -sS 'http://127.0.0.1:20200/api/event-history/jt808/locations?phone=13079963296&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&limit=10'

GB32960 链路已用合成实时帧验证:

  • TCP 32960 返回 GB32960 2323 ACK。
  • raw_frames 中测试 VIN LTEST202606290001 已有 2 条 raw 记录。
  • telemetry_fields 中测试 VIN LTEST202606290001 已有 34 条字段记录。
  • latest raw 包含 archive://2026/06/29/GB32960/LTEST202606290001/...
  • snapshots API 可查到 speedKmh=62.4totalMileageKm=223456.7longitude=116.397128latitude=39.916527

复查 SQL

USE vehicle_ts;
SELECT COUNT(*) FROM raw_frames
  WHERE protocol = 'GB32960' AND vin = 'LTEST202606290001';
SELECT COUNT(*) FROM telemetry_fields
  WHERE protocol = 'GB32960' AND vin = 'LTEST202606290001';
SELECT event_time, vin, raw_uri, raw_id
  FROM raw_frames
  WHERE protocol = 'GB32960' AND vin = 'LTEST202606290001'
  ORDER BY event_time DESC
  LIMIT 5;

复查 API

curl -sS 'http://127.0.0.1:20200/api/event-history/gb32960/snapshots?vin=LTEST202606290001&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&limit=10'
curl -sS 'http://127.0.0.1:20200/api/event-history/gb32960/snapshots/fields?vin=LTEST202606290001&fields=VEHICLE.speedKmh,VEHICLE.totalMileageKm,POSITION_V2016.longitude,POSITION_V2016.latitude&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&limit=10'

当前注意事项

  • 当前本机使用 TDengine WebSocket JDBC例如 jdbc:TAOS-WS://<tdengine-host>:6041/vehicle_ts
  • KAFKA_CONSUMER_AUTO_OFFSET_RESET=latest 适合生产接入新流量;如果要回放历史 Kafka 数据,需要切换 consumer group 或重置 offset。
  • vehicle-history-app raw 和 event 使用不同 consumer bindingraw consumer 必须开启,否则 raw_frames 不会持续增长。
  • JT808 设备没有 VIN 映射时,vehicle_key 使用 jt808:<phone>;启用 MySQL identity store 后,注册维护的 phone/deviceId/plate 绑定会用于后续 raw/event 的 VIN 解析。