导航菜单
路很长,又很短
博主信息
昵   称:Cocodroid ->关于我
Q     Q:2531075716
博文数:356
阅读量:1744862
访问量:218070
至今:
×
云标签 标签球>>
云标签 - Su的技术博客
Tags : 同步,架构发表时间: 2021-12-09 23:37:56

背景

这里所说的云同步,指魅族的业务背景下,在移动应用场景中,经同步服务把数据保持多端一致的服务。它提供了如联系人、便笺、信息、通话记录、日历、文件等类型的数据同步功能,由移动设备上的客户端和服务端组成。

魅族云同步于 2008 年开始使用,目前服务千万级用户。以下就同步协议,架构部署和数据处理等方面进行一些分享。

业务定义、同步协议

根据场景,把同步业务划分为如下 3 类型 4 协议:

MZ-SyncML 协议

MZ-SyncML,基于微软的 SyncMl 协议(俗称 4 步同步),进行重新设计和开发实现的魅族同步协议。它交互精简、业务聚焦,解决了典型的结构化数据同步需求,如联系人、日历、便笺、通话记录、信息等业务。

它采用 JSON 进行数据交换,由接口层、同步点管理、数据解析、中间缓存数据管理、同步引擎、同步策略、冲突解决机制和 Mapping 关系管理等逻辑组成。

在同步策略上,实现了双向同步 200(Two-way、快同步)、慢同步 201(Slow sync)、客户端刷新同步 203(Refresh from client)、服务端刷新同步 205(Refresh from server)。

在同步点管理上,设计了客户端同步点(ClientAnchor),用于校验验证采用何种同步类型,管理选取客户端增量数据;还有服务端同步点 (ServerAnchor),用于管理选取服务端增量数据。

一个完整的同步有 4 个阶段,分别为 Request、Submitdata、Getdata、Result,简单示意图如下。

其中,sessionId 为服务端的会话标识,isFinal 为分批数据结束标识,clientData 为客户端业务数据,serverData 为服务端业务数据,resultList 为处理 data 结果数据(标识成功或失败)。

Semi-Sync 协议

半同步协议,在快同步和慢同步中,同步失败时,实现不重复上传和拉取已同步成功的数据。请注意,它有别于 MySQL 同步复制的半同步方案 (Semi-Synchronous)。

云同步是批量传输数据的,如果某批次出错,或单批次有若干数据出错,导致同步失败。下次同步时会有两个问题,一是客户端重复提交上次的所有数据(包括已成功的数据),二是拉取上次同步成功的数据。

MZ-SyncML 设计了 ClientAnchor 和 ServerAnchor 两个同步点,在半同步协议里,我们增加一个半同步锚点(SemiAnchor)。

以 201 慢同步为例说明。

第一次 201 同步:

  1. 客户端提交 100 个联系人,当前同步点 Anchor
  2. 服务端成功写入 40 个,60 个失败;则生成这 40 个 Mapping 数据,包括 Luid、Guid、Anchor 三个字段;更新 SemiAnchor 的值为 Anchor;返回 100 个 Result 数据,40 个成功,60 个失败
  3. 客户端接收到 100 个 Result 数据,对 40 个成功的数据生成 Mapping;并更新 SemiAnchor 为 Anchor;同步结束,结果为失败

第二次继续发起 201 同步:

  1. 客户端检测有 100 个联系人,但 SemiAnchor 与 Mapping 标记了 40 个同步过的数据,过滤掉这 40 个联系人,只上传 60 个联系人
  2. 服务端接收到 60 个联系人,并成功写入;但服务端有 40 个联系人,需要返回给客户端;进一步检测到 SemiAnchor 和 Mapping,发现这 40 个已同步成功,无需返回给客户端
  3. 客户端拉取数据为 0,无需处理;同步结束,结果为成功;下次则会发起 200 快同步

如上,根据 SemiAnchor 和 Mapping 数据,可以解决同步失败下数据重复提交,二次拉取数据两个场景问题。

File-Sync 协议

