首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >两地双活:同时写入的数据冲突怎么处理

两地双活:同时写入的数据冲突怎么处理

原创
作者头像
用户12624040
发布于 2026-10-17 15:34:34
发布于 2026-10-17 15:34:34
170
举报

公司业务连续性要求升级,我们从主备架构演进到了两地双活——两个机房同时对外服务,同时接收写入。双活架构的拦路虎只有一个:同一条数据在两地同时被修改,冲突怎么办。这篇把我们落地双活的冲突处理方案讲透。结论先说:两地双活的数据冲突,八成要靠架构设计避免——按业务维度把写权限分区,让同一条数据只有一个写入地;剩下两成避免不了的,靠版本检测加解决方案自动收敛,外加对账兜底。

一、为什么冲突是双活的头号难题

1.1 主备没有的问题,双活有了

主备架构里数据冲突不存在——写入只在主机房,备机房只读,数据单向流动。双活把单向变双向:两地同时写,同一条数据两地同时改,谁为准?举例最直观:会员表里张三的手机号,A 地运营改成一号,B 地客服几乎同时改成二号,两个改动各自同步给对方——没有冲突处理,结果取决于谁后到达:晚到的覆盖早到的,先改的丢失,而且没人知道丢过。静默丢数据,是分布式系统里坏的一类问题——数据丢了没人知道,等知道时已经没法补。

1.2 冲突的三种面目

实践里冲突长三种样:更新冲突——两地同时改同一条记录的不同字段或同字段;写写冲突——两地同时创建逻辑上同一条记录,比如同一个会员两地注册;删除冲突——一地删了,另一地正在改。三种冲突里更新冲突占九成,处理策略也最丰富;写写冲突靠唯一键约束化解;删除冲突最阴险,靠墓碑机制标记——删除打标记而非物理清除,同步时删除意图能被对方感知。

二、架构层:让冲突发生不出来

2.1 写权限分区:业务的纵切

避免冲突的主策略:按业务维度分区写权限。我们的切法是纵向按业务域:会员和订单相关写入固定走 A 地,库存和售后写入固定走 B 地,前端按请求的业务域路由到对应机房。这样同一条数据的写入永远只在一个机房发生,同步是单向流水,冲突在架构上就不存在了——这是分布式设计的头号心法:能靠架构绕开的问题,别留给算法。分区的前提是业务边界清晰——好在低代码平台上的应用按业务域天然分库,路由规则配置在网关层,按应用维度指路,改造量比想象小得多。

2.2 用户就近读,写入归区

分区带来的体验问题:B 地用户写订单要跨区到 A 地,延迟变高。我们的平衡术:读操作两地都走,就近响应——用户九成的操作是看,体验不打折;写操作按分区路由,跨区写多出的几十毫秒,用户在提交场景里感知不强。这个读写分治的取舍,让分区策略的代价降到了业务无感——架构没有免费的午餐,但有便宜的午餐——把贵的要求按场景拆开,多数场景只付得起的那部分钱,体验就保住了。

2.3 分区改不了的特殊场景

有些写入分不了区:全公司共用的配置表、两地都有客户的边缘业务、跨业务域的聚合操作。这些是冲突处理真正的考题,靠下一节的版本检测接住。架构层的结论:能分区的坚决分区,分区消化八成写入,剩下两成才有资格谈冲突解决——不先做分区,任何冲突算法都会被冲突量淹死。

三、未分区数据的冲突处理

3.1 版本号检测

无法分区的表,全部带版本号字段:每次修改版本号加一,同步时携带本地的版本和原始版本。同步协议的判定逻辑:

代码语言:pseudo
复制
function resolveSync(remote, local):
  if remote.base_version == local.version:      # 对方基于我当前版本改的
     apply(remote); local.version++             # 直接应用
  elif remote.base_version < local.version:     # 对方基于旧版本,本地已前进
     CONFLICT -> strategy(remote, local)        # 冲突,进解决策略
  else:                                         # 对方版本更新,等下一轮
     defer

版本检测的本质:比较改动所基于的起点——双方基于同一起点先后改,后到者可直接应用(顺序冲突,天然消解);双方基于不同起点同时改,才是真冲突,进解决策略。检测把冲突从混沌变成了精确制导——知其冲突且知其如何冲突,解决才有章法。

3.2 解决策略:按字段自动收敛

真冲突的解决,我们的策略按字段类型自动收敛,人工介入压到极少。数值字段取更晚时间戳——最后写入胜出,简单粗暴但可解释;枚举字段取业务优先级——状态类字段定义优先级链,比如锁定状态优先于激活状态;文本字段保双方——冲突的文本字段进冲突暂存区,两版本都留,标记待人工确认。自动策略消化九成九的冲突,人工只处理真正值得人判断的文本分歧——每天个位数,运营顺手就处理了——好的自动化不是消灭人工,是把人工留给真正值得人的判断。

