# 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 做历史分页查询。 每一步都必须执行命令并检查输出后,才能标记为已验证。 ## 必需运行参数 启动服务前先设置: ```bash export KAFKA_BROKERS=114.55.58.251:9092 export TDENGINE_HISTORY_ENABLED=true export TDENGINE_JDBC_URL='jdbc:TAOS-RS://:6041/vehicle_history' export TDENGINE_USERNAME=root export TDENGINE_PASSWORD='' export TDENGINE_MIN_IDLE=0 export TDENGINE_MAX_POOL_SIZE=32 ``` `TDENGINE_MIN_IDLE=0` 用于减少冷启动时 TDengine 连接重试日志。TDengine 地址稳定后,再按生产并发调大连接池。 ## 构建 ```bash 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 端口 ```bash HTTP_PORT=20400 \ JT808_PORT=808 \ KAFKA_CONSUMER_ENABLED=false \ java -jar modules/apps/jt808-ingest-app/target/jt808-ingest-app.jar ``` 验证: ```bash curl -sS http://127.0.0.1:20400/actuator/health lsof -nP -iTCP:808 -sTCP:LISTEN ``` 预期:健康检查为 `UP`,并且 Java 进程监听 TCP `808`。 ## 启动 GB32960 接入服务 ```bash HTTP_PORT=20100 \ GB32960_PORT=32960 \ KAFKA_CONSUMER_ENABLED=false \ java -jar modules/apps/gb32960-ingest-app/target/gb32960-ingest-app.jar ``` 验证: ```bash curl -sS http://127.0.0.1:20100/actuator/health lsof -nP -iTCP:32960 -sTCP:LISTEN ``` ## 启动 TDengine 版历史服务 ```bash 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 ``` 验证: ```bash 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' ``` 预期:健康检查为 `UP`,OpenAPI 中包含这两个 TDengine 查询接口。 ## 本机 launchctl 部署 当前本机生产验证建议使用仓库模板生成 plist: ```bash deploy/local/launchctl/ ``` 关键约束: - `jt808-ingest-app` 监听 TCP `808`,HTTP `20482`。 - `gb32960-ingest-app` 监听 TCP `32960`,HTTP `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=file` 或 `memory`。 - 生产需要把 0x0100 注册信息维护到 MySQL 时,设置 `VEHICLE_IDENTITY_STORE=mysql`。 - 需要提供 `VEHICLE_IDENTITY_MYSQL_JDBC_URL`、`VEHICLE_IDENTITY_MYSQL_USERNAME`、`VEHICLE_IDENTITY_MYSQL_PASSWORD`。 - 服务启动时自动创建 `vehicle_identity_binding` 表,按 `protocol + identifier_type + identifier_value` 维护 VIN 绑定。 - MySQL 绑定在启动时加载到内存索引,注册/补写时写穿 MySQL 并刷新内存索引;帧解析热路径只查内存,不按帧访问 MySQL。 - 绑定类型包括 `PHONE`、`DEVICE_ID`、`PLATE`;后续同一终端上报 raw/event 时会优先解析成已绑定 VIN。 健康检查: ```bash 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.v1` 和 `vehicle.raw.jt808.v1` 有新增记录。 - `vehicle-history-app` 日志没有持续出现 consumer 或 TDengine 写入失败。 消费完成后,使用已知终端手机号查询: ```bash curl -sS 'http://127.0.0.1:20200/api/event-history/jt808/locations?phone=&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&limit=10' ``` 预期:响应包含 `items`,并且每条记录包含 `eventTime`、`phone`、`longitude`、`latitude`、`speedKmh`、`rawUri`、`metadataJson`。 ## Telemetry Field 查询验收 查询 GB32960 字段历史: ```bash curl -sS 'http://127.0.0.1:20200/api/event-history/telemetry/fields?protocol=GB32960&vin=&fieldKey=&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&limit=10' ``` 查询 JT808 字段历史。没有 VIN 映射时,优先使用 `phone`: ```bash curl -sS 'http://127.0.0.1:20200/api/event-history/telemetry/fields?protocol=JT808&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` 里的 `cursorTs` 和 `cursorId` 查询。 ## TDengine 直接检查 使用 TDengine CLI 或 JDBC 客户端检查超级表和子表是否创建: ```sql USE vehicle_history; SHOW STABLES; SELECT COUNT(*) FROM raw_frames; SELECT COUNT(*) FROM vehicle_locations; SELECT COUNT(*) FROM telemetry_fields; ``` 预期: - `raw_frames`、`vehicle_locations`、`telemetry_fields` 存在。 - 有实时流量后,计数持续增加。 ## 失败语义 - TDengine 不可达时,TDengine 查询接口应该返回 HTTP `503`,消息类似 `tdengine history query failed`。 - TDengine 未启用时,TDengine 专属接口不应该出现在 OpenAPI 中。 - 路径不存在时,API 层应该返回 HTTP `404`,而不是泛化的存储失败。 ## 2026-06-29 本机实时链路验证结果 运行服务: - `com.lingniu.jt808.808`: `jt808-ingest-app`,TCP `808`,HTTP `20482` - `com.lingniu.gb32960.32960`: `gb32960-ingest-app`,TCP `32960`,HTTP `20100` - `com.lingniu.vehicle-history.jt808`: `vehicle-history-app`,HTTP `20200` 健康检查已确认三个服务均返回 `{"status":"UP"}`。 JT808 真实转发链路已验证: - 本机 TCP `808` 有外部平台持续发送 JT808 报文。 - `vehicle.raw.jt808.v1` 和 `vehicle.event.jt808.v1` 被 history 消费。 - `raw_frames` 中 `protocol='JT808'` 的真实行数已超过 `6000`。 - `vehicle_locations` 中 `protocol='JT808'` 的位置行数已超过 `1900`。 - `telemetry_fields` 中 `protocol='JT808'` 的字段行数已超过 `15000`。 - 最新样例包含终端号 `13079963310`、消息 ID `512`、`archive://2026/06/29/JT808/...` 原始帧引用。 - 合成 0x0100 注册帧终端号 `13079969999` 已验证:TCP `808` 返回 `0x8100` 注册 ACK,`raw_frames.metadata_json` 包含 `jt808.register.province`、`jt808.register.city`、`jt808.register.maker`、`jt808.register.deviceType`、`jt808.register.deviceId`、`jt808.register.plateColor`、`jt808.register.plate`,对应 raw archive 文件存在。 复查 SQL: ```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: ```bash 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.4`、`totalMileageKm=223456.7`、`longitude=116.397128`、`latitude=39.916527`。 复查 SQL: ```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: ```bash 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://:6041/vehicle_ts`。 - `KAFKA_CONSUMER_AUTO_OFFSET_RESET=latest` 适合生产接入新流量;如果要回放历史 Kafka 数据,需要切换 consumer group 或重置 offset。 - `vehicle-history-app` raw 和 event 使用不同 consumer binding;raw consumer 必须开启,否则 `raw_frames` 不会持续增长。 - JT808 设备没有 VIN 映射时,`vehicle_key` 使用 `jt808:`;启用 MySQL identity store 后,注册维护的 phone/deviceId/plate 绑定会用于后续 raw/event 的 VIN 解析。