关于即时通讯:阿里IM技术分享八深度解密钉钉即时消息服务DTIM的技术设计

7次阅读

共计 14653 个字符,预计需要花费 37 分钟才能阅读完成。

本文援用自 InfoQ 社区“5 亿用户如何高效沟通?钉钉首次对外揭秘即时消息服务 DTIM”一文,作者陈万红等、策动褚杏娟,有订正和改变。

一、引言

本文是国内企业 IM 的事实王者钉钉首次对外深度解密其即时消息服务(即 DingTalk IM,简称 DTIM)的技术设计实际。本篇文章内容将从模型设计原理到具体的技术架构、最底层的存储模型到跨地区的单元化等,全方位展示了 DTIM 在理论生产利用中所遇到的各种技术挑战及相应的解决方案,心愿借本文内容的分享能为国内企业级 IM 的开发带来思考和启发。

学习交换:

  • 挪动端 IM 开发入门文章:《新手入门一篇就够:从零开发挪动端 IM》
  • 开源 IM 框架源码:https://github.com/JackJiang2…(备用地址点此)
    (本文已同步公布于:http://www.52im.net/thread-40…)

    二、系列文章

    本文是系列文章的第 8 篇,总目录如下:
    《阿里 IM 技术分享(一):企业级 IM 王者——钉钉在后端架构上的过人之处》
    《阿里 IM 技术分享(二):闲鱼 IM 基于 Flutter 的挪动端跨端革新实际》
    《阿里 IM 技术分享(三):闲鱼亿级 IM 音讯零碎的架构演进之路》
    《阿里 IM 技术分享(四):闲鱼亿级 IM 音讯零碎的牢靠投递优化实际》
    《阿里 IM 技术分享(五):闲鱼亿级 IM 音讯零碎的及时性优化实际》
    《阿里 IM 技术分享(六):闲鱼亿级 IM 音讯零碎的离线推送达到率优化》
    《阿里 IM 技术分享(七):闲鱼 IM 的在线、离线聊天数据同步机制优化实际》
    《阿里 IM 技术分享(八):深度解密钉钉即时消息服务 DTIM 的技术设计》(* 本文)

相干文章:
古代 IM 零碎中聊天音讯的同步和存储计划探讨
钉钉——基于 IM 技术的新一代企业 OA 平台的技术挑战 (视频 +PPT)
企业微信的 IM 架构设计揭秘:音讯模型、万人群、已读回执、音讯撤回等

三、钉钉的技术挑战

钉钉曾经有 2100 万 + 组织、5 亿 + 注册用户在应用。DTIM 为钉钉用户提供即时消息服务,用于组织内外的沟通,这些组织包含公司、政府、学校等,规模从几人到百万人不等。DTIM 有着丰盛的性能,单聊、各种类型的群聊、音讯已读、文字表情、多端同步、动静卡片、专属平安和存储等等。同时:钉钉外部很多业务模块,比方文档、钉闪会、Teambition、音视频、考勤、审批等,每个业务都在应用 DTIM,用于实现业务流程告诉、经营音讯推送、业务信令下发等。每个业务模块对于 DTIM 调用的流量峰值模型各有差异,对可用性要求也不尽相同。DTIM 须要可能面对这些简单的场景,保持良好的可用性和体验,同时兼顾性能与老本。通用的即时消息系统对音讯发送的成功率、时延、达到率有很高的要求,企业 IM 因为 ToB 的个性,在数据安全可靠、零碎可用性、多终端体验、凋谢定制等多个方面有着极致的要求。构建稳固高效的企业 IM 服务,DTIM 次要面临的挑战是:1)企业 IM 极致的体验要求对于零碎架构设计的挑战:比方数据长期保留可漫游、多端数据同步、动静音讯等带来的数据存储效率和老本压力,多端数据同步带来的一致性问题等;2)极限场景冲击、依赖零碎谬误带来的可用性问题:比方超大群音讯,突发疫情带来的线上办公和线上教学高并发流量,零碎须要可能应答流量的冲击,保障高可用;同时在中间件广泛可用性不到 99.99% 的时候,DTIM 服务须要保障外围性能的 99.995% 的可用性;3)不断扩大的业务规模,对于零碎部署架构的挑战:比方持续增长的用户规模,突发事件如席卷寰球的疫情,单地区架构曾经无奈满足业务倒退的要求。DTIM 在零碎设计上:1)为了实现音讯收发体验、性能和老本的均衡,设计了高效的读写扩散模型和同步服务,以及定制化的 NoSQL 存储;2)通过对 DTIM 服务流量的剖析,对于大群音讯、单账号大量的音讯热点以及音讯更新热点的场景进行了合并、削峰填谷等解决;3)外围链路的利用中间件的依赖做容灾解决,实现了繁多中间件失败不影响外围音讯收发,保障根底的用户体验。在音讯存储过程中,一旦呈现存储系统写入异样,零碎会盘旋缓冲重做,并且在服务复原时,数据能被动向端上同步。随着用户数一直增长,繁多地区已无奈承载 DTIM 的容量和容灾需要,DTIM 实现了异地多单元的云原生的弹性架构。在分层上听从的准则为重云轻端:业务数据计算、存储、同步等简单操作尽量后移到云端解决,客户端只做终态数据的接管、展现,通过升高客户端业务实现的复杂度,最大化地晋升客户端迭代速度,让端上开发能够专一于晋升用户的交互体验,所有的性能需要和零碎架构都围绕着该准则做设计和扩大。以下章节咱们将对 DTIM 做更加具体的介绍。

