feat: build vehicle data platform and production pipeline
This commit is contained in:
224
docs/vehicle-data-platform-data-model.md
Normal file
224
docs/vehicle-data-platform-data-model.md
Normal file
@@ -0,0 +1,224 @@
|
||||
# 车辆数据中台一期数据模型
|
||||
|
||||
## 1. 数据职责原则
|
||||
|
||||
| 存储 | 负责 | 不负责 |
|
||||
| --- | --- | --- |
|
||||
| Redis DB 50 | 最新状态、在线 TTL、字段级当前值、热查询缓存 | 历史事实、告警事件、规则、导出任务 |
|
||||
| TDengine `lingniu_vehicle_ts` | 高频 RAW 证据、位置/稳定时序历史 | 车辆档案、权限、工作流状态 |
|
||||
| MySQL `lingniu_vehicle_data` | 车辆主数据、身份映射、接入配置、当前业务投影、统计、规则、事件、通知、导出任务 | 每帧完整历史和无限增长的遥测明细 |
|
||||
|
||||
统一业务主键为 VIN。车牌、JT808 手机号、设备号、平台标识只是可变标识,通过映射解析到 VIN;无法解析 VIN 的数据仍留 RAW/接入排障,不进入正式车辆统计。
|
||||
|
||||
## 2. 当前 TDengine 模型
|
||||
|
||||
### 2.1 `raw_frames` stable
|
||||
|
||||
列:`ts, frame_id, event_id, message_id, event_time, received_at, raw_size_bytes, raw_hex, raw_text, parsed_json, parse_status, parse_error, source_endpoint`。
|
||||
|
||||
Tags:`protocol, vehicle_key, vin, phone, device_id`。
|
||||
|
||||
用途:证明收到什么、何时收到、解析成什么。`parsed_json` 物理列保存 Gateway 已一次扁平化的 `parsed_fields`,是动态协议字段的历史证据。新字段默认先进入这里,不为每个厂家字段立即新增物理列。
|
||||
|
||||
### 2.2 `raw_frame_payload_chunks` stable
|
||||
|
||||
列:事件/帧、接收时间、payload 类型、分片序号/总数、分片文本;Tags 与 RAW 身份类似。
|
||||
|
||||
用途:保存超过主表列长度的 raw/parsed payload,不参与常规业务查询。
|
||||
|
||||
### 2.3 `vehicle_locations` stable
|
||||
|
||||
列:`ts, event_id, received_at, longitude, latitude, altitude_m, speed_kmh, direction_deg, alarm_flag, status_flag, total_mileage_km`。
|
||||
|
||||
Tags:`protocol, vin`。
|
||||
|
||||
用途:VIN 非空车辆的高频位置、速度、方向、告警/状态位、总里程历史。当前平台 DTO 尚未完整透出方向、告警和状态位,也没有 SOC 列;轨迹一期需先补 DTO/查询,SOC 可从 RAW 指标取值或按验证后的需求物化。
|
||||
|
||||
数据库当前配置 `KEEP 7300 DURATION 10 BUFFER 256`。保留期和磁盘容量应纳入运维监控,不在业务页面查询时临时改变。
|
||||
|
||||
## 3. 当前 Redis 模型
|
||||
|
||||
| Key | 值/用途 | 约束 |
|
||||
| --- | --- | --- |
|
||||
| `vehicle:latest:{vin}` | 跨协议最新核心字段 | 仅 VIN 非空;轻量快照 |
|
||||
| `vehicle:latest:{vin}:{protocol}` | 单协议最新核心字段 | 可过期/重建 |
|
||||
| `vehicle:realtime-raw:{protocol}:{vin}` | 单协议最新完整 parsed 状态 | Redis 中完整协议字段唯一副本 |
|
||||
| `vehicle:rt-kv:{protocol}:{vin}:values` | 扁平字段当前值 | 与类型/时间/meta 配套 |
|
||||
| `...:types` | 字段值类型 | 支持动态展示和规则类型校验的实时侧依据 |
|
||||
| `...:times` | 每字段最新归一事件时间 | 防止乱序旧帧覆盖 |
|
||||
| `...:meta` | 最新事件/接收时间、映射版本 | 用于新鲜度和追踪 |
|
||||
| `vehicle:online:{protocol}:{vin}` | TTL 在线状态 | 在线事实的快速判断,不应永久保存 |
|
||||
| `vehicle:online-state:{protocol}:{vin}` | 可分页的 Hash 副本 | 用于在线列表 |
|
||||
| `vehicle:protocols:{vin}` | 最近出现协议集合 | 车辆来源发现 |
|
||||
| `vehicle:last_seen` | 最近活跃车辆 ZSET | 分页/排序候选 |
|
||||
|
||||
生产只允许 `nats-fast-writer` 写 Redis 当前态;Kafka 慢链路的 realtime writer 不应覆盖快路径。在线产品状态应由“最新时间 + 配置阈值”计算并返回阈值/依据,不能只信一个固定 Boolean。
|
||||
|
||||
## 4. 当前 MySQL 模型
|
||||
|
||||
### 4.1 身份与档案
|
||||
|
||||
| 表 | 主键/关键字段 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `vehicle` | `vin`;`plate, oem, enabled, updated_at` | 轻量车辆主实体;当前字段不足一期完整档案 |
|
||||
| `vehicle_identifier` | `(protocol, source_code, identifier_type, identifier_value)`;VIN/车牌/OEM | 多协议、多来源、多标识解析到 VIN |
|
||||
| `vehicle_identity_binding` | VIN;车牌、phone、OEM | 外部维护的兼容映射事实,运行期只读 |
|
||||
| `jt808_registration` | `phone`;device、plate、VIN、厂家、鉴权、来源、首次/最近注册鉴权/出现时间 | JT808 注册鉴权与绑定证据 |
|
||||
|
||||
### 4.2 当前态与来源
|
||||
|
||||
| 表 | 主键/关键字段 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `vehicle_realtime_snapshot` | `(protocol, vin)`;plate、platform、peer、扁平 `parsed_json`、event/received time | 每协议每 VIN 最新合并遥测快照 |
|
||||
| `vehicle_realtime_location` | `(protocol, vin)`;经纬度、速度、总里程、SOC、海拔、方向、alarm/status、event/received time | 每协议每 VIN 最新位置业务缓存 |
|
||||
| `vehicle_data_source` | 自增 ID,唯一 `(protocol, source_ip)`;source code/kind、platform、priority、enabled、first/latest seen | 数据来源配置和可信源选择 |
|
||||
|
||||
### 4.3 日里程
|
||||
|
||||
| 表 | 主键/关键字段 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `vehicle_daily_mileage_source` | `(vin, stat_date, protocol, source_key)`;首末里程、样本、质量、是否选中 | 多来源日里程事实和质量解释 |
|
||||
| `vehicle_daily_mileage` | `(vin, stat_date, protocol)`;source ID、日里程、最新总里程 | 对外查询结果投影 |
|
||||
|
||||
当前明确不存在/不应恢复的旧模型包括泛化 `vehicle_daily_metric`、TDengine `vehicle_mileage_points` 和 `raw_frames.fields_json` 重复列。
|
||||
|
||||
## 5. 一期统一领域模型
|
||||
|
||||
### 5.1 车辆标识
|
||||
|
||||
```text
|
||||
VehicleId = VIN(内部规范化大写、去空格)
|
||||
VehicleIdentifier = protocol + sourceCode + type + value -> VIN
|
||||
Plate = 可变展示标识,不作为跨表唯一主键
|
||||
Source = protocol + sourceCode/sourceId + endpoint
|
||||
```
|
||||
|
||||
所有 API 都以 VIN 作为详情路径主键;搜索接口可接受车牌、VIN、车辆编号/手机号并返回解析结果。多协议数据保留 `protocol` 和 `sourceId` 做归因,不能在合并时丢失来源。
|
||||
|
||||
### 5.2 时间模型
|
||||
|
||||
- `eventTime`:车端/协议事件时间,是轨迹、曲线和告警判断的主要时间。
|
||||
- `receivedAt`:平台接收时间,用于延迟、迟到数据和链路健康。
|
||||
- `storedAt/updatedAt`:投影或业务记录更新时间,不冒充车辆上报时间。
|
||||
- `dataDelaySec = receivedAt - eventTime`;`silenceSec = now - max(receivedAt/eventTime 的已确认口径)`。
|
||||
|
||||
### 5.3 在线状态
|
||||
|
||||
```text
|
||||
never_reported: 无任何 latestReceivedAt
|
||||
online: silenceSec <= thresholdSec
|
||||
offline: silenceSec > thresholdSec
|
||||
unknown: 时间非法、未来时间过大或来源状态无法判断
|
||||
```
|
||||
|
||||
行驶/静止是独立 motion 状态,建议以速度阈值 + 最近更新时间判断;告警也是独立状态。不要把 `online/running/alarm` 压成一个互斥枚举,UI 可基于多维状态决定主色和徽标。
|
||||
|
||||
### 5.4 指标值
|
||||
|
||||
```text
|
||||
MetricValue {
|
||||
vehicleId, metricKey, value, valueType, unit,
|
||||
eventTime, receivedAt, protocol, sourceId,
|
||||
quality, mappingVersion
|
||||
}
|
||||
```
|
||||
|
||||
`metricKey` 是协议无关的规范键;协议原字段通过映射表关联。厂家扩展字段允许命名空间,但必须有显示名、类型、分类和单位后才可进入图表/告警。
|
||||
|
||||
## 6. 建议新增 MySQL 模型
|
||||
|
||||
### 6.1 档案与组织
|
||||
|
||||
建议优先用关联表而非不断扩宽 `vehicle`:
|
||||
|
||||
- `vehicle_profile(vin PK, vehicle_no, model_id, vehicle_type, company_id, operation_status, access_vendor_id, first_access_at, ...)`
|
||||
- `vehicle_model(id, oem_id, code, name, vehicle_type, ...)`
|
||||
- `organization(id, parent_id, type, code, name, enabled, ...)`
|
||||
- `access_vendor(id, code, name, enabled, ...)`
|
||||
|
||||
外部主数据通过受控同步写入 `source_system/source_version/synced_at`。默认策略保护 `manual` 和其他外部来源;只有管理员显式选择 takeover 才能改变所有权。同一来源版本相同载荷幂等,不同载荷冲突,避免上游版本不可变性被破坏;每次创建/更新都进入 `vehicle_profile_audit`。
|
||||
|
||||
### 6.2 指标目录
|
||||
|
||||
- `metric_definition(metric_key PK, display_name, category, value_type, unit, precision, chartable, alertable, enabled, sort_order, version)`
|
||||
- `metric_protocol_mapping(metric_key, protocol, source_field, transform, mapping_version, enabled)`
|
||||
|
||||
`transform` 不能存任意可执行代码;使用有限转换类型或由版本化 Go 映射实现。目录服务可缓存,变更有版本和审计。
|
||||
|
||||
### 6.3 告警域
|
||||
|
||||
- `alert_rule(id, name, description, metric_key, operator, threshold_json, severity, duration_sec, recovery_json, repeat_interval_sec, enabled, version, created_by, updated_by, timestamps)`
|
||||
- `alert_rule_scope(rule_id, scope_type, scope_value)`:vehicle/model/oem/protocol/company;一期可限制组合复杂度。
|
||||
- `alert_event(id, rule_id, rule_version, vin, protocol, source_id, status, trigger_value_json, threshold_json, first_triggered_at, last_triggered_at, recovered_at, closed_at, location_json, dedupe_key, assignee, timestamps)`
|
||||
- `alert_event_action(id, event_id, action, from_status, to_status, operator_id, note, created_at)`
|
||||
- `notification(id, user_id, event_id, title, body, read_at, created_at)`
|
||||
|
||||
`alert_event.dedupe_key` 建唯一约束或等价幂等机制;阈值快照和 rule version 必须保存在事件上,避免规则修改后历史无法解释。
|
||||
|
||||
当前实现使用带业务前缀的实体表,完整 DDL 位于 `vehicle-data-platform/deploy/migrations/002_alert_center.sql`:
|
||||
|
||||
- `vehicle_alert_rule` + `vehicle_alert_rule_audit`:当前规则与每版本不可变快照。
|
||||
- `vehicle_alert_candidate`:`(rule_id, vin, protocol)` 持续命中计时,避免单帧达到阈值就误开事件。
|
||||
- `vehicle_alert_stream_checkpoint`:`(consumer_group, topic, partition_id)` 保存数据库权威 `next_offset`、Kafka high watermark、处理/非法/迟到/回放计数、最近事件证据以及最近非法代码/时间。流 worker 先提交该事务,再提交 Kafka group offset;崩溃后重复抓取的 offset 会被数据库 checkpoint 跳过。累计非法数用于审计,健康状态只对五分钟内仍在发生的非法消息告警。
|
||||
- `vehicle_alert_event`:保存规则名/版本、触发阈值快照、证据时间、位置和乐观锁版本;`fingerprint + active status` 用于评估器幂等检查。
|
||||
- `vehicle_alert_event_action`:触发、恢复和人工处置的不可变时间线。
|
||||
- `vehicle_alert_notification`:站内通知真实已读状态;外部通道只有 `reserved`,没有配置供应商时绝不标记 `sent`。
|
||||
- `vehicle_alert_rule_state`:为 Boolean `changed` 规则保存每个 rule/VIN/protocol 的最近观测值;`003` 同时增加区间上限和 OEM 范围,`004` 为 fingerprint 重复间隔查询增加索引。
|
||||
|
||||
一期 evaluator 读取 `vehicle_realtime_location` 的当前快照并用 candidate 表证明持续时长。除 `freshness_sec` 明确按平台墙钟增长外,候选只允许由不同 `source_event_id` 且事件时间不回退的新观测推进;重复快照不能制造持续时长,迟到观测不能回退 candidate 或 Boolean 状态。规则行会在评估事务内加锁,停用规则、清理 candidate/Boolean 状态和写版本审计在同一事务提交,从而避免 evaluator 与管理员停用并发后留下幽灵候选。它仍不是 Kafka event-time 可重放评估器,因此跨当前快照的迟到数据重算、历史窗口规则和消费 offset 仍是阶段 8 的后续能力。
|
||||
|
||||
`alert-stream-evaluator` 已以 active 模式消费三类 canonical fields topic。它复用 Kafka consumer group 的分区顺序,校验 `event_kind/field_mapping/protocol/VIN/source_event_id/字段命名空间`,用接收时间识别超过可配置窗口的迟到观测。动态规则锁、当前批次范围内的 candidate/Boolean/活跃事件/重复窗口、事件/动作/通知副作用和 checkpoint 在同一个 MySQL 事务内完成,成功后才 commit Kafka;数据库 ahead 时的重复 offset 由 checkpoint 跳过。超过迟到窗口的观测只允许驱动 `data_delay_sec`,不能开关速度/SOC/告警位事件。快照 evaluator 在 active 模式只负责按墙钟增长的 `freshness_sec`,不再读取动态规则。
|
||||
|
||||
### 6.4 导出域
|
||||
|
||||
- `export_job(id, user_id, type, format, query_json, status, progress, estimated_rows, exported_rows, file_uri, file_size, checksum, error_code, error_message, started_at, completed_at, expires_at, created_at)`
|
||||
|
||||
索引至少覆盖 `(user_id, created_at)`、`(status, created_at)` 和过期清理。`query_json` 保存规范化查询快照,不保存数据库密码或签名下载 URL。
|
||||
|
||||
### 6.5 在线阈值与审计
|
||||
|
||||
- `online_threshold(scope_type, scope_value, threshold_sec, version, updated_by, updated_at)`,一期建议 scope 仅 global/protocol。
|
||||
- `audit_log(id, actor, action, resource_type, resource_id, before_json, after_json, trace_id, created_at)`。
|
||||
|
||||
当前 V2 接入管理已先落地等价的窄表:
|
||||
|
||||
- `vehicle_access_threshold_config(id=1, version, default_threshold_sec, delay_threshold_sec, long_offline_sec, protocol_overrides_json, updated_by, updated_at)`。
|
||||
- `vehicle_access_threshold_audit(id, version, actor, summary, config_json, changed_at)`。
|
||||
|
||||
表仅向前新增,不改变 gateway 的 `vehicle_realtime_snapshot(protocol, vin)` 主键与写入语义。后续统一审计域上线时可迁移到通用 `audit_log`,但必须保留版本历史。
|
||||
|
||||
## 7. 查询与物化策略
|
||||
|
||||
1. 实时页面优先 Redis,MySQL realtime 作为业务查询/降级投影;返回值统一由 BFF 归一化。
|
||||
2. 轨迹只查 TDengine `vehicle_locations`,必要的 SOC/告警补充应避免对每个点逐条回查 RAW;先验证是否需要将 SOC 提升为位置列或建立专用指标 stable。
|
||||
3. 通用历史指标首版可从 `raw_frames.parsed_json` 按白名单提取,但必须限制车辆数、指标数、时间范围并做基准;高频稳定指标按实际查询热度物化为专用时序模型。
|
||||
4. 档案和字典在 BFF/Redis 做版本化短缓存,避免每次实时请求重复查不变数据。
|
||||
5. 地图聚合可从 MySQL realtime/Redis 快照构建短周期服务端缓存;不要把地理历史查询压到实时表,也不要把全量点放浏览器聚合。
|
||||
6. 告警 worker 使用 Kafka 可重放流和 eventTime,MySQL 保存工作流事实;Redis 可保存短期去重/规则缓存但不是唯一事实。
|
||||
|
||||
## 8. 数据质量与治理要求
|
||||
|
||||
- 数值同时记录单位和精度;未知单位不得参与跨协议比较或规则判断。
|
||||
- 原始值、规范值和转换版本可追踪;异常值标记不直接篡改 RAW。
|
||||
- 未来时间、经纬度越界、速度突变、里程回退、重复事件均定义质量码。
|
||||
- 轨迹过滤返回算法版本、原始/过滤/抽稀数量,可选择查看未过滤证据。
|
||||
- 协议新增字段先进入扁平 RAW + Redis KV,经目录登记后才进入 UI;形成稳定高频查询后再物化。
|
||||
- 所有新增表、字段、索引、保留期和清理任务随 migration 与数据字典发布。
|
||||
|
||||
## 9. 容量和保留
|
||||
|
||||
- 约 1,000 到 10,000 车辆、5~30 秒上报意味着时序写入持续增长;TDengine 查询必须带 VIN/时间,禁止开放无界扫描。
|
||||
- RAW 保留期、位置保留期、导出文件保留期和告警/审计保留期分别配置,不能共用一个默认值。
|
||||
- MySQL 告警事件和审计按时间索引并规划归档;导出任务定时过期,文件删除和 DB 状态更新需幂等。
|
||||
- 单 ECS 上告警和导出 worker 设置独立并发、内存、CPU 和 systemd 限制,避免影响接入写链路。
|
||||
|
||||
## 10. 仍需确认的数据问题
|
||||
|
||||
1. `vehicle_identity_binding` 的实际 DDL、权威维护方和未来是否继续兼容。
|
||||
2. 车型、车辆类型、运营公司、车辆编号、运营状态、接入厂家的权威来源与更新频率。
|
||||
3. 各协议 SOC、方向、启动、告警等级、电机/燃料电池等规范字段映射和单位。
|
||||
4. “累计运行时长”是已有车端字段、由状态积分计算,还是一期可不提供。
|
||||
5. 在线时间基准使用 eventTime 还是 receivedAt,以及不同协议的默认阈值。
|
||||
6. 轨迹停车阈值、漂移判定、迟到点容忍和跨协议主轨迹选择规则。
|
||||
7. 导出存储与保留期、单用户并发/最大行数。
|
||||
8. 告警规则适用范围组合、迟到窗口、重复/恢复语义和事件归属人规则。
|
||||
Reference in New Issue
Block a user