3.3 对账兜底:冲突处理的最后一道网

自动策略再精巧,也要承认可能出错——时间戳可能因时钟漂移失真,优先级链可能有配置疏漏。所以对账兜底:每晚全量对账任务比对两地数据,字段级差异输出清单;清单按类型分流——自动策略造成的合理差异登记备案,可疑差异(比如两地同一条记录的创建时间不一致)告警人工核查。对账上线头一个月抓出三处时钟漂移导致的误判——兜底网的价值,是让你敢相信自动策略。

四、切换演练:双活的真实成色

双活架构成色如何,演练说了算。我们每季度做一次真切换:把 A 地流量全部切到 B 地,业务跑一小时,再切回。演练验证三件事:路由切换是否分钟级生效——网关配置推送加健康检查摘除,实测三分钟;B 地独立承接全量写入后,数据同步链路反向是否正常——分区写入的地域变了,同步方向跟着切;回切后对账是否平——一小时双写窗口的数据,对账差异应为零。三次演练后,双活从架构图上的概念变成了团队手里的肌肉记忆——真出故障那晚,值班工程师十分钟完成切换,业务方第二天看报表才发现有过一次切换——对他们来说,无感的故障就不算故障,这就是双活买来的东西。

五、总结

两地双活的数据冲突处理全景:架构层写权限分区,按业务域纵切,让八成冲突无从发生;无法分区的数据带版本号检测,真冲突按字段策略自动收敛——数值取时间戳、枚举取优先级、文本双存人工定;对账兜底每晚一跑,可疑差异告警人工;季度切换演练把纸面双活练成真双活。双活的全部秘密就一句话:用架构消灭大部分冲突,用算法消化小部分冲突,用对账兜住算法的万一——层层设防,才敢说高可用。

常见问题

问:两地时钟不一致,时间戳策略会不会误判?

答:会,这正是要害。两个对策:时钟纪律——两地机房全部走网络时间协议对时,漂移超过阈值告警,把时钟当成基础设施监控起来;策略降级——时间戳策略只在时钟健康时生效,对账发现时钟漂移期间的数据,自动改走人工确认流程。我们踩过一次时钟漂移三秒的坑,从那以后时钟监控的告警级别提到很高——所有看似可靠的东西,都要有不可靠时的预案。

问:分区写入后,某地机房故障,写入怎么接管?

答:这正是双活的意义:故障地的业务域写入由另一地接管,同步方向反转。要点在准备:接管预案预置在网关配置里——一键把会员订单域的路由从A地切到B地,不用临时想;接管后B地对该业务域的写入带接管标记,回切时这个标记参与对账——区分正常同步数据和接管期数据,回切核对才有靶子。演练练的就是这个动作,练熟了,故障接管就是换个开关。

问:冲突暂存区的人工确认,业务方嫌麻烦怎么办?

答:两个方向减负:策略覆盖率提升——把高频冲突场景的模式沉淀进自动策略,我们的文本双存比例从初期每天几十条降到个位数,靠的就是持续把人工判过的案例规则化;确认体验优化——暂存区的确认界面做成移动端可用,两版本并排、一键采纳、支持批量处理,运营在地铁上顺手就清了。人工确认是最后一步,不该是重活——重说明策略该进化了。

问:低代码平台上的应用数据,适合直接做双活吗?

答:分数据类型看。配置类数据——表单定义、流程配置——天然适合,变更频率低,冲突罕见,双活基本白拿收益;业务流水数据——订单、日志——适合,追加型写入冲突面小;高频修改的共享数据——库存、 counters 类——要先做写入分区或收归单地写,否则冲突率会教你做人。我们的节奏:先让配置和流水双活,高频数据观察冲突率再逐步纳入——双活是渐进的艺术,不是一刀切的仪式。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、为什么冲突是双活的头号难题
    • 1.1 主备没有的问题,双活有了
    • 1.2 冲突的三种面目
  • 二、架构层:让冲突发生不出来
    • 2.1 写权限分区:业务的纵切
    • 2.2 用户就近读,写入归区
    • 2.3 分区改不了的特殊场景
  • 三、未分区数据的冲突处理
    • 3.1 版本号检测
    • 3.2 解决策略:按字段自动收敛
    • 3.3 对账兜底:冲突处理的最后一道网
  • 四、切换演练:双活的真实成色
  • 五、总结
  • 常见问题
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档