四、模型设计

4.1、DTIM 零碎架构低提早、高触达、高可用始终是 DTIM 设计的第一准则,根据这个准则在架构上 DTIM 将零碎拆分为三个服务做能力的承载。三个服务别离是:1)音讯服务:负责 IM 外围音讯模型和凋谢 API,IM 根底能力包含音讯发送、单聊关系保护、群组元信息管理、历史音讯拉取、已读状态告诉、IM 数据存储以及跨地区的流量转发;2)同步服务:负责用户音讯数据以及状态数据的端到端同步,通过客户端到服务端长连贯通道做实时的数据交互,当钉钉各类设施在线时 IM 及上游各业务通过同步服务做多端的数据同步,保障各端数据和体验统一;3)告诉服务:负责用户第三方通道保护以及告诉性能,当钉钉的自建通道无奈将数据同步到端上时,通过三方提供的告诉和透传能力做音讯推送,保障钉钉音讯的及时性和有效性。同步服务和告诉服务除了服务于音讯服务,也面向其余钉钉业务比方音视频、直播、Ding、文档等多端 (多设施) 数据同步。图 1:DTIM 架构图 ▼

上图展现了 DTIM 零碎架构,接下来具体介绍音讯收发链路。4.2、音讯收发链路图 2:DTIM 音讯解决架构 ▼

1)音讯发送:音讯发送接口由 Receiver 提供,钉钉对立接入层将用户从客户端发送的音讯申请转发到 Receiver 模块,Receiver 校验音讯的合法性(文字图片等平安审核、群禁言性能是否开启或者是否触发会话音讯限流规定等)以及成员关系的有效性(单聊校验二者聊天、群聊校验发送者在群聊成员列表中),校验通过后为该音讯生成一个全局惟一的 MessageId 随音讯体以及接收者列表打包成音讯数据包投递给异步队列,由上游 Processor 解决。音讯投递胜利之后,Receiver 返回音讯发送胜利的回执给客户端。2)音讯解决:Processor 生产到 IM 发送事件首先做按接收者的地区散布(DTIM 反对跨域部署,Geography,Geo)做音讯事件分流,将本域用户的音讯做本地存储入库(音讯体、接收者维度、已读状态、集体会话列表红点更新),最初将音讯体以及本域接收者列表打包为 IM 同步事件通过异步队列转发给同步服务。3)音讯接管:同步服务按接收者维度写入各自的同步队列,同时查取以后用户设施在线状态,当用户在线时捞取队列中未同步的音讯,通过接入层长连贯推送到各端。当用户离线时,打包音讯数据以及离线用户状态列表为 IM 告诉事件,转发给告诉服务的 PNS 模块,PNS 查问离线设施做三方厂商通道推送,至此一条音讯的推送流程完结。4.3、存储模型设计理解 IM 服务最快的路径就是把握它的存储模型。业界支流 IM 服务对于音讯、会话、会话与音讯的组织关系尽管不尽相同,然而归纳起来次要是两种模式:写扩散读聚合、读扩散写聚合。所谓读写扩散其实是定义音讯在群组会话中的存储模式。如下图所示。图 3:读模式和写模式 ▼

如上图所示:1)读扩散的场景:音讯归属于会话,对应到存储中相当于有张 conversation_message 的表存储着该会话产生的所有音讯 (cid->msgid->message,cid 会话 ID、msgid 音讯 ID、message 音讯),这样实现的益处是音讯入库效率高,只存储会话与音讯的绑定关系即可;2)写扩散的场景:会话产生的音讯投递到相似于集体邮件的收件箱,即 message_inbox 表,存储集体的所有音讯(uid->msgid->message,uid 用户 ID、msgid 音讯 ID、message 音讯),基于这种实现,会话中的每条音讯面向不同的接收者能够呈现出不同状态。DTIM 对 IM 音讯的及时性、前后端存储状态一致性要求异样严格,特地对于历史音讯漫游的诉求非常强烈,以后业界 IM 产品对于音讯长时间存储和客户端历史音讯多端漫游都做得不尽如人意,次要是存储老本过高。因而在产品体验与投入老本之间须要找到一个平衡点。采纳读扩散:在个性化的音讯扩大及实现层面有很大的束缚。采纳写扩散带来的问题也很显著:一个群成员为 N 的会话一旦产生音讯就会扩散 N 条音讯记录,如果在音讯发送和扩散量较少的场景,这样的实现相比于读扩散落地更为简略,存储老本也不是问题。然而 DTIM 会话活跃度超高,一条音讯的均匀扩散比能够达到 1:30,超大群又是企业 IM 最外围的沟通场景,如果采纳齐全写扩散所带来存储老本问题势必制约钉钉业务倒退。所以,在 DTIM 的存储实现上,钉钉采取了混合的计划,将读扩散和写扩散针对不同场景做了适配,最终在用户视角零碎会做对立合并,如下图所示。图 4:DTIM 读写混合模式 ▼

