场景二:车联网 / IoT 数据平台
如果说秒杀是"百米冲刺",IoT 就是"永不停歇的马拉松":百万台车每秒都在上报位置、车速、电池状态,写入洪流 7×24 小时不退潮,存储账单还蹭蹭上涨。
场景描述与业务特征
每辆智能汽车就像一个话痨:每 1~10 秒上报一次 GPS、车速、电机温度、电池 SOC……单车每天产生数万条数据。一家有 100 万台在网车辆的车企,平台每秒要接住几十万到几百万个数据点。类比:不是一群人挤一扇门(秒杀),而是一百万根水管同时对着你的水库放水,全年不关阀。
🌊 写多读少
数据 99% 的时间在"睡觉",只有查轨迹、出报表、诊断故障时才被读。为写优化是第一原则。
⏱️ 时序天性
每条数据都带时间戳、按时间追加、极少修改。天生适合时序数据库(按时间分区、列式压缩)。
📦 单条小、总量大
一条报文几百字节,但架不住量大:1TB/天起步,存储成本是核心 KPI。
🔌 弱网乱序
车过隧道、进地库就断网,恢复后补传旧数据——数据到达顺序和产生顺序经常不一致。
🔁 至少一次送达
设备端重试机制导致同一条数据可能被发两次,平台必须自己去重。
🚨 实时+离线双需求
既要实时告警(电池过热 3 秒内通知),又要离线分析(月度驾驶行为报告),一份数据两条处理链路。
整体运作流程
IoT 平台的标准姿势是"接入 → 缓冲 → 分流 → 分层存储":网关只管接得快,Kafka 当巨型蓄水池,后面实时、离线两条流水线各取所需,最后按数据温度分层存放。
核心瓶颈与数据一致性挑战
🕰️ 乱序:迟到的数据算不算数?
车辆 10:00 过隧道断网,10:05 恢复后补传 10:00~10:05 的数据。此时"10:00~10:05 平均车速"的统计窗口早关了。Flink 水位线(Watermark)就是给迟到数据留的宽限期:窗口多等 N 秒再关账。等太久实时性差,等太短数据不准——又是取舍。
👯 重复:至少一次的副作用
设备发出报文没收到 ACK 就重发,平台可能收到两条一模一样的数据。里程统计、电费计算会虚增。解法:以"设备ID+时间戳+序列号"做唯一键去重,或选支持 upsert 的时序库让重复写入天然幂等。
💾 写入放大:数据库被"逐条写"拖死
百万点/秒逐条 INSERT,任何数据库都会跪——每条都要走一遍网络、解析、索引、刷盘。攒批写入(每 5000 条或每 200ms 刷一次)能把开销摊薄百倍,代价是数据可见性延迟零点几秒。
💰 存储成本:不删数据会破产
1TB/天 × 365 天 × 3 副本 ≈ PB 级。全放 SSD 时序库,存储账单能吓哭 CFO。必须冷热分层 + 降采样(3 个月前的数据从秒级抽稀成分钟级)+ 列式压缩(时序数据压缩比可达 10:1 以上)。
优化手段、获益与代价
① MQTT 网关集群 + 薄接入 接入层
网关只做鉴权、解码、转发三件事,不写数据库不做业务,无状态水平扩容。
② Kafka 缓冲 + 按设备分区 核心
所有数据先进 Kafka,按 vin(车架号)哈希分区,保证同一辆车的数据在分区内有序。
③ 批量写入 + 时序数据库 存储
消费端攒批(如 5000 条/200ms)写入 TDengine / InfluxDB / Apache IoTDB,按时间+设备分区,列式压缩。
④ Flink 流处理:水位线 + 状态去重 一致性
用事件时间 + Watermark 容忍乱序,用 keyed state 记录已见序列号去重,checkpoint 保证 exactly-once。
⑤ 冷热分层 + 降采样 成本
热数据(7天)SSD 时序库,温数据(6个月)降采样后存 HDD,冷数据转对象存储(S3/OSS)只为合规留存。
多种解决方案对比与选型建议
| 存储方案 | 写入吞吐 | 压缩/成本 | 查询能力 | 适用规模 |
|---|---|---|---|---|
| MySQL 分表 按月分表硬扛 | 低 · 万级/秒 | 差 | SQL 灵活 | 万台设备以内的试水期 |
| MongoDB 文档模型+TTL索引 | 中 · 十万级/秒 | 中 | 较灵活 | 报文结构多变的中小平台 |
| 时序数据库 TDengine/InfluxDB/IoTDB | 高 · 百万级/秒 | 优 · 10:1+ | 时间维度极强 | 十万~百万设备的主流选择 |
| HBase/Cassandra 宽表 LSM 存储 | 高 · 百万级/秒 | 中 | 只适合按键查 | 超大规模+自有大数据团队 |
| 数据湖方案 Kafka→Iceberg/Hudi+OLAP | 高(批流一体) | 优 · 对象存储价 | 分析能力最强 | 分析需求重于点查的平台 |
推演检验:换个条件还成立吗?
背下架构图不算学会,能判断"条件变了方案还成不成立"才算。先自己推,再展开参考。
推演 1:如果百万台车从"秒级定时上报"改成"仅报警时上报"(事件驱动),Kafka + 时序库这套还需要吗?
💡 参考推演
日常写入量骤降几个数量级,时序库可以退化成普通库分表。但注意事件驱动的风险是相关性脉冲:台风天全城车辆同时报警、OTA 升级后全量回传日志——瞬时峰值可能比定时上报更猛。所以 Kafka 这层缓冲反而更不能省:定时上报的流量可预测,事件驱动的流量不可预测,越不可预测越需要队列兑底。
推演 2:如果新业务要求"查车辆当前位置"毫秒级响应(网约车派单),攢批写入还成立吗?
💡 参考推演
成立,但要读写路径分离:攢批只影响"历史轨迹落库"的延迟,而"当前位置"应该在消费链路上顺手更新一份 Redis 里的 last-known 状态(每车一个 key,覆盖写)。查实时位置读 Redis,查历史轨迹读时序库——同一份数据两条链路,各自优化各自的延迟,而不是逼落库链路提速。
推演 3:如果存储预算砍半,三年账单撑不住,优先动哪一层?
💡 参考推演
先谈数据生命周期而不是换数据库:热数据(近30天)保留秒级精度;温数据降采样成分钟级聚合(体积缩几十倍);冷数据归档对象存储甚至删原始报文只留聚合结果。大部分 IoT 分析只用聚合值,原始报文的"全量永久保存"往往是惯性而非需求——先把需求问清楚,再动架构。