理想状况下,若服务端下发全量节点,客户端铲掉旧数据,并且去拉全量节点的信息,并且用新数据覆盖即可。但是移动端这样做会消耗大量的用户流量,这样的做法是不可接受的。所以若服务端下发全量节点,客户端需要本地对比出增删改节点,再去拉变更节点的具体信息。 增量同步情况下,若服务端下发全量节点,我们在本文中称这种情况为版本号回退,效果类似于客户端用空版本号去同步架构。从统计结果来看,线上版本的同步中有 4% 的情况会出现版本号回退。 阈值分片拉取 若客户端的传的 seq 过旧,增量数据可能很大。此时若一次性返回全部的更新数据,客户端请求的数据量会很大,时间会很长,成功率很低。针对这种场景,客户端和服务端需要约定阈值,若请求的更新数据总数超过这个阈值,服务端每次最多返回不超过该阈值的数据。若客户端发现服务端返回的数据数量等于阈值,则再次到服务端请求数据,直到服务端下发的数据数量小于阈值。 节点结构体优化 在全量同步方案中,节点通过 hash 唯一标示。服务端下发的全量 hash 列表,客户端对比本地存储的全量 hash 列表,若有新的 hash 值则请求节点具体信息,若有删除的 hash 值则客户端删除掉该节点信息。 在全量同步方案中,客户端并不能理解 hash 值的具体含义,并且可能遇到 hash 碰撞这种极端情况导致客户端无法正确处理下发的 hash 列表。 而增量同步方案中,使用 protobuf 结构体代替 hash 值,增量更新中节点的 proto 定义为: 在增量同步方案中,用 vid 和 partyid 来唯一标识节点,完全废弃了 hash 值。这样在增量同步的时候,客户端完全理解了节点的具体含义,而且也从方案上避免了曾经在全量同步方案遇到的 hash 值重复的异常情况。 并且在节点结构体里带上了 seq 。节点上的 seq 来表示该节点的版本,每次节点的具体信息有更新,服务端会提高节点的 seq,客户端发现服务端下发的节点 seq 比客户端本地的 seq 大,则需要去请求节点的具体信息,避免无效的节点信息请求。 判断完整架构同步完成 因为 svr 接口支持传阈值批量拉取变更节点,一次网络操作并不意味着架构同步已经完成。那么怎么判断架构同步完成了呢?这里客户端和服务端约定的方案是: 若服务端下发的(新增节点+删除节点)小于客户端传的阈值,则认为架构同步结束。 当完整架构同步完成后,客户端需要清除掉缓存,并进行一些额外的业务工作,譬如计算部门人数,计算成员搜索热度等。 增量同步方案 - 完整流程图 考虑到各种边界条件和异常情况,增量同步方案的完整流程图为: 增量同步方案难点 在加入增量和分片特性后,针对几十万人的超大企业,在版本号回退的场景,怎样保证架构同步的完整性和方案选择成为了难点。 前文提到,隐藏规则变更以及后台物理删除无效节点后,客户端若用很旧的版本同步,服务端算不出增量节点,此时服务端会下发全量节点,客户端需要本地对比所有数据找出变更节点,该场景可以理解为版本号回退。在这种场景下,对于几十万节点的超大型企业,若服务端下发的增量节点过多,客户端请求的时间会很长,成功率会很低,因此需要分片拉取增量节点。而且拉取下来的全量节点,客户端处理不能请求全量节点的具体信息覆盖旧数据,这样的话每次版本号回退的场景流量消耗过大。 因此,针对几十万节点的超大型企业的增量同步,客户端难点在于: 断点续传。增量同步过程中,若客户端遇到网络问题或应用中止了,在下次网络或应用恢复时,能够接着上次同步的进度继续同步。 同步过程中不影响正常展示。超大型企业同步的耗时可能较长,同步的时候不应影响正常的组织架构展示。 控制同步耗时。超大型企业版本号回退的场景同步非常耗时,但是我们需要想办法加快处理速度,减少同步的消耗时间。 思路 架构同步开始,将架构树缓存在内存中,加快处理速度。 若服务端端下发了需要版本号回退的 flag,本地将 db 中的节点信息做一次备份操作。 (责任编辑:本港台直播) |