企业组织架构同步优化的思路
作为企业级的,在业务快速发展的背景下,迭代优化的要求也越发急迫。企业初版的全量同步⽅案在快速的业务增长⾯前已经捉襟见肘,针对其遇到的问题,怎样做好组织架构同步优化?这是⼜⼀篇来⾃团队的技术实战。
写在前⾯
企业在快速发展过程中,陆续有⼤企业加⼊使⽤,企业初版采⽤全量同步⽅案,该⽅案在⼤企业下存在流量和性能两⽅⾯的问题,每次同步消耗⼤量流量,且在 iPhone 5s 上拉取 10w+ 成员架构包解压时会提⽰ memory warning ⽽应⽤崩溃。
全量同步⽅案难以⽀撑业务的快速发展,优化同步⽅案越来越有必要。本⽂针对全量同步⽅案遇到的问题进⾏分析,提出组织架构增量同步⽅案,并对移动端实现增量同步⽅案的思路和重难点进⾏了讲解。
企业业务背景
在企业中,组织架构是⾮常重要的模块,⽤户可以在⾸页的 tab 上选择"通讯录"查看到本公司的组织架构,并且可以通过"通讯录"到本公司的所有成员,并与其发起会话或者视频语⾳通话。
组织架构是⾮常重要且敏感的信息,企业作为企业级产品,始终把⽤户隐私和安全放在重要位置。针对组织架构信息,企业管理员具有⾼粒度隐私保护操作权限,不仅⽀持个⼈信息隐藏,也⽀持通讯录查看权限等操作。
在企业中,组织架构特征有:
1、多叉树结构。叶⼦节点代表成员,⾮叶⼦节点代表部门。部门最多只有⼀个⽗部门,但成员可属于多个部门。
2、架构隐藏操作。企业管理员可以在管理后台设置⽩名单和⿊名单,⽩名单可以查看完整的组织架构,其他成员在组织架构⾥看不到他们。⿊名单的成员只能看到⾃⼰所在⼩组和其所有的⽗部门,其余⼈可以看到⿊名单的成员。
3、组织架构操作。企业管理员可以在 web 端和 app 端添加 / 删除部门,添加 / 删除 / 移动 / 编辑成员等操作,并且操作结果会及时同步给本公司所有成员。
全量同步⽅案的问题
本节⼤致讲解下全量同步⽅案实现以及遇到的问题。
都美竹吴亦凡事件是怎么回事
全量同步⽅案原理
企业在 1.0 时代,从稳定性以及快速迭代的⾓度考虑,延⽤了企业邮通讯录同步⽅案,采取了全量架构同步⽅案。
核⼼思想为服务端下发全量节点,客户端对⽐本地数据出变更节点。此处节点可以是⽤户,也可以是部门,将组织架构视为⼆叉树结构体,其下的⽤户与部门均为节点,若同⼀个⽤户存在多个部门下,被视为多个节点。
全量同步⽅案分为⾸次同步与⾮⾸次同步:
⾸次同步服务端会下发全量的节点信息的压缩包,客户端解压后得到全量的架构树并展⽰。
⾮⾸次同步分为两步:中国10大黑社会老大
服务端下发全量节点的 hash 值。客户端对⽐本地数据到删除的节点保存在内存中,对⽐到新增的节点待请求具体信息。
客户端请求新增节点的具体信息。请求具体信息成功后,再进⾏本地数据库的插⼊ / 更新 / 删除处理,保证同步流程的原⼦性。
⽤户反馈
初版上线后,收到了⼤量的组织架构相关的 bug 投诉,主要集中在:
流量消耗过⼤。
客户端架构与 web 端架构不⼀致。
组织架构同步不及时。
这些问题在⼤企业下更明显。
问题剖析
深究全量同步⽅案难以⽀撑⼤企业同步的背后原因,皆是因为采取了服务端全量下发 hash 值⽅案的原因,⽅案存在以下问题:
拉取⼤量冗余信息。即使只有⼀个成员信息的变化,服务端也会下发全量的 hash 节点。针对⼏⼗万⼈的⼤企业,这样的流量消耗是相当⼤的,因此在⼤企业要尽可能的减少更新的频率,但是却会导致架构数据更新不及时。
⼤企业拉取信息容易失败。全量同步⽅案中⾸次同步架构会⼀次性拉取全量架构树的压缩包,⽽超⼤企业这个包的数据有⼏⼗兆,解压后⼏百兆,对内存不⾜的低端设备,⾸次加载架构可能会出现内存不⾜⽽ crash。⾮⾸次同步在对⽐出新增的节点,请求具体信息时,可能遇到数据量过⼤⽽请求超时的情况。
客户端⽆法过滤⽆效数据。客户端不理解 hash 值的具体含义,导致在本地对⽐ hash 值时不能过滤掉⽆效 hash 的情况,可能出现组织架构展⽰错误。
优化组织架构同步⽅案越来越有必要。
寻优化思路
寻求同步⽅案优化点,我们要准原来⽅案的痛点以及不合理的地⽅,通过⽅案的调整来避免这个问题。
组织架构同步难点
准确且耗费最少资源同步组织架构是⼀件很困难的事情,难点主要在:
组织架构架构数据量⼤。消息 / 联系⼈同步⼀次的数据量⼀般情况不会过百,⽽企业活跃企业中有许多上万甚⾄⼏⼗万节点的企业,意味着架构⼀次同步的数据量很轻松就会上千上万。移动端的流量消耗是⽤户⾮常在乎的,且内存有限,减少流量的消耗以及减少内存使⽤并保证架构树的完整同步是企业追求的⽬标。
架构规则复杂。组织架构必须同步到完整的架构树才能展⽰,⽽且企业⾥的涉及到复杂的隐藏规则,为了安全考虑,客户端不应该拿到隐藏的成员。
修改频繁且改动⼤。组织架构的调整存在着新建部门且移动若⼲成员到新部门的情况,也存在解散某个部门的情况。⽽员⼯离职也会通过组织架构同步下来,意味着超⼤型企业基本上每天都会有改动。
技术选型-提出增量更新⽅案
上述提到的问题,在⼤型企业下会变得更明显。在⼏轮⽅案讨论后,我们给原来的⽅案增加了两个特性来实现增量更新:
增量。服务端记录组织架构修改的历史,客户端通过版本号来增量同步架构。
分⽚。同步组织架构的接⼝⽀持传阈值来分⽚拉取。
在新⽅案中,服务端针对某个节点的存储结构可简化为:
李宏毅哥哥
vid 是指节点⽤户的唯⼀标识 id,departmentid 是指节点的部门 id,is_delete 表⽰该节点是否已被删除。
若节点被删除了,服务端不会真正的删除该节点,⽽将 is_delete 标为 true。
若节点被更新了,服务端会增⼤记录的 seq,下次客户端来进⾏同步便能同步到。
其中,seq 是⾃增的值,可以理解成版本号。每次组织架构的节点有更新,服务端增加相应节点的 seq 值。客户端通过⼀个旧的 seq 向服务器请求,服务端返回这个 seq 和最新的 seq 之间所有的变更给客户端,完成增量更新。
图⽰为:
通过提出增量同步⽅案,我们从技术选型层⾯解决了问题,但是在实际操作中会遇到许多问题,下⽂中我们将针对⽅案原理以及实际操作中遇到的问题进⾏讲解。
增量同步⽅案
本节主要讲解客户端中增量同步架构⽅案的原理与实现,以及基础概念讲解。
增量同步⽅案原理
企业中,增量同步⽅案核⼼思想为:
服务端下发增量节点,且⽀持传阈值来分⽚拉取增量节点,若服务端计算不出客户端的差量,下发全量节点由客户端来对⽐差异。增量同步⽅案可抽象为四步完成:
客户端传⼊本地版本号,拉取变更节点。
客户端到变更节点并拉取节点的具体信息。
客户端处理数据并存储版本号。
判断完整架构同步是否完成,若尚未完成,重复步骤 1,若完成了完整组织架构同步,清除掉本地的同步状态。
忽略掉各种边界条件和异常状况,增量同步⽅案的流程图可以抽象为:
接下来我们再看看增量同步⽅案中的关键概念以及完整流程是怎样的。
版本号
同步的版本号是由多个版本号拼接成的字符串,版本号的具体含义对客户端透明,但是对服务端⾮常重要。
版本号的组成部分为:
版本号回退
增量同步在实际操作过程中会遇到⼀些问题:
服务端不可能永久存储删除的记录,删除的记录对服务端是毫⽆意义的⽽且永久存储会占⽤⼤量的硬盘空间。⽽且⽆效数据过多也会影响架构读取速度。当 is_delete 节点的数⽬超过⼀定的阈值后,服务端会物理删除掉所有的 is_delete 为 true 的节点。此时客户端会重新拉取全量的数据进⾏本地对⽐。
⼀旦架构隐藏规则变化后,服务端很难计算出增量节点,此时会下发全量节点由客户端对⽐出差异。
理想状况下,若服务端下发全量节点,客户端铲掉旧数据,并且去拉全量节点的信息,并且⽤新数据杨舒婷
覆盖即可。但是移动端这样做会消耗⼤量的⽤户流量,这样的做法是不可接受的。所以若服务端下发全量节点,客户端需要本地对⽐出增删改节点,再去拉变更节点的具体信息。
增量同步情况下,若服务端下发全量节点,我们在本⽂中称这种情况为版本号回退,效果类似于客户端⽤空版本号去同步架构。从统计结果来看,线上版本的同步中有 4% 的情况会出现版本号回退。
阈值分⽚拉取怎么更新最新版本
若客户端的传的 seq 过旧,增量数据可能很⼤。此时若⼀次性返回全部的更新数据,客户端请求的数据量会很⼤,时间会很长,成功率很低。针对这种场景,客户端和服务端需要约定阈值,若请求的更新数据总数超过这个阈值,服务端每次最多返回不超过该阈值的数据。若客户端发现服务端返回的数据数量等于阈值,则再次到服务端请求数据,直到服务端下发的数据数量⼩于阈值。
沉香重华几月几号上映节点结构体优化
在全量同步⽅案中,节点通过 hash 唯⼀标⽰。服务端下发的全量 hash 列表,客户端对⽐本地存储的全量 hash 列表,若有新的 hash 值则请求节点具体信息,若有删除的 hash 值则客户端删除掉该节点信息。
在全量同步⽅案中,客户端并不能理解 hash 值的具体含义,并且可能遇到 hash 碰撞这种极端情况导
致客户端⽆法正确处理下发的hash 列表。
⽽增量同步⽅案中,使⽤ protobuf 结构体代替 hash 值,增量更新中节点的 proto 定义为:
在增量同步⽅案中,⽤ vid 和 partyid 来唯⼀标识节点,完全废弃了 hash 值。这样在增量同步的时候,客户端完全理解了节点的具体含义,⽽且也从⽅案上避免了曾经在全量同步⽅案遇到的 hash 值重复的异常情况。
并且在节点结构体⾥带上了 seq 。节点上的 seq 来表⽰该节点的版本,每次节点的具体信息有更新,服务端会提⾼节点的 seq,客户端发现服务端下发的节点 seq ⽐客户端本地的 seq ⼤,则需要去请求节点的具体信息,避免⽆效的节点信息请求。
判断完整架构同步完成
因为 svr 接⼝⽀持传阈值批量拉取变更节点,⼀次⽹络操作并不意味着架构同步已经完成。那么怎么判断架构同步完成了呢?这⾥客户端和服务端约定的⽅案是:
若服务端下发的(新增节点+删除节点)⼩于客户端传的阈值,则认为架构同步结束。
当完整架构同步完成后,客户端需要清除掉缓存,并进⾏⼀些额外的业务⼯作,譬如计算部门⼈数,计算成员搜索热度等。
增量同步⽅案 - 完整流程图
考虑到各种边界条件和异常情况,增量同步⽅案的完整流程图为: