马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本文作者陈万红等、筹谋褚杏娟,有修订和改动。</p>一、弁言
本文是国内企业IM的究竟王者钉钉初次对外深度解密其即时消息服务(即DingTalk IM,简称DTIM)的技能操持实践。
本篇文章内容将从模子操持原理到具体的技能架构、最底层的存储模子到跨地区的单元化等,全方位显现了 DTIM 在现实生产应用中所遇到的各种技能寻衅及相应的办理方案,盼望借本文内容的分享能为国内企业级IM的开辟带来思索和启发。
二、系列文章
本文是系列文章的第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)体系理论架构方案
即时通讯技能学习:
- 移动端IM开辟入门文章:《新手入门一篇就够:从零开辟移动端IM》
- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK(备用地点点此)
(本文已同步发布于:http://www.52im.net/thread-4012-1-1.html)
|