文件同步协议,是从 MZ_SyncML 分离出来的独立文件同步协议,它描述了文件类数据的同步方式。

采用和 MZ-SyncML 类似的方式,把变更文件信息列表进行同步,再按需进行上传与下拉文件。

业务上需要考虑一点,即文件对象需与父对象保持一致。

注意,文件同步需在父对像同步完成后进行;并且,文件同步的类型需与父对象同步类型一致。 如联系人本次同步类型是 205,则联系人头像同步类型也必须是 205。否则,会导致联系人头像同步时,解决冲突的合并规则与父对象不一致。

One-Sync 协议

一次同步,即一次交互完成数据同步的协议,它解决联系人分组,便笺分组,短信快速回复、邮箱帐号和浏览器书签等小数据同步的场景。

数据模型设计为{key,value}的结构。key 存储业务的唯一值,如分组名称;value 以 JSON 格式存储多个附属值,如邮箱帐号的帐号类型,帐号名称等。

一般而言,数据变更有增删改(N、U、D)三个类型。对于 key 变更的操作,One-Sync 里把 U 分解为 N、D 两个操作。而对于 key 不变,value 变化的变更操作仍为 U。

One-Sync 只有一个同步点,由服务端同步点 ServerAnchor。

在一次请求中,客户端会上传 SyncType、ServerAnchor 和变更数据;服务端则把 ClientData 和 ServerData 进行比对后存储,然后把比对后的 SyncType、变更数据和 New_ServerAnchor 返回客户端。

One-Sync 同样支持 200、201、203、205 同步类型。以客户端发起 205 同步为例(服务端刷新同步),逻辑如下:

  1. 客户端请求 205 的同步,不提交本地数据
  2. 服务端丢弃客户端提交的数据,返回服务端的所有数据
  3. 客户端接收数据成功,数据处理成功;然后清除本地旧数据,保证本地数据与服务端一致;本次同步结束,结果为成功,下次会进行 200 快同步
  4. 客户端接收数据失败,或接收成功后数据处理失败;则不清除本地旧数据;本次同步结束,结果为失败;下次仍进行 205 同步

同步失败处理机制

同步涉及到客户端、服务端逻辑,实际逻辑中会有失败的场景,我们设计了失败处理的机制。

  1. 在 Submitdata 阶段,服务端处理完客户端数据,会返回每条的结果数据 Result 给客户端,标记成功或失败
  2. 在 Getdata 阶段,客户端处理完服务端数据后,也会提交每条 Result 数据给服务端,标记成功或失败
  3. 只要有一条数据标记为失败,当次同步即被认为失败
  4. 下次同步会使用上次的同步点(如何不重复传输数据,请看 Semi-Sync 协议)

服务架构

分析云同步的业务场景,具有下面的特性:

云同步的服务端服务能力,和用户数成正比关系。魅族云同步随着用户规模的增长,经过几次的重构、线上运行、探索与沉淀,逐步形成了当前平台的架构。

接口规范

我们规范了接口的固有参数,扩展参数,统一返回格式,可精确到代码行的错误码,匹配错误码的信息。

如 userid、imei、sn 为固有参数;像 apk 版本,系统固件为扩展参数,部分接口不需要。

返回格式例子如下:

{

"code":10001

"message":" 参数不合法 "

"value":""

}

其中 code 为错误码,200 为成功,其他为错误。value 是成功时返回的数据,建议使用 JSON 格式传递。

message 是 code 对应的错误信息,它与 code 共同放在资源文件。在返回时由一个 MessageHandler 截停,自动填上 code 对应的 message,不需要人工维护。

模块化 + 单元化

通过业务规整,抽象出了联系人模块、短信模块 、通话记录模块、小业务模块、文件同步模块。

联系人、短信、通话记录是使用频次和数据量最大的 3 个项,故此独立成模块。

文件同步,与结构化数据分离,进行 IO 等有针对性的性能调优。