作为读扩散、写扩散计划的混合模式存在,用户维度的音讯别离从 conversation_message 和 message_inbox 表中获取,在利用侧按音讯发送工夫做排序合并,conversation_message 表中记录了该会话面向所有群成员接管的一般音讯 N(Normal),而 message_inbox 表在以下两种场景下被写入:1)第一种是:定向音讯 P(Private,公有音讯),群会话中发送的音讯指定了接收者范畴,那么会间接写入到接收者的 message_inbox 表中,比方红包的支付状态音讯只能被红包发送者可见,那么这种音讯即被定义为定向音讯。2)第二种是:归属于会话音讯的状态转换 NP(Normal to Private,一般音讯转公有音讯),当会话音讯通过某种行为使得某些音讯接收者的音讯状态产生转换时,该状态会写入到 message_inbox 表中,比方用户在接管侧删除了音讯,那么音讯的删除状态会写入到 message_inbox 中,在用户拉取时会通过 message_inbox 的删除状态将 conversation_message 中的音讯做笼罩,最终用户拉取不到本人已删除的音讯。当用户在客户端发动某个会话的历史音讯漫游申请时,服务端依据用户上传的音讯截止工夫(message_create_time)别离从 conversation_message 表和 message_inbox 表拉取音讯列表,在应用层做状态的合并,最终返回给用户合并之后的数据,N、P、NP 三种类型音讯在音讯个性化解决和存储老本之间获得了很好的均衡。4.4、同步模型设计 4.4.1 推送模型用户在会话中收回的音讯和音讯状态变更等事件是如何同步到端上呢?业界对于音讯的同步模型的实现计划大抵有三种:1)客户端拉取计划;2)服务端推送计划;3)服务端推送位点之后客户端拉取的推拉联合计划。三种计划各有优劣,在此简短总结:1)首先:客户端拉取计划的长处是该计划施行简略、研发成本低,是传统的 B/S 架构。劣势是效率低下,拉取距离控制权在客户端,对于 IM 这种实时的场景,很难设置一个无效的拉取距离,距离太短对服务端压力大,距离太长时效性差;2)其次:服务端被动推送计划的长处是低提早、能做到实时,最重要的主动权在服务端。劣势绝对拉取计划,如何协调服务端和客户端的解决能力存在问题;3)最初:推拉联合这个计划整合了拉和推的长处,然而计划更简单,同时会比推的计划多一次 RTT,特地是在挪动网络的场景下,不得不面临功耗和推送成功率的问题。DTIM 绝对传统 toC 的场景,有较显著的区别:1)第一是对实时性的要求:在企业服务中,比方员工聊天音讯、各种零碎报警,又比方音视频中的共享画板,无不要求实时事件同步,因而须要一种低延时的同步计划。2)第二是弱网接入的能力:在 DTIM 服务的对象中,上千万的企业组织波及各行各业,从大城市 5G 的高速到偏僻的山区弱网,都须要 DTIM 的音讯能发送、能触达。对于简单的网络环境,须要服务端能判断接入环境,并根据不同的环境条件调整同步数据的策略。3)第三是功耗可控老本可控:在 DTIM 的企业场景中,音讯收发频率比传统的 IM 多出一个数量级,在这么大的音讯收发场景怎么保障 DTIM 的功耗可控,特地是挪动端的功耗可控,是 DTIM 必须面对的问题。在这种要求下,就须要 DTIM 尽量升高 IO 次数,并基于不同的音讯优先级进行合并同步,既能要保障实时性不被毁坏,又要做到低功耗。从以上三点可知,服务端被动推送的模型更适宜 DTIM 场景:1)首先能够做到极低的延时,保障推送耗时在毫秒级别;2)其次是服务端能通过用户接入信息判断用户接入环境好坏,进行对应的分包优化,保障弱网链路下的成功率;3)最初是被动推送绝对于推拉联合来说,能够升高一次 IO,对 DTIM 这种每分钟过亿音讯服务来说,能极大的升高设施功耗,同时配合音讯优先级合并包的优化,进一步升高端的功耗。虽说被动推送有诸多劣势,然而客户端会离线,甚至客户端处理速度无奈跟上服务端的速度,必然导致音讯沉积。DTIM 为了协调服务端和客户端解决能力不统一的问题,反对 Rebase 的能力,当服务端音讯沉积的条数达到肯定阈值时触发 Rebase,客户端会从 DTIM 拉取最新的音讯,同时服务端跳过这部分音讯从最新的位点开始推送音讯。DTIM 称这个同步模型为推优先模型(Preferentially-Push Model,PPM)。在基于 PPM 的推送计划下,为了保障音讯的牢靠达到,DTIM 还做一系列优化。这些优化具体是:1)反对音讯可重入:服务端可能会针对某条音讯做反复推送,客户端须要依据 msgId 做去重解决,防止端上音讯反复展现。2)反对音讯排序:服务端推送音讯特地是群比拟沉闷的场景,某条音讯因为推送链路或者端侧网络抖动,推送失败,而新的音讯失常推送到端侧,如果端上不做音讯排序的话,音讯列表就会产生乱序,所以服务端会为每条音讯调配一个工夫戳,客户端每次进入音讯列表就是依据工夫戳做排序再投递给 UI 层做音讯展现。3)反对缺失数据回补:在某个极其状况下客户端群音讯事件比群创立事件更早达到端上,此时端上没有群的根本信息音讯也就无奈展示,所以须要客户端被动向服务端拉取群信息同步到本地,再做音讯的透出。4.4.2 多端数据一致性多端数据一致性问题始终是多端同步最外围的问题,单个用户能够同时在 PC、Pad 以及 Mobile 登录,音讯、会话红点等状态须要在多端保持一致,并且用户更换设施状况下音讯能够做全量的回溯。基于下面的业务诉求以及零碎层面面临的诸多挑战,钉钉自研了同步服务来解决一致性问题。钉钉的同步服务的设计理念和准则如下:1)对立音讯模型形象,对于 DTIM 服务产生的新音讯以及已读事件、会话增删改、多端红点革除等事件对立形象为同步服务的事件;2)同步服务不感知事件的类型以及数据序列化形式。同步服务为每个用户的事件调配一个自增的 ID(注:这里非间断递增),确保音讯能够依据 ID 做遍历的有序查问;3)对立同步队列,同步服务为每个用户调配了一个 FIFO 的队列存储,自增 id 和事件串行写入队列;当有事件推送时,服务端依据用户以后各端在线设施状态做增量变更,将增量事件推送到各端;4)依据设施和网络品质的不同能够做多种分包推送策略,确保音讯能够有序、牢靠、高效的发送给客户端。下面介绍了 DTIM 的存储模型以及同步模型的设计与思考:1)在存储优化中,存储会基于 DTIM 音讯特点进行深度优化,并会对其中原理以及实现细节做深入分析与介绍;2)在同步机制中,会进一步介绍多端同步机制是如何保障音讯必达以及各端音讯一致性。

