19 KiB
Vehicle Ingest TDengine 链路验收手册
这份手册用于验收当前 32960/JT808 接入重构链路:
- 协议 App 接收 TCP 报文。
- 协议 App 归档原始帧元数据,并把事件信封发布到 Kafka。
vehicle-history-app消费 Kafka。- history 写入 raw、location 到 TDengine;按需开启 telemetry field 逐字段宽表。
- Swagger/API 通过 TDengine 做历史分页查询。
每一步都必须执行命令并检查输出后,才能标记为已验证。
必需运行参数
启动服务前先设置:
export KAFKA_BROKERS=114.55.58.251:9092
export TDENGINE_HISTORY_ENABLED=true
export TDENGINE_HISTORY_DATABASE=vehicle_ts
export TDENGINE_JDBC_URL='jdbc:TAOS-WS://<tdengine-host>:6041/vehicle_ts'
export TDENGINE_DRIVER_CLASS_NAME=com.taosdata.jdbc.ws.WebSocketDriver
export TDENGINE_USERNAME=root
export TDENGINE_PASSWORD='<tdengine-password>'
export TDENGINE_MIN_IDLE=0
export TDENGINE_MAX_POOL_SIZE=32
export TDENGINE_TELEMETRY_FIELDS_ENABLED=false
TDENGINE_MIN_IDLE=0 用于减少冷启动时 TDengine 连接重试日志。TDengine 地址稳定后,再按生产并发调大连接池。
高吞吐生产验收默认保持 TDENGINE_TELEMETRY_FIELDS_ENABLED=false,验证 TDengine raw_frames、位置表和分页查询闭环。RAW 帧的 parsedJson、metadataJson、rawUri 直接进入 TDengine,GB32960 snapshot/fields 接口基于 raw_frames 与当前解析器即时返回结构化结果;接入服务写出的原始 .bin 只作为冷备复核材料。需要逐字段趋势宽表时,再显式开启 TDENGINE_TELEMETRY_FIELDS_ENABLED=true,并单独压测写入放大。
构建
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.jarmodules/apps/gb32960-ingest-app/target/gb32960-ingest-app.jarmodules/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
curl -sS http://127.0.0.1:20400/actuator/health/liveness
curl -sS http://127.0.0.1:20400/actuator/health/readiness
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
curl -sS http://127.0.0.1:20100/actuator/health/liveness
curl -sS http://127.0.0.1:20100/actuator/health/readiness
lsof -nP -iTCP:32960 -sTCP:LISTEN
启动 TDengine 版历史服务
HTTP_PORT=20200 \
KAFKA_CONSUMER_ENABLED=true \
TDENGINE_TELEMETRY_FIELDS_ENABLED=false \
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/actuator/health/liveness
curl -sS http://127.0.0.1:20200/actuator/health/readiness
curl -sS http://127.0.0.1:20200/v3/api-docs \
| grep -E '/api/event-history/locations|/api/event-history/raw-frames'
预期:健康检查为 UP,OpenAPI 中包含通用位置分页查询和 RAW 帧查询接口。/api/event-history/telemetry/fields 只有在 TDENGINE_TELEMETRY_FIELDS_ENABLED=true 后才会暴露;默认高吞吐模式不暴露该接口,也不会持续写入逐字段宽表。
本机 launchctl 部署
当前本机生产验证建议使用仓库模板生成 plist:
deploy/local/launchctl/
关键约束:
jt808-ingest-app监听 TCP808,HTTP20400。gb32960-ingest-app监听 TCP32960,HTTP20100。vehicle-history-app监听 HTTP20200。- history 热查询只依赖 Kafka 和 TDengine
raw_frames;本地模板不会给 history 注入SINK_ARCHIVE_PATH。 - GB32960/JT808 接入服务可以继续使用
SINK_ARCHIVE_PATH保存原始.bin冷备,但这不是 history API 的实时查询前置条件。 - 替换 jar 前先
launchctl bootout,再复制 jar 和launchctl bootstrap,避免 KeepAlive 在 jar 拷贝中途重启。
JT808 注册身份绑定:
- 生产默认使用
VEHICLE_IDENTITY_STORE=mysql,不再使用 file/memory 作为运行时身份绑定仓储。 - 生产需要把 0x0100 注册信息维护到 MySQL 时,设置
VEHICLE_IDENTITY_STORE=mysql。 - 需要提供
VEHICLE_IDENTITY_MYSQL_JDBC_URL、VEHICLE_IDENTITY_MYSQL_USERNAME、VEHICLE_IDENTITY_MYSQL_PASSWORD。 - 服务启动时自动创建
vehicle_identity_binding和vehicle_identity_binding_registration两张表。vehicle_identity_binding只维护plate、vin两列;vehicle_identity_binding_registration按protocol + phone保存 JT808 0x0100 注册字段。 - 注册帧无真实 VIN 时也会写入 registration 表,
vin默认为unknown。外部系统识别车辆后只需要维护车牌和 VIN,例如:INSERT INTO vehicle_identity_binding (plate, vin) VALUES ('沪A61559F', 'LNVIN000000000001') ON DUPLICATE KEY UPDATE vin = VALUES(vin); - MySQL 绑定在启动时加载到内存索引,
plate/vin反写后会按VEHICLE_IDENTITY_MYSQL_REFRESH_INTERVAL周期刷新,默认60s;帧解析热路径只查内存,不按帧访问 MySQL。 - 后续同一终端上报 raw/event 时,服务会用 registration 表里的
phone/device_id/plate加绑定表里的plate/vin解析成真实 VIN。
健康检查:
curl -sS http://127.0.0.1:20400/actuator/health
curl -sS http://127.0.0.1:20400/actuator/health/liveness
curl -sS http://127.0.0.1:20400/actuator/health/readiness
curl -sS http://127.0.0.1:20100/actuator/health
curl -sS http://127.0.0.1:20100/actuator/health/liveness
curl -sS http://127.0.0.1:20100/actuator/health/readiness
curl -sS http://127.0.0.1:20200/actuator/health
curl -sS http://127.0.0.1:20200/actuator/health/liveness
curl -sS http://127.0.0.1:20200/actuator/health/readiness
Swagger:
- JT808 ingest:
http://127.0.0.1:20400/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.v1vehicle.raw.gb32960.v1vehicle.event.jt808.v1vehicle.raw.jt808.v1
使用 Kafka CLI 或管理工具检查 topic 是否存在,并确认 history consumer group 在测试流量后没有持续堆积。默认 KAFKA_GROUP_HISTORY=vehicle-history 时,实际 group 会拆成:
vehicle-history-gb32960-eventvehicle-history-gb32960-rawvehicle-history-jt808-eventvehicle-history-jt808-raw
JT808 实时转发验收
如果外部平台已经把 JT808 报文转发到本机 TCP 808,至少观察 60 秒日志和 Kafka 数据。
必须拿到以下证据:
jt808-ingest-app日志显示接入连接或解析到上游消息 ID。- Kafka 的
vehicle.event.jt808.v1和vehicle.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,并且每条记录包含 eventTime、phone、longitude、latitude、speedKmh、rawUri、metadataJson。
GB32960 Snapshot / 字段投影验收
默认高吞吐模式下,GB32960 全字段查询不依赖 telemetry_fields 宽表。history 先查 TDengine raw_frames,直接使用 RAW 行中的 parsedJson/parsedFields 生成 snapshot 和字段投影:
curl -sS 'http://127.0.0.1:20200/api/event-history/gb32960/snapshots?vin=<vin>&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=<vin>&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'
预期:snapshot 返回 sourceFrames.rawArchiveUri 和解析后的 blocks;字段投影返回所选字段。新增协议字段后,先通过 replay 或专用解析任务补写 raw_frames.parsedJson,再基于历史 RAW 结构化结果查询。
Telemetry Field 查询验收
查询 GB32960 字段历史。该能力需要 TDENGINE_TELEMETRY_FIELDS_ENABLED=true 并确认压测后无持续 lag:
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。该能力同样需要 TDENGINE_TELEMETRY_FIELDS_ENABLED=true:
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 里的 cursorTs 和 cursorId 查询。
TDengine 直接检查
使用 TDengine CLI 或 JDBC 客户端检查超级表和子表是否创建:
USE vehicle_ts;
SHOW STABLES;
SELECT COUNT(*) FROM raw_frames;
SELECT COUNT(*) FROM vehicle_locations;
SELECT COUNT(*) FROM jt808_locations;
-- 仅在 TDENGINE_TELEMETRY_FIELDS_ENABLED=true 时检查:
SELECT COUNT(*) FROM telemetry_fields;
预期:
raw_frames、vehicle_locations、jt808_locations存在;有对应协议实时流量后,计数持续增长。telemetry_fields表结构会创建;默认高吞吐模式不会持续增长,除非显式开启TDENGINE_TELEMETRY_FIELDS_ENABLED=true。- 有实时流量后,计数持续增加。
失败语义
- TDengine 不可达时,TDengine 查询接口应该返回 HTTP
503,消息类似tdengine history query failed。 - TDengine 未启用时,TDengine 专属接口不应该出现在 OpenAPI 中。
- 路径不存在时,API 层应该返回 HTTP
404,而不是泛化的存储失败。
2026-06-29 本机实时链路验证结果
运行服务:
com.lingniu.jt808.808:jt808-ingest-app,TCP808,HTTP20400com.lingniu.gb32960.32960:gb32960-ingest-app,TCP32960,HTTP20100com.lingniu.vehicle-history.jt808:vehicle-history-app,HTTP20200
健康检查已确认三个服务均返回 {"status":"UP"}。
可重复运行 live 验收工具:
python3 tools/vehicle_ingest_live_verify.py \
--tdengine-rest-url 'http://115.29.185.82:6041/rest/sql/vehicle_ts' \
--tdengine-username root \
--tdengine-password '<tdengine-password>' \
--history-base-url 'http://127.0.0.1:20200' \
--date-from '2026-06-29 00:00:00' \
--date-to '2026-06-29 23:59:59' \
--jt808-peer-like '222.66.200.68:%' \
--gb32960-peer-like '115.29.187.205:%'
该工具输出 pass、warn 或 fail:当前正式 GB32960 只有平台登录、没有车辆 0x02 时会输出 warn,避免把平台在线误判为车辆数据在线。正式车辆数据验收时增加 --require-gb32960-vehicle-realtime,缺少非测试 VIN 的 0x02 会直接返回非 0 退出码。
JT808 真实转发链路已验证:
- 本机 TCP
808有外部平台222.66.200.68持续发送 JT808 报文。 vehicle.raw.jt808.v1和vehicle.event.jt808.v1被 history 消费。raw_frames中protocol='JT808'的真实行数已超过36000。- 外部平台真实 0x0100 注册帧已超过
347条,真实 0x0200 位置帧已超过12400条。 jt808_locations中位置行数已超过8783。- 在旧的字段宽表开启模式下,
telemetry_fields中protocol='JT808'的字段行数曾超过15000;当前高吞吐默认不要求该表持续增长。 - 分页 API 已用终端号
13079963301验证第一页和 nextCursor 第二页,样例位置包含longitude=118.913846、latitude=31.927309、statusFlag=3和archive://2026/06/29/JT808/...原始帧引用。 - 注册帧样例:终端号
13079963320、deviceId9963320、deviceTypeSEG-9888G、plate沪A61559F、maker70112、province31、city113、plateColor2。生产 VIN 反写依赖 MySQL identity store,后续 raw/event 的 VIN 解析也从 MySQL 绑定读取。
JT808 本机 smoke / 轻压测工具
仓库提供 tools/jt808_e2e_smoke.py,用于重复验证 TCP 808 到 TDengine history 的闭环:
export TDENGINE_REST_URL='http://<tdengine-host>:6041/rest/sql/vehicle_ts'
export TDENGINE_USERNAME='root'
export TDENGINE_PASSWORD='<tdengine-password>'
python3 tools/jt808_e2e_smoke.py \
--connection-mode session \
--start-phone 13079962000 \
--frames 3 \
--expect-history-count 3 \
--verify-pagination \
--archive-root "$PROJECT_ROOT/data/archive-jt808" \
--tdengine-rest-url "$TDENGINE_REST_URL" \
--tdengine-username "$TDENGINE_USERNAME" \
--tdengine-password "$TDENGINE_PASSWORD"
默认 --connection-mode per-frame,适合单帧连接 smoke。生产验收建议使用 --connection-mode session 覆盖同一连接内连续位置帧。脚本会输出发送数量、history 可见数量、分页验证结果、raw archive 检查结果和 tdengineRawFrames。tdengineRawFrames 表示本次可见位置记录中的唯一 rawUri 有多少个已确认写入 TDengine raw_frames。
- 合成 0x0100 注册帧终端号
13079969999已验证:TCP808返回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:
USE vehicle_ts;
SELECT COUNT(*) FROM raw_frames WHERE protocol = 'JT808';
SELECT COUNT(*) FROM jt808_locations WHERE protocol = 'JT808';
-- 仅在 TDENGINE_TELEMETRY_FIELDS_ENABLED=true 时复查:
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=13079963301&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&order=DESC&limit=3'
curl -sS 'http://127.0.0.1:20200/api/event-history/jt808/raw-frames?phone=13079963320&messageId=256&dateFrom=2026-06-29T00:00:00%2B08:00&dateTo=2026-06-29T23:59:59%2B08:00&order=DESC&limit=3'
/api/event-history/jt808/raw-frames 用于排查注册、鉴权、心跳、位置等原始帧索引。返回项会保留 messageId、messageIdHex、rawUri、parseStatus、peer、vin、phone 和完整 metadataJson;注册帧的 metadataJson 包含 jt808.register.province、jt808.register.city、jt808.register.maker、jt808.register.deviceType、jt808.register.deviceId、jt808.register.plateColor、jt808.register.plate、identitySource、identityResolved 等字段。
GB32960 链路已用正式平台登录和合成实时帧验证:
- 正式平台
115.29.187.205已连接 TCP32960,服务收到0x05 PLATFORM_LOGIN并返回 ACK;日志显示账号Hyundai、策略ALLOW。 - 2026-06-29 正式平台登录 raw 已有
3条,均落入 TDengineraw_frames,可通过 RAW 查询看到parsedJson中的PLATFORM_LOGIN解析结果。 - 当前正式平台尚未发送车辆实时上报
0x02;非测试 VIN 的message_id=2计数为0,因此不能把平台登录误判为车辆数据在线。 - TCP
32960返回 GB329602323ACK。 raw_frames中测试 VINLTEST202606290001已有2条 raw 记录。- 在旧的字段宽表开启模式下,
telemetry_fields中测试 VINLTEST202606290001曾有34条字段记录;当前默认通过 GB32960 snapshot/fields 即时解析 raw,不要求该表增长。 - latest raw 包含
archive://2026/06/29/GB32960/LTEST202606290001/...。 - snapshots API 可查到
speedKmh=62.4、totalMileageKm=223456.7、longitude=116.397128、latitude=39.916527。
复查 SQL:
USE vehicle_ts;
SELECT COUNT(*) FROM raw_frames
WHERE protocol = 'GB32960' AND vin = 'LTEST202606290001';
-- 仅在 TDENGINE_TELEMETRY_FIELDS_ENABLED=true 时复查:
SELECT COUNT(*) FROM telemetry_fields
WHERE protocol = 'GB32960' AND vin = 'LTEST202606290001';
SELECT event_time, vin, raw_uri, frame_id
FROM raw_frames
WHERE protocol = 'GB32960' AND vin = 'LTEST202606290001'
ORDER BY event_time DESC
LIMIT 5;
SELECT ts, vin, message_id, event_time, raw_uri, peer, metadata_json
FROM raw_frames
WHERE protocol = 'GB32960' AND peer LIKE '115.29.187.205:%'
ORDER BY ts DESC
LIMIT 5;
SELECT COUNT(*) FROM raw_frames
WHERE protocol = 'GB32960' AND message_id = 2 AND vin <> '' AND vin NOT LIKE 'LTEST%';
也可以直接运行仓库 smoke 工具验证 TCP 32960、GB32960 snapshot/fields、TDengine raw_frames。如果需要复核冷备 .bin,再传入接入服务 archive 根目录:
export TDENGINE_REST_URL='http://<tdengine-host>:6041/rest/sql/vehicle_ts'
export TDENGINE_USERNAME='root'
export TDENGINE_PASSWORD='<tdengine-password>'
python3 tools/gb32960_e2e_smoke.py \
--archive-root "$PROJECT_ROOT/data/archive-jt808" \
--tdengine-rest-url "$TDENGINE_REST_URL" \
--tdengine-username "$TDENGINE_USERNAME" \
--tdengine-password "$TDENGINE_PASSWORD"
预期输出包含 records >= 1、fieldCounts 中关键字段均大于 0、tdengineRawFrames 等于本次可见唯一 rawUri 数量。传入 --archive-root 时,archiveChecked >= 1 说明冷备文件也能复核;这里的 records 字段表示 snapshot 数量,用于兼容早期脚本输出名。
复查 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-appraw 和 event 使用不同 consumer binding;raw consumer 必须开启,否则raw_frames不会持续增长。- JT808 设备没有 VIN 映射时,
vehicle_key使用jt808:<phone>;启用 MySQL identity store 后,registration 表中已反写 VIN 的 phone/deviceId/plate 会用于后续 raw/event 的 VIN 解析。 - GB32960 正式对端目前只验证到平台登录;等待真实车辆
0x02到达后,再用非测试 VIN 复查vehicle_locations、snapshot/fields API 和导出能力。