IoT 在线状态标准回答¶
90 秒版本¶
我们会把设备静态信息和实时在线状态分离。设备基础信息保存在关系数据库,在线状态由 MQTT 心跳或连接事件驱动,状态服务记录每台设备的 last_seen,并根据超时时间判断离线。
查询设备列表时不会一次读取全部设备,而是先从数据库分页获取本页设备,再使用 Redis 的 MGET 或 HMGET 批量获取本页状态,在应用层按设备 ID 合并。这样既减少 Redis 网络往返,也把应用内存限制在一页数据范围内。
在线总数不会每次扫描全部设备,可以维护在线设备 Set,通过 SADD、SREM 和 SCARD 实现去重统计,或者维护计数缓存。但只在 offline 到 online、online 到 offline 的真实状态迁移时更新,并通过定时任务校准。对于突然断电的设备,不能依赖主动离线消息,需要 TTL 或超时调度产生离线状态。
我实际项目规模不是百万级;如果继续扩展,会按租户或设备 ID 分片状态服务和 Redis,并重点压测批量重连、消息突发、状态延迟与统计漂移。
追问:为什么不用数据库直接查询?¶
在线状态变化频繁,若每次心跳更新关系数据库、每次页面再执行实时统计,会把高频写入和高频查询集中到数据库。Redis 用于实时查询视图,数据库保存设备资料和必要历史。
追问:MGET 为什么快?¶
主要是把多个 GET 的多次网络往返合并成一次请求和一次响应。Redis 内部仍需查找每个 key,所以应该只批量读取一页,而不是一次获取十万条大 value。
追问:应用层组装是否占内存?¶
会占,但通过分页控制对象数量。真正的风险是全量加载、字段过多、响应过大和高并发,而不是应用层合并这个动作本身。全量导出应转成异步任务并分批流式处理。
追问:为什么 Set 比 INCR 更安全?¶
Set 的成员自动去重,重复上线事件执行两次 SADD 仍只有一个设备;纯 INCR 会重复加一。但 Set 仍不能自动处理突然断电,需要超时检测执行 SREM,并且应保留可校准的状态依据。