五、音讯存储设计

DTIM 底层应用了表格存储作为音讯零碎的外围存储系统,表格存储是一个典型 LSM 存储架构,读写放大是此类零碎的典型问题。LSM 零碎通过 Major Compaction 来升高数据的 Level 高度,升高读取数据放大的影响。在 DTIM 的场景中,实时音讯写入超过百万 TPS,零碎须要划归十分多的计算资源用于 Compaction 解决,然而在线音讯读取提早毛刺仍旧重大。在存储的性能剖析中,咱们发现如下几个特点:1)6% 的用户奉献了 50% 左右的音讯量,20% 的用户奉献了 74% 的音讯量。高频用户产生的音讯远多于低频用户,在 Flush MemTable 时,高频用户音讯占据了文件的绝大部分;2)对于高频的用户,因为其“高频”的起因,当音讯进入 DTIM,零碎发现用户设施在线(高概率在线),会立刻推送音讯,因而须要推送的音讯大部分在内存的 MemTable 中;3)高频用户产生大量的音讯,Compaction 消耗了零碎大量的计算和 IO 资源;4)低频的用户音讯通常散落在多个文件当中。从下面的四个体现来看,咱们能得出如下论断:1)绝大部分 Compaction 是有效的计算和 IO,因为大量音讯写入产生大量的文件,然而高频的用户音讯其实曾经下推给用户的设施,Compaction 对读减速成果大打折扣。反而会抢占计算资源,同时引起 IO 抖动;2)低频用户因为入库音讯频率低,在 Flush 之后的文件中占比低;同时用户上线频率低,期间会累计较多的待接管的音讯,那么当用户上线时,间断的历史音讯高概率散落在多个文件当中,导致遍历读取音讯毛刺,重大的有可能读取超时。为了解决此类问题,咱们采纳分而治之办法,将高频用户和低频用户的音讯区别对待。咱们借鉴了 WiscKey KV 拆散技术的思维,就是将达到肯定阈值的 Value 分离出来,升高这类音讯在文件中的占比进而无效的升高写放大的问题。附:WiscKey KV 原始论文附件下载:WiscKey:Separating Keys from Values in SSD-conscious Storage(52im.net).pdf (2.24 MB)然而 WiscKey KV 拆散仅思考单 Key 的状况,在 DITM 的场景下,Key 之间的大小差距不大,间接采纳这种 KV 拆散技术并不能解决以上问题。因而咱们在原有 KV 拆散的根底上,改良了 KV 拆散,将雷同前缀的多个 Key 聚合判断,如果多个 Key 的 Value 超过阈值,那么将这些 Key 的 Value 打包了 value-block 拆散进来,写入到 value 文件。数据显示:上述办法可能在 Minor Compaction 阶段将 MemTable 中 70% 的音讯放入 value 文件,大幅升高 key 文件大小,带来更低的写放大;同时,Major Compaction 能够更快升高 key 文件数,使读放大更低。高频用户发送音讯更多,因而其数据行更容易被拆散到 value 文件。读取时,高频用户个别把最近音讯全副读出来,思考到 DTIM 音讯 ID 是递增生成,音讯读取的 key 是间断的,同一个 value-block 外部的数据会被程序读取,基于此,通过 IO 预取技术提前读取 value-block,能够进一步提高性能。对于低频用户,其发送音讯较少,K-V 拆散不失效,从而缩小读取时候 value 文件带来的额定 IO。图 5:KV 拆散和预读取 ▼

