端云同步不是简单调接口:用版本号、幂等键和冲突合并把数据做可靠

举报
yd_210306688 发表于 2026/11/06 09:12:28 2026/11/06
【摘要】 端云应用上线后,接口超时、网络重试、离线编辑和多端并发都会放大数据一致性问题。本文给出一套最小可落地协议:本地先写、Outbox 可重试、服务端幂等、版本检查与可解释的冲突合并。

很多端云应用在演示阶段只需要把本地数据 POST 到服务端,看起来就完成了同步。真正上线后,网络重试、离线编辑、多端同时修改和接口超时都会出现。若没有明确的数据协议,“最后一次请求覆盖数据库”很快就会造成重复记录或用户内容丢失。

本文以笔记类应用为例,讨论一套可以直接落地的最小同步设计:本地先写、失败可重试、服务端幂等、版本可检查、冲突可解释。

一、先定义三条不变量

  1. 本地成功优先。用户点击保存后,内容必须先进入本地持久化存储。即使此刻断网,页面刷新或应用重启也不能丢。
  2. 请求可以重复。同一次保存被重发两次、三次,服务端最终也只能落一条业务记录。
  3. 版本必须显式。客户端不能只相信时间戳,因为设备时钟可能漂移;服务端应维护单调递增的记录版本。

这三条看似简单,却决定了系统在网络抖动时是否可恢复。

二、Outbox:把“写本地”和“传服务端”拆开

推荐把业务写入和同步任务放进同一个本地事务:先更新笔记表,再写一条 outbox 记录。后台同步器只读取 outbox,成功后标记完成。这样 UI 不必等待网络,失败也能在同一队列中重试。

type OutboxItem = {
  opId: string;          // 由客户端生成,全局唯一
  entityId: string;
  baseVersion: number;
  payload: NotePayload;
  status: "pending" | "sending" | "done";
  retryCount: number;
};

opId 不是数据库主键的替代品,而是“这次操作”的幂等键。每次用户保存生成新值;网络重试必须复用原值,不能重新生成。

三、服务端幂等:先约束,再处理业务

服务端应在事务内先插入幂等记录。如果唯一索引冲突,说明请求已处理过,直接返回此前结果,不要再次修改业务表。

BEGIN;
INSERT INTO sync_op(op_id, user_id, result_version)
VALUES (:opId, :userId, :nextVersion); -- op_id 唯一

UPDATE note
SET content = :content,
    version = version + 1,
    updated_at = NOW()
WHERE id = :entityId
  AND user_id = :userId
  AND version = :baseVersion;
COMMIT;

同时检查受影响行数。若更新为零,通常是版本已变化,应返回 409 Conflict,并附带服务端当前版本和摘要。客户端据此决定拉取最新数据、保留冲突副本,或提示用户选择。

四、冲突处理要可解释

对短文本,最简单的策略不是静默覆盖,而是保留两份:服务端版本作为主记录,客户端版本另存为“冲突副本”。对结构化数据,可以按字段做三方合并,但界面必须明确标出自动合并和需要人工确认的部分。

版本号比 updatedAt 更可靠,因为时间戳既可能受设备时钟影响,也可能在同一毫秒内产生并列值。服务端版本由数据库原子递增,能稳定表达“我是基于哪一版修改的”。

五、客户端同步循环要有退避与上限

for (let attempt = 0; attempt < 5; attempt++) {
  const item = await nextPendingOutbox();
  try {
    const res = await push(item);   // 每次重试都复用 item.opId
    await markDone(item.opId, res.version);
  } catch (error) {
    await markRetry(item.opId, attempt);
    await sleep(2 ** attempt * 500 + Math.random() * 250);
  }
}

重试不能无限循环,也不能固定间隔打满服务端。建议使用指数退避、随机抖动和最大次数;持续失败的记录进入可见的待处理状态,避免用户误以为已经同步。

六、上线前至少验证这些异常场景

  • 服务端已提交但响应丢失,客户端重试后不能产生重复记录。
  • 两台设备基于同一版本编辑,后提交的一方收到冲突信息而不是静默覆盖。
  • 同一 opId 并发到达时,服务端只执行一次业务修改。
  • 长时间离线后恢复网络,待同步队列能按顺序完成并保留失败项。
  • 设备时间被调快或调慢,版本判断仍然正确。

七、结语

端云同步的核心不是某个 POST 接口,而是一份双方都遵守的数据协议:本地先落盘保证用户体验,幂等键保证重试安全,版本号保证并发可检测,冲突副本保证信息不被静默吞掉。把这四件事做好,再复杂的同步场景也会从“偶发丢数据”变成可以定位、可以恢复的工程问题。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。