Appearance
数据同步的难点
本文档记录蓝牙门锁数据同步方案的设计背景,解释为什么不采用"双向自动同步"的方案。
为什么不做双向自动同步?
理想中的方案:
- 云端和设备都可以自由管理用户、凭证
- APP 连接时自动双向同步,合并数据
- 用户无感知,数据始终一致
这是一个经典的分布式系统难题,类似 MySQL 双主同步。
难点一:增量对比
要实现增量同步,需要知道"哪些数据变了"。
方案对比
| 方案 | 实现方式 | 问题 |
|---|---|---|
| 时间戳 | 每条记录带 updated_at | 设备时钟可能不准;删除操作无法追踪 |
| 版本号 | 每条记录带版本号 | 只知道"有变更",不知道"改了什么" |
| 变更日志 | 记录每个增删改操作 | 存储开销大,设备资源有限 |
| 全量对比 | 拉取全量数据后对比 | 无法区分"新增"和"删除" |
删除操作的困境
假设云端有凭证 A、B、C,设备删除了 B:
云端: A, B, C
设备: A, CAPP 连接时对比发现"设备少了 B",但无法区分:
- 场景1:设备删除了 B → 应该告诉云端删除 B
- 场景2:云端新增了 B → 应该把 B 下发到设备
除非记录操作日志(binlog),否则无法区分这两种情况。
难点二:冲突解决
即使能检测出变更,双端同时修改时仍有冲突。
冲突场景
| 场景 | 云端操作 | 设备操作 | 如何处理? |
|---|---|---|---|
| 1 | 删除用户 A | 修改用户 A 的名称 | 删除 or 保留? |
| 2 | 修改密码为 1234 | 修改密码为 5678 | 用哪个? |
| 3 | 删除指纹 X | 给指纹 X 改名 | ? |
常见解决策略
| 策略 | 说明 | 问题 |
|---|---|---|
| 时间戳优先 | 最后修改的为准 | 设备时钟不可靠 |
| 云端优先 | 冲突时云端覆盖设备 | 设备操作可能丢失 |
| 设备优先 | 冲突时设备覆盖云端 | 云端操作可能丢失 |
| 手动解决 | 提示用户选择 | 用户体验差 |
手动解决:
- 用户无法理解此类操作。
- 所有冲突类型都需要枚举出来以合适的方式供用户选择处理方案,实现成本高昂。
难点三:实现成本
要实现可靠的双向同步,需要:
| 组件 | 说明 | 成本 |
|---|---|---|
| 操作日志 | 设备记录每个增删改操作 | 存储空间、Flash 寿命 |
| 版本向量 | 追踪每端的修改历史 | 复杂的数据结构 |
| 冲突检测 | 发现并处理冲突 | 复杂的业务逻辑 |
| 回滚机制 | 同步失败时恢复 | 更多存储空间 |
这相当于在资源受限的嵌入式设备上实现一个分布式数据库同步系统。
对于门锁这种嵌入式设备,成本过高。
我们的方案
接受现实,简化设计:
| 方向 | 策略 | 说明 |
|---|---|---|
| 云端 → 设备 | 云端优先,自动下发 | 版本号对比,有变更则全量覆盖该类型数据 |
| 设备 → 云端 | 手动触发,设备覆盖 | 用户主动点击"同步数据" |
| 事件记录 | 设备产生,增量上报 | 只增不改不删,用 ID 增量拉取 |
为什么这样设计
- 避免冲突:明确数据所有权,不存在"双方同时修改"的场景
- 简化实现:设备不需要记录操作日志,只维护版本号
- 用户可控:设备本地操作不会被意外覆盖,需要用户主动同步
- 资源友好:设备端实现简单,不消耗额外存储
用户需要理解
- 云端管理的操作会自动生效
- 设备本地操作需要手动同步到云端
- 手动同步时,设备数据会覆盖云端
类比
这个方案类似于:
- Git 的 force push:手动同步 = 设备 force push 到云端
- MySQL 主从复制:云端是主库,设备是从库(但从库偶尔可写)
- 备份恢复:手动同步 = 从设备恢复备份到云端
总结
"双向自动同步"看起来很美好,但在蓝牙门锁场景下:
- 技术上:增量对比、冲突解决都是难题
- 成本上:设备资源有限,无法承担复杂同步机制
- 必要性上:门锁管理操作频率低,手动同步可接受
简单可靠优于复杂完美。
继续阅读
了解我们最终采用的同步方案,请阅读 数据同步。