六、多端同步机制设计

6.1、概述 DTIM 面向办公场景,和面向普通用户的产品在服务端到客户端的数据同步上最大的区别是音讯量微小、变更事件简单、对多端同步有着强烈的诉求。DTIM 基于同步服务构建了一套残缺同步流程。同步服务是一个服务端到客户端的数据同步服务,是一套对立的数据上行平台,撑持钉钉多个应用服务。图 6:微服务架构 ▼

同步服务是一套多端的数据同步服务,由两局部组成:1)部署于服务端的同步服务;2)由客户端 APP 集成的同步服务 SDK。工作原理相似于 MQ 音讯队列:1)用户 ID 近似音讯队列中的 Topic;2)用户设施近似音讯队列中的 Consumer Group。每个用户设施作为一个音讯队列消费者可能按需取得这个用户一份数据拷贝,从而实现了多端同步诉求。当业务须要同步一个变更数据到指定的用户或设施时:业务调用数据同步接口,服务端会将业务须要同步的数据长久化到存储系统中,而后当客户端在线的时候把数据推送给客户端。每一条数据入库时都会原子的生成一个按用户维度枯燥递增的位点,服务端会依照位点从小到大的程序把每一条数据都推送至客户端。客户端应答接管胜利后:更新推送数据最大的位点到位点治理存储中,下次推送从这个新的位点开始推送。同步服务 SDK 外部负责接管同步服务数据,接管后写入本地数据库,而后再把数据异步散发到客户端业务模块,业务模块解决胜利后删除本地存储对应的内容。在上文章节中,曾经初步介绍同步服务推送模型和多端一致性的思考,本章次要是介绍 DTIM 是如何做存储设计、在多端同步如何实现数据一致性、最初再介绍服务端音讯数据沉积技术计划 Rebase。* 举荐浏览:如果您对音讯同步机制没有概念,能够后行浏览《浅谈挪动端 IM 的多点登陆和音讯漫游原理》。6.2、全量音讯存储逻辑在同步服务中,采纳以用户为核心,将所有要推送给此用户的音讯汇聚在一起,并为每个音讯调配惟一且递增的 PTS(即位点,英文术语 Point To Sequence),服务端保留每个设施推送的位点。通过两个用户 Bob 和 Alice,来理论展现音讯在存储系统中存储的逻辑状态。例如:Bob 给 Alice 发送了一个音讯”Hi! Alice“,Alice 回复了 Bob 音讯”Hi! Bob“。当 Bob 发送第一条音讯给 Alice 时,接管方别离是 Bob 和 Alice,零碎会在 Bob 和 Alice 的存储区域开端别离增加一条音讯,存储系统在入库胜利时,会别离为这两行调配一个惟一且递增的位点(Bob 的位点是 10005,Alice 的位点是 23001);入库胜利之后,触发推送。比方 Bob 的 PC 端上一次下推的位点是 10000,Alice 挪动端的推送位点是 23000,在推送流程发动之后,会有两个推送工作,第一是 Bob 的推送工作,推送工作从上一次位点(10000)+ 1 开始查问数据,将获取到 10005 地位的”Hi“音讯,将此音讯推送给 Bob 的设施,推送胜利之后,存储推送位点(10005)。Alice 推送流程也是同理。Alice 收到 Bob 音讯之后,Alice 回复 Bob,相似下面的流程,入库胜利并调配位点(Bob 的位点是 10009,Alice 的位点是 23003)。图 7:同步服务的存储设计 ▼

