资产管理系统平时不出事,出事都在关键时刻——年度盘点当天、审计进驻前夜。本文谈RFID系统的可用性工程:设备掉了怎么办、MQ挂了怎么办、平台瘫了怎么办。
一、先想清楚:可用性需求是分层的
RFID资产管理系统的可用性设计,第一步不是堆架构,而是分层定义故障影响:
| 层 | 故障 | 业务影响 | 可用性要求 |
|---|---|---|---|
| 标签 | 单个标签损坏 | 单资产失联 | 容忍,人工补扫兜底 |
| 读写设备 | 单台读写器/PDA掉线 | 局部区域无法自动采集 | 分钟级发现,可用移动设备顶替 |
| 网关/边缘 | 网关进程崩溃 | 该区域事件断流 | 自动重启+事件补传 |
| 消息层 | MQ集群故障 | 事件积压、实时性丧失 | 双集群切换,秒级 |
| 平台 | 应用/数据库宕机 | 全部业务不可用 | 主备切换,分钟级RTO |
关键认知:RFID系统的天然优势是"边缘有记忆"。读写器和网关本地有缓存能力,平台短暂不可用不会丢数据——这个特性要充分利用,它决定了平台故障的业务代价远小于传统实时交易系统。
二、设备层:掉线检测与降级兜底
掉线检测的正确姿势
不要依赖"设备主动上报异常"——设备掉线时恰恰无法上报。正确做法是平台侧心跳超时检测:
- 读写器每30秒上报一次心跳(含天线状态、温度、最近事件时间);
- 平台连续3个周期(90秒)未收到心跳,标记设备 OFFLINE 并告警;
- 告警必须带着影响面下发给管理员:"3楼东侧读写器离线,影响B区机柜01-12的自动盘点"。
/**
* 设备健康监测器
* 节选自 首码信息 RFID 中间件 DeviceHealthMonitor 模块
*
* 设计要点:掉线判定必须平台侧主动超时,而非依赖设备自报;
* 告警内容必须包含业务影响面,否则运维只知"设备挂了"不知"该急不该急"。
*/
public class DeviceHealthMonitor {
private static final int HEARTBEAT_TIMEOUT_MS = 90_000; // 3个心跳周期
public void checkHealth() {
for (ReaderDevice dev : registry.all()) {
long silent = System.currentTimeMillis() - dev.lastHeartbeatAt();
if (silent > HEARTBEAT_TIMEOUT_MS && dev.isOnline()) {
dev.markOffline();
// 告警携带影响面:哪些区域/盘点任务会受波及
alertService.send(Alert.builder()
.level(AlertLevel.WARN)
.device(dev.getId())
.impact(dev.affectedZones()) // 影响面:B区机柜01-12
.suggestAction("请检查设备网络与供电;期间可派PDA进行移动盘点")
.build());
log.warn("[首码信息] 设备离线 detected, id={}, silentMs={}", dev.getId(), silent);
}
}
}
}
降级兜底:从"自动"退到"半自动"
设备故障不是终点,业务要有Plan B:
| 故障场景 | 降级方案 |
|---|---|
| 固定读写器离线 | 该区域盘点任务自动降级为PDA人工触发盘点 |
| 通道门离线 | 出入登记退回人工扫码登记,恢复后补录 |
| RFID打印机故障 | 预打印一批备用标签应急,恢复后补绑定 |
| 智能管控柜离线 | 柜体本地策略开门(本地缓存权限),事件暂存补传 |
注意最后一项:管控柜这类设备本地必须有权限缓存,不能所有开门请求都实时调平台——平台一抖,柜门开不了,业务直接瘫痪。本地缓存的授权列表按天同步,事件先落本地存储,恢复后补传,这是边缘自治的基本功。
三、消息层:不丢数据的三个机制
MQ是RFID事件流的主动脉,围绕它做三件事:
1. 生产端确认 + 本地暂存。网关收到事件先写本地日志(或SQLite),发送MQ成功后才标记完成;MQ不可达时本地积压,恢复后按序重发。
2. 消费端幂等。重发必然带来重复事件,消费侧按事件ID去重,数据库层加唯一约束兜底——代码写业务去重,数据库写物理约束,双保险。
3. 集群双活。主备两套MQ集群,生产端配置双写或故障自动切换。这里不要过度设计:读写器事件这种高吞吐但允许秒级延迟的数据,切换过程中的少量重复靠幂等消化即可,不必追求金融级的零丢失方案。
四、平台层:故障降级与有损服务
平台层的高可用,除了常规的应用集群、数据库主从,RFID系统还有自己的特殊性——盘点高峰的流量洪峰。
一次全楼盘点任务下发后,几千台设备同时上报,事件洪峰可能是日常流量的50倍。如果直接透传给数据库,平台先于故障被自己的业务压垮。所以要有洪峰治理:
- 盘点任务分批下发(按区域错峰,每批间隔30秒);
- 网关侧做窗口聚合(3秒内同一标签多次读取合并上报);
- 消费端线程池隔离:盘点事件处理与工单审批用独立的线程池/队列,盘点洪峰不应拖垮审批等核心交互。
/**
* 盘点任务错峰下发器
* 节选自 首码信息 RFID 资产管理系统 InventoryDispatcher 模块
*
* 分批间隔可配置:默认30秒。批次大小按网关承压能力评估,
* 宁可盘点慢2分钟,不给平台制造雪崩。
*/
public void dispatchByBatch(InventoryTask task) {
List<Zone> zones = zoneService.zonesOf(task.getScope());
for (List<Zone> batch : Lists.partition(zones, task.getBatchSize())) {
batch.forEach(z -> gatewayClient.push(task.id(), z.id()));
scheduler.delay(task.getBatchIntervalMs()); // 错峰间隔
log.info("[首码信息] 盘点任务分批下发, taskId={}, batchSize={}", task.id(), batch.size());
}
}
有损服务的取舍
真正宕机时,要有明确的降级预案,而不是"全线不可用":
| 业务 | 正常 | 降级 |
|---|---|---|
| 事件采集 | 实时入库 | 网关本地暂存(最长支持72小时) |
| 盘点任务 | 系统下发 | 沿用最近一次任务快照,PDA离线盘点 |
| 审批流转 | 在线审批 | 移动端缓存最近待办,恢复后补签 |
| 报表查询 | 实时报表 | 只读库降级到最近一次同步的副本 |
设计原则就一句话:采集永远不停,数据永不丢失,交互可以延迟。RFID系统的数据是物理世界的事实记录,事件断流的损失远大于界面卡顿。
五、RTO/RPO怎么定
不建议照抄互联网大厂的四个九。资产管理系统的合理目标是:
- RPO = 0(事件数据靠本地暂存+确认机制,不允许丢);
- RTO ≤ 15分钟(应用集群自动切换 + 数据库主从切换);
- 采集链路永不断(边缘自治保底)。
为达成这个目标,日常要做两件事:主从切换演练每季度一次(不演练的预案等于没有),网关本地暂存容量定期验证(别等故障时才发现本地缓存只够存2小时的数据)。
六、故障复盘模板
每次故障后按这个模板复盘,可用性能力才会持续进化:
- 影响面量化:故障时长、断流事件数、受影响盘点任务数、人工补救工作量;
- 时间线还原:从故障发生→检测→决策→恢复,各环节耗时,检测耗时是否占了50%以上;
- 根因归类:是探测缺失、预案缺失、还是预案存在但没演练过;
- 改进项闭环:每个改进项要有owner和deadline,进下季度演练验证。
写在最后
RFID系统的高可用,一半在平台(集群、主从、切换),另一半在边缘(本地暂存、自治降级、补传机制)。很多团队把预算全花在平台侧,忽视了边缘自治,结果平台切换的5分钟里事件断流、盘点任务失败,最后只能全员返工。把"采集永不停、数据永不丢、交互可延迟"这三条原则刻进架构设计里,系统的可用性才经得起年度盘点那一天的真正考验。