我们在一个 IDC 里划分了多个服务单元(建议不多于 5 个),每个单元包括服务模块和存储,一个单元服务只服务合理的用户数。这样易于控制规模,分拆风险,维护迁移和容灾。

海量数据 + 路由组件

云同步的数据是海量的,DB 记录数可能达到百亿级、千亿级,单个数据库解决不了云同步的业务场景。

我们按用户标识(Userid)进行水平拆分,设计出多个数据库;配备一个 Userid 到 DB 的路由规则。

单实例 DB 服务器上部署多个数据库,建议 10-30 个,既降低运维成本,又提高资源利用率。

横向扩容时,更新路由规则即可平滑完成。

该 DB 集群,由一个路由组件(SyncRouter)来管理。它包括 Userid 到 DB、Userid 到 Unit、Userid 到 Redis、Userid 到文件系统的多个路由功能。它具有透明访问、业务低耦合、DB 连接池自管理等特点。

我们采用 RDB 存取对用户常用的热数据,而用 NoSQL 存取冷备数据。例如联系人有个时光机的备份功能,我们就采用 HBase 来实现存储。

多机房部署

我们做多机房部署的目的有三,一是用户就近访问,二是流量调度,三是异地容灾。

看如下云同步的架构图,以 3 个 IDC 为例。

(点击放大图像)

部署了多IDC,设计好路由规则,由路由组件提供Userid 到IDC 的路由功能。

IDC 间的用户数据分开,不共享,做好异地容灾,如把 IDC_1 的数据备份到 IDC_2。而在 IDC_1 出现故障无法提供服务时,通过 GSLB 分流,把该用户群分发到 IDC_2 里进行服务。

路由 DB 采用单点写保证一致性。所有 IDC 通过专线访问主 IDC,操作主路由 DB;主 IDC 通过 MQ 通知其他 IDC,进行数据更新,保持数据一致。

手机端根据 Useric 和域名,访问 GSLB 的分发服务,获取到用户相应的同步服务 IP,实现流量调度目的。并且,手机端都通过 IP 访问同步服务,不使用域名,有效避免 DNS 劫持问题。

GSLB 根据 IP 所在区域和所属线路,在最优的 IDC 落地,并返回业务的最优 IP(GSLB 详见魅族另一篇博文,不再赘述)。

理论上,上述的方案仅适应于有客户端的 Http、Https 请求,不适合浏览器访问。 为此,我们做了一个扩展,支持浏览器按 GSLB 的规则进行调度。

  1. 把业务分为总域名、多个子域名(匹配多个 IDC)
  2. 业务层嵌入一个 GSLB 模块,根据设定规则进分发到目标子域名

流量优化

流量优化一方面是采用 gzip 或 deflate 进行压缩传输,一方面是让原始数据尽可能的小。

魅族云同步第一阶段采用 XML 为交换格式;第二阶段上线了 MZSync 项目,采用 JSON 为交换格式。

我们在考虑数据格式时,选出传统 JSON、精简 JSON 和 Protobuf 三种格式,进行对比。

精简 JSON,是指变量名为少量字符,不输出空值变量的 JSON 格式。

Protobuf 本质上是对变量进行排序,不需要传变量名。

精简 JSON 和 Protobuf 的设计原理,有点相似,前者简化变量名,后者不传变量名。

最后,我们选择了精简 JSON 格式,与传统 JSON 相比,能减少 40%-60% 的流量,接近 Protobuf 的值。

参考图如下(使用多维度抽样数据,进行实测计算得到)。

结语

以上,便是在业务的实践、发展中,总结的同步协议,架构部署和数据处理心得。

其中,MZ_SyncML 和 Semi-sync 描述了云同步的核心解决方案,File-Sync 和 One-Sync 描述了云同步的业务解决方案;而 One-Sync 的设计思想较为通用,适用场景不局限于云同步。

多机房部署、GSLB 和路由组件,构成了魅族云同步的核心架构,也保证了高可用;而精简 JSON 并非新技术,我们描述了一种数据交换的思路。欢迎大家讨论交流。



...阅读原文
推荐文章