6.3、音讯多端同步逻辑多端同步是 DTIM 的典型特点,如何放弃多端的数据及时触达和解决一致性是 DTIM 同步服务最大的挑战。上文中曾经介绍了同步服务的事件存储模型,将须要推送的音讯依照用户聚合。当用户有多个设施时,将设施的位点保留在位点管理系统之中,Key 是用户 + 设施 ID,Value 是上一次推送的位点。如果是设施第一次登录,位点默认为 0。由此可知:每个设施都有独自的位点,数据在服务端只有一份依照用户维度的数据,推送到客户端的音讯是服务端对应位点下的快照,从而保障了每个端的数据都是统一的。比方:此时 Bob 登录了手机(该设施之前登录过钉钉),同步服务会获取到设施登录的事件,事件中有此设施上次接收数据的位点(比方 10000),同步服务会从 10000 + 1(位点)开始查问数据,获取到五条音讯(10005~10017),将音讯推送给此台手机并更新服务端位点。此时,Bob 手机和 PC 上的音讯统一,当 Alice 再次发送音讯时,同步服务会给 Bob 的两台设施推送音讯,始终保持 Bob 两个设施之间音讯数据的一致性。6.4、大量需同步离线音讯的优化逻辑正如上文所述:咱们采纳了推优先的模型下推数据以保障事件的实时性,采纳位点治理实现多端同步,然而理论状况却远比下面的状况简单。最常见的问题:就是设施离线从新登录,期间该用户可能会累计大量未接管的音讯数据,比方几万条。如果依照下面的计划,服务端在短时间会给客户端推送大量的音讯,客户端 CPU 资源极有可能耗尽导致整个设施假死。其实对于 IM 这种场景来说:几天甚至几小时之前的数据,再推送给用户曾经丢失即时消息的意义,反而会耗费客户挪动设施的电量,得失相当。又或者节假日大群中各种流动,都会有大量的音讯产生。对于以上状况:同步服务提供 Rebase 的计划,当要推送的音讯累计到肯定阈值时,同步服务会向客户端发送 Rebase 事件,客户端收到事件之后,会从音讯服务中获取到最新的音讯(Lastmsg)。这样能够跳过两头大量的音讯,当用户须要查看历史音讯,能够基于 Lastmsg 向上回溯,即省电也能晋升用户体验。还是以 Bob 为例:Bob 登录了 Pad 设施(一台全新的设施),同步服务收到 Pad 登录的事件,发现登录的位点为 0,查问从 0 开始到以后,曾经累计 1 万条音讯,累计量大于同步服务的阈值,同步服务发送 Rebase 事件给客户端,客户端从音讯服务中获取到最新的一条音讯“Tks !!!”,同时客户端从同步服务中获取最新的位点为 10017,并通知同步服务后续从 10017 这个地位之后开始推送。当 Bob 进入到和 Alice 的会话之后,客户端只有从 Lastmsg 向上回溯几条历史音讯填满聊天框即可。

七、高可用设计

7.1、概述 DTIM 对外提供 99.995% 的可用性 SLA,有上百万的组织将钉钉作为本身数字化办公的基础设施,因为其极广的覆盖面,DTIM 些许抖动都会影响大量企业、机构、学校等组织,进而可能造成社会性事件。因而,DTIM 面临着极大的稳定性挑战。高可用是 DTIM 的外围能力。对于高可用,须要分两个维度来看,首先是服务自我防护,在遇到流量洪峰、黑客攻击、业务异样时,要有流量管控、容错等能力,保障服务在极其流量场景下还有根本服务的能力。其次是服务扩大能力,比方常见的计算资源的扩大、存储资源的扩大等,资源随同流量增长和缩减,提供优质的服务能力并与老本获得较好的均衡。7.2、自我防护 7.2.1 背景 DTIM 常常会面临各种突发大流量,比方万人大群红包大战、早顶峰打卡揭示、春节元旦红包等等都会在短时间内产生大量的聊天音讯,给零碎带来很大的冲击,基于此咱们采纳了多种措施。首先是流量管控,限流是爱护零碎最简略无效的形式。DTIM 服务通过各种维度的限流来爱护本身以及上游,最重要的是爱护上游的存储。在分布式系统中存储都是分片的,最容易呈现的是单个分片的热点问题,DTIM 外面有两个维度的数据:用户、会话 (音讯属于会话), 分片也是这两个维度,所以限流采纳了会话、用户维度的限流,这样既能够爱护上游存储单个分区,又能够肯定水平上限度整体的流量。要控制系统的整体流量, 后面两个维度还不够,DTIM 还采纳了客户端类型、利用 (服务端 IM 上游业务) 两个维度的限流,来防止整体的流量上涨对系统带来的冲击。其次是削峰平谷。限流简略无效,然而对用户的影响比拟大。在 DTIM 服务中有很多音讯对于实时性要求不高,比方经营推送等。对于这些场景中的音讯能够充分利用音讯零碎异步性的特点,应用异步音讯队列进行削峰平谷,这样一方面缩小了对用户的影响,另一方面也加重对上游零碎的刹时压力。DTIM 能够依据业务类型 (比方经营推送)、音讯类型 (比方点赞音讯) 等多种维度对音讯进行分级,对于低优先级的音讯保障在肯定工夫 (比方 1 个小时) 内解决实现。最初是热点优化。DTIM 服务中面临着各种热点问题,对于这些热点问题仅仅靠限流是不够的。比方通过钉钉小秘书给大量用户推送降级揭示,因为是一个账号与大量账号建设会话,因而会存在 conversation_inbox 的热点问题,如果通过限速来解决,会导致推送速度过慢、影响业务。对于这类问题须要从架构上来解决。总的来说,次要是两类问题:大账号和大群导致的热点问题。对于大账户问题,因为 conversation_inbox 采纳用户维度做分区,会导致系统账号的申请都落到某个分区,从而导致热点。解决方案为做热点拆分,既将 conversation_inbox 数据合并到 conversation_member 中 (依照会话做分区),将用户维度的操作转换为会话维度的操作,这样就能够将零碎账号的申请打散到所有分区上,从而实现打消热点。对于大群问题,压力来自大量发消息、音讯已读和贴表情互动,大量的接收者带来极大的扩散量。所以咱们针对以上三个场景,分而治之。7.2.2 计算提早与按需拉取对于音讯发送,个别的音讯对于群外面所有人都是一样的,所以能够采纳读扩散的形式,即不论多大的群,发一条音讯就存储一份。另一方面,因为每个人在每个会话上都有红点数和 Lastmsg, 个别状况下每次发消息都须要更新红点和 Lastmsg,然而在大群场景下会存在大量扩散,对系统带来微小的压力。咱们的解决方案为,对于大群的红点和 Lastmsg,在发消息时不更新,在拉首屏时实时算,因为拉首屏是低频操作且每个人只有一到两个大群,实时计算压力很小,这样高峰期能够缩小 99.99 % 的存储操作, 从而解决了大群发音讯对 DTIM 带来的冲击。7.2.3 申请合并在大群发音讯的场景中,如果用户都在线,刹时就会有大量已读申请,如果每个已读申请都解决,则会产生 M*N(M 音讯条数,N 群成员数) 的扩散,这个扩散是非常恐怖的。DTIM 的解决方案是客户端将一个会话中的屡次已读进行合并,一次性发送给服务端,服务端对于每条音讯的已读申请进行合并解决,比方 1 分钟的所有申请合并为 1 次申请。在大群中,进行音讯点赞时,短时间会对音讯产生大量更新,再加上须要扩散到群外面的所有人,零碎整体的扩散量非常微小。咱们发现,对于音讯屡次更新的场景,能够将一段时间外面屡次更新合并,能够大大减少扩散量,从理论优化之后的数据来看,高峰期零碎的扩散量同比缩小 96%。即便齐全做到以上几点,也很难提供以后承诺的 SLA,除了避免本身服务呈现问题以外,还必须实现对依赖组件的容灾。咱们整体采纳了冗余异构存储和异步队列与 RPC 相结合的计划,当任意一类 DTIM 依赖的产品呈现问题时,DTIM 都能失常工作,因为篇幅问题,此处不再开展。7.3、程度扩大能力对于服务的弹性扩大能力,也须要分两个维度来看:1)首先:服务外部的弹性扩大,比方计算资源的扩大、存储资源的扩大等,是咱们通常构建弹性扩大能力关注的重点方向;2)其次:跨地区维度的扩大,服务能依据本身须要,在其余区域扩大一个服务集群,新的服务集群承接局部流量,在跨地区层面造成一个逻辑对立的分布式服务,这种分布式服务咱们称之为单元化。7.3.1 弹性利用架构对于 DTIM 的扩展性,因为构建和成长于云上,在弹性扩大能力建设领有了更多云的特点和抉择。对于计算节点:利用具备横向扩大的能力,零碎能在短时间之内感知流量突增进而进行疾速扩容,对于上文提到的各种流动引起的流量上涨,能做到轻松应答。同时,零碎反对定时扩容和缩容,在零碎弹性能力和老本之间获得较好的均衡。对于存储:DTIM 底层抉择了能够程度扩大的 Serverless 存储服务,存储服务外部基于读写流量的大小进行动静调度,利用下层齐全无感知。对于服务本身的扩展性,咱们还施行了不可变基础设施、利用无状态、去单点、松耦合、负载平衡等设计,使 DTIM 构建出了一套高效的弹性利用架构。7.3.2 弹性地区级扩大(单元化)在利用外部实现了高效弹性之后,随同着业务流量的增长,单个地区曾经无奈满足 DTIM 亿级别 DUA 的弹性扩大的需要。因为 DTIM 特点,所有用户都能够在增加好友之后进行聊天,这就意味着不能简略换个地区搭建一套孤岛式的 DTIM。为了解决这种规模下的弹性能力,咱们基于云上的地区架构,在一个 Geo 地区内,构建了一套异地多活、逻辑上是一体的弹性架构,咱们称之为单元化。下图是 DTIM 的单元化架构。图 8:DTIM 单元化架构 ▼:

对于单元化的弹性扩大架构,其中最外围的内容是流量动静调度、数据单地区的自封闭性和单元整体降级。7.3.3 弹性动静调度流量路由决定了数据流向,咱们能够依靠这个能力,将大群流量调度到新的单元来承接急速增长的业务流量,同时实现流量依照企业维度汇聚,提供就近部署能力,进而提供优质的 RT 服务。业界当初支流的单元化调度计划次要是基于用户维度的动态路由分段,这种计划算法简略牢靠,然而很难实现动静路由调度,一旦用户路由固定,无奈调整服务单元。比方:在 DTIM 的场景中,企业(用户)规模是随着工夫增长、用户业务规模增长之后,单地区无奈无效撑持多个大型企业用户时,传统动态计划很难将企业弹性扩大到其余单元,强行迁徙会付出极高的运维代价。因而传统的路由计划不具备弹性调度能力。DTIM 提供一套全局一致性的高可用路由服务零碎 (RoutingService)。服务中存储了用户会话所在单元,音讯服务基于路由服务,将流量路由到不同的单元。利用更新路由数据之后,随之路由信息也发生变化。与此同时,路由服务发动数据勘误事件,将会话的历史音讯数据进行迁徙,迁徙实现之后正式切换路由。路由服务底层依赖存储的 GlobalTable 能力,路由信息更新实现之后,保障跨地区的一致性。7.3.4 弹性单元自关闭数据的单元自关闭是将 DTIM 最重要且规模最大的数据:“音讯数据”的接管、解决、长久化、推送等过程关闭在以后单元中,解除了对其余单元依赖,进而能高效地裁减单元,实现跨地区级别高效弹性能力。要做到业务数据在单元内自关闭,最要害是要辨认分明要解决哪种数据的弹性扩大能力。在 DTIM 的场景下,用户 Profile、会话数据、音讯数据都是 DTIM 最外围的资产,其中音讯数据的规模远超其余数据,弹性扩大能力也是围绕音讯数据的解决在建设。怎么将音讯依照单元数据正当的划分成为单元自关闭的要害维度。在 IM 的场景中,音讯数据来自于人与人之间的聊天,能够依照人去划分数据,然而如果聊天的两个人在不同的单元之间,音讯数据必然要在两个单元拷贝或者冗余,因而依照人划分数据并不是很好的维度。DTIM 采纳了会话维度划分:因为人和会话都是元数据,数据规模无限,音讯数据近乎有限,音讯归属于会话,会话与会话之间并无交加,音讯解决时并没有跨单元的调用。因而,将不同的会话拆分到不同的单元,保障了音讯数据仅在一个单元解决和长久化,不会产生跨单元的申请调用,进而实现了单元自关闭。7.3.5 弹性单元降级在单元化的架构中,为了反对服务级别的横向扩大能力,多单元是根本状态。单元的异样流量亦或者是服务版本保护的影响都会放大影响面,进而影响 DTIM 整体服务。因而:DTIM 重点打造了单元降级的能力,繁多单元失去服务能力之后,DTIM 会将业务流量切换到新的单元,新音讯会从失常的单元下推,钉钉客户端在数据渲染时也不会受到故障单元的影响,做到了单元故障切换用户无感知。

八、本文小结

本文通过模型设计、存储优化、同步机制以及高可用等维度,本文全方位地展现了当代企业级 IM 设计的外围。本文也是对 DTIM 过来一段时间的技术总结,随着用户数的持续增长,DTIM 也在与时俱进、继续迭代和优化,比方反对条件索引进而实现索引减速和老本可控、实现音讯位点的间断累加、实现音讯按需拉取和高效的完整性校验、提供多种上下行通道,进一步晋升弱网下的成功率和体验等。

九、相干文章

[1] 企业级 IM 王者——钉钉在后端架构上的过人之处
[2] 古代 IM 零碎中聊天音讯的同步和存储计划探讨
[3] 钉钉——基于 IM 技术的新一代企业 OA 平台的技术挑战(视频 +PPT)》
[5] 一套亿级用户的 IM 架构技术干货(上篇):整体架构、服务拆分等
[6] 一套亿级用户的 IM 架构技术干货(下篇):可靠性、有序性、弱网优化等
[7] 从老手到专家:如何设计一套亿级音讯量的分布式 IM 零碎
[8] 企业微信的 IM 架构设计揭秘:音讯模型、万人群、已读回执、音讯撤回等
[9] 全面揭秘亿级 IM 音讯的牢靠投递机制
[10] 一套高可用、易伸缩、高并发的 IM 群聊、单聊架构方案设计实际
[11] 一套海量在线用户的挪动端 IM 架构设计实际分享(含具体图文)
[12] 一套原创分布式即时通讯(IM) 零碎实践架构计划
(本文已同步公布于:http://www.52im.net/thread-40…)

正文完
 0