本文由作者jhon_11分享,有大量订正和改变。

1、引言
如何设计一款高性能、高并发、高可用的im综合音讯平台是很多公司倒退过程中会碰到且必须要解决的问题。比方一家公司外部的通信零碎、各个互联网平台的客服征询零碎,都是离不开一款好用且保护的不便im综合音讯零碎。

那么,咱们应该怎么样来设计一款三高个性的im零碎,并能同时反对各个业务线的接入(比方:外部OA通信、客服征询、音讯推送等等性能)有呢?

上面就由我来介绍一下我所负责的公司IM综合音讯零碎所经验的架构设计历程,以及架构设计过程中的一些思路和总结,心愿能给你带来启发。
学习交换:

  • 挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》
  • 开源IM框架源码:https://github.com/JackJiang2...(备用地址点此)

(本文已同步公布于:http://www.52im.net/thread-39...)

2、初版IM架构

2.1 概述
im第一版设计的初衷是公司须要一款im消息中间件用于撑持客服征询业务。

然而,思考到为了不便日后其余业务线也能接入音讯沟通平台,所以一开始就将整个音讯核心的能力需要给到中间件团队进行开发,以便除客服外的各业务线接入综合音讯核心,从而实现多元的音讯实时触达能力。

2.2 初版架构介绍
初版架构图如下图所示:

针对下面的架构图,咱们一一解释一下各模块的作用。

1)存储端:

在初版的架构下,存储端咱们应用tidb、redis作为次要存储:

[1] redis用于存储音讯已读未读,缓存连贯信息等性能;
[2] tidb作为开源的分布式数据库,抉择它是为了不便音讯的存储。

2)mq音讯总线:

咱们应用rocketmq来实现音讯总线(PS:即分布式状况下,不同im实例间通过MQ进行音讯交互)。

音讯总线是整个im的外围,应用rocketmq能反对十万级别的tps。根本所有服务都要从音讯总线中生产音讯进行业务解决。

3)zookeeper注册核心:各个服务会注册到zk中,不便服务之间外部进行调用,同样也能够裸露服务给内部进行调用。

4)link服务:

link服务次要用于接管客户端的ws(WebSocket协定)、tcp、udp等协定的连贯。

同时调用用户服务进行认证,并投递连贯胜利的音讯给位置服务进行生产,存储连贯信息。

ws(WebSocket协定)过去的音讯先到link再投递到音讯总线。

5)音讯散发服务:

音讯散发服务次要用于接管音讯总线推过来的音讯进行解决,依照im内部消息协定结构好消息体后,又推送到音讯总线中(比方会推给会话服务、音讯盒子、link服务)。

6)位置服务:

存储link的(WebSocket协定)连贯、tcp连贯等信息,并应用redis进行缓存(key为userId),不便依据UserId查问到该用户所登录的客户端连贯在哪个link上。

一个用户在雷同设施只能登录一个,但能够反对多端登录。

7)用户服务:用于存储所有用户,提供认证查问接口。

8)音讯盒子:存储所有音讯,提供音讯查问、音讯已读未读、音讯未读数、音讯检索等性能。

9)会话服务:治理会话、群聊会话、单聊会话等性能。

2.3 整体时序图
整体架构的时序图如下:

3、初版IM架构存在的问题及思考

在上节的架构设计介绍中,咱们具体分享了初版IM零碎架构的设计思路以及具体流程。

那么在初版IM架构设计中还存在什么样的问题,又该如何优化呢?咱们一条条来看看。

3.1 应用MQ音讯总线的问题
正如上节所分享的那样,咱们初版IM架构中,link服务到音讯散发服务的音讯应用的MQ音讯总线。

初版架构设计中,link服务将音讯下推给音讯散发服务进行解决时,应用的是mq音讯总线(艰深了说,IM集群内不同IM实例间的通信是依赖于MQ进行的消息传递),而mq音讯总线必然做对有肯定的时延(而且时延受制于MQ自身的零碎实现和技术策略)。

举个例子:

当两个处于不同IM实例的客户端A和B聊天时,A用户发送音讯到link --> 音讯总线 --> 音讯散发服务 --> 音讯总线 --> link --> B用户。

正如下面这个例子,im音讯投递流程太长了,并且这样也会大大降低零碎的吞吐量。

3.2 音讯落库为写扩散的问题
其实现阶段咱们应用的是跟微信一样的写扩散策略(详见《企业微信的IM架构设计揭秘:音讯模型、万人群、已读回执、音讯撤回等》)。

那么为啥微信应用写扩散不是缺点,而对于咱们的IM架构来说确是缺点呢?

微信的技术个性:

1)微信号称没有存储用户的聊天记录,全是实时推送;
2)微信聊天记录全副会在咱们手机端存储一份,两台手机终端上的聊天记录并不互通,并且互不可见。

咱们的IM综合音讯核心技术个性:

1)综合音讯核心是会有拉取历史聊天记录(服务端拉取)的性能,存储了全量音讯;
2)综合音讯核心的客户端,须要反对网页版本。

综上所述:

1)写扩散对微信这样有挪动端的富客户端版本的即时通讯产品非常敌对,每个音讯在音讯散发的时候给处于这个会话(单聊,群聊)下的所有用户所在客户端先推送音讯,没找到连贯就针对这个用户写一个离线缓存音讯,那么下次该用户登录进来,能够从缓存中拉取到该音讯,并且清掉缓存;
2)写扩散对于咱们这类通用综合音讯平台并不敌对,因为接入方大部分是网页版的客户端,所以没有缓存音讯的能力,浏览器刷新就没有了任何音讯,所以须要实时去服务端拉取历史音讯。假如我是写扩散,在一个群聊中有五百个用户,针对这五百个用户在这个会话,我须要去写五百条音讯,大大的减少了写io,并且还不能写缓存(得写数据库)。

3.3 tidb存在不稳定性和事务并发的问题
tidb是目前支流的开源分布式数据库,查问效率高、无需分库分表。

但同样的,tidb存在一些暗藏的问题:

1)tidb在高并发状况下,并发事务会导致事务失败,具体起因不知;
2)tidb排错老本高,公司很少有tidb业余运维,常常遇到不走索引的状况。

3.4 群聊、单聊冗余在同一个服务的问题
在咱们初版的IM架构设计中,单聊和群聊是冗余在会话服务中的,并且冗余在同一张表的。

其实单聊、群聊从数据角度来说,还是会有些不同(比方业务属性)尽管都是会话,咱们还是须要将这两个服务拆离开,细粒度的服务拆分能更好的把控整体的逻辑。

4、升级版IM架构

4.1 初始架构问题
正如后面两节分享的那样,慢慢的咱们发现初版im架构有很大的不足之处。

在生产上暴露出了以下问题:

1)tps没达到预期,吞吐量不能满足公司业务的倒退;
2)应用的存储中间件难以保护(次要是tidb),试错老本高,常常在生产裸露问题,并且速度越来越慢;
3)音讯写扩散没有太大必要,并大大增加了零碎io次数(起因见上一节);
4)一些个性无奈反对,比方音讯图文检索,音讯已读未读。

4.2 升级版im架构介绍
本次降级后的im架构如下图所示:

如上图所示,改版后的各模块状况如下:

1)存储端:存储端咱们改用了mysql,针对音讯服务独自应用了主从mysql集群(主节点用于写音讯、从节点用于音讯检索)——;
2)mq音讯总线:与第一版相比没有改变;
3)link服务:与第一版相比,改变了link服务到音讯散发服务的音讯推送形式(由MQ总线形式变更为tcp实时推送);
4)音讯散发服务:集成了音讯解决能力、路由能力,每台音讯散发服务领有所有link服务的tcp连贯;
5)单聊服务:负责单聊会话的治理能力;
6)群聊服务:负责群聊会话的治理能力;
7)用户服务:提供用户认证,登录\注册能力。

5、具体比照针对初版IM架构的改变

升级版的IM架构,比照初始初始,具体次要是上面这些改变。

5.1 改良了不同im实例间的音讯散发形式
针对初版MQ音讯总结的问题,升级版架构中,咱们将link到音讯散发服务改为tcp实时连贯,百万客户端连贯同一台link机器,音讯实时触达能力tps达到16万。

link到音讯散发服务的改版是本次设计的亮点之一,齐全打消了mq推送的时延性,并且路由简略,简直实时触达。

举个例子:(当两个处于不同IM实例的客户端A和B聊天时)

1)初版架构中是:A用户发送音讯到link --> 音讯总线 --> 音讯散发服务 --> 音讯总线 --> link --> B用户;
2)升级版架构是:用户A --> link --> 音讯散发 --> link --> 用户B。
而且:link服务到音讯散发服务集群的音讯推送应用轮询负载平衡的形式,保障偏心,不会导致个别机器负载过高。

5.2 勾销了位置服务
勾销了位置服务(这里的地位不是指的IM音讯里的地理位置音讯哦),音讯散发服务集成位置服务的能力。

音讯散发服务自身业务简略,不须要再独自划分位置服务,因为会减少网络io,并且音讯散发服务直连link,而让它负责路由则更加不便。

5.3 存储由tidb改成了mysql
存储端由tidb改成了mysql,加强了可维护性,音讯服务应用mysql主从读写拆散形式,进步了音讯落库速度与检索速度的同时,也加重数据库压力。

后面有提到过应用tidb这样保护老本高,排查问题难的分布式数据库是一件很苦楚的事件。

而咱们应用mysql更加稳固,大家对mysql的学习老本绝对较低。针对音讯服务应用读写拆散的形式,能大大提高音讯的吞吐量。

5.4 实现了初版无奈实现的个性性能
升级版架构中,咱们实现了初版无奈实现的个性性能,比方音讯已读未读、红包推送、商品链接推送等性能。

新版综合音讯核心退出了音讯已读未读、发送红包、链接推送等性能,但这些性能带有肯定的业务个性,毕竟不是所有Im都须要,可通过配置勾销这些性能。

5.5 音讯由写扩散改为读扩散
升级版IM架构中,音讯存储由写扩散改为了读扩散。

后面咱们有提到写扩散和读扩散的利弊,对于网页端IM咱们更适宜应用读扩散,只须要落一条音讯,大大提高音讯服务的吞吐量.

5.6 减少了门面服务
升级版IM架构中,咱们减少门面服务 im-logic,用于裸露给第三方业务线接口调用。

初版架构中,都是im的各个服务各自裸露接口给到内部进行调用, 而升级版架中咱们对立应用logic服务裸露给内部调用。

在logic服务针对调用能够做一些解决,这样不会影响到整体im的通用,不会减少im底层代码的复杂度,从而将业务逻辑与底层进行解耦。

6、优化后的成果比照

针对升级版和初版IM架构,咱们也做了一些比照测试,具体的测试过程就是具体开展了。

以下是测试后果:

7、业务线接入im综合音讯零碎的业务划分思考

7.1 到底该如何设计高性能通用im综合音讯零碎
对于业务线接入im综合音讯零碎的业务划分,我也做了一些总结和思考,为了更形象和易于了解,我这里以客服零碎以及企业微信为例来进行剖析。

如果我开发了一款通用的im综合音讯零碎,当初有很多业务方须要接入咱们,咱们该如何进行业务域的清晰划分就显得尤为重要,须要在斗争与不斗争中进行均衡。

就像以后市面上开源的im音讯平台来说,存在的问题次要是:要么是集成了很多的业务逻辑,要么就只是一款单纯的客服零碎,再或者就是一款IM好友聊天零碎,两头的业务划分并不明确。当然,这也有益处,拿来就能用,并不需要进行二次业务封装。

那么,到底如何将im设计为一款真正的高性能通用im综合音讯零碎呢?

通用的综合音讯音讯平台只须要有通用的底层能力:

以下案例假如在我曾经依照上述架构设计了一版im综合音讯核心。

7.2 以客服零碎为例
客服零碎:

客服零碎不光须要实现本身业务,还须要整合im的音讯能力(生产im的音讯),来进行场景剖析,实现会话变更、信令音讯推送等逻辑。

客服零碎外部须要依据im的底层反对能力进行相应的业务封装以及客服零碎的客服用户池,c端用户池如何初始化到im的用户核心这些问题都是须要思考进去的。

7.3 外部OA通信为例
外部OA通信:

员工外部OA通信零碎须要集成IM好友性能,须要依据im的用户核心封装组织架构,用户权限等性能。

同时,外部通信零碎须要依据im实现音讯已读未读,群聊列表,会话列表拉取等性能。

8、本文小结

im的综合音讯平台是一款须要高度联合业务的中间件零碎,它间接与业务打交道,跟一般的中间件有基本的区别。

一款好用的im综合音讯平台,间接取决于你的通用性,可扩展性以及零碎吞吐能力。

心愿这篇文章所分享的内容,能对大家开发im时候的思路有所启迪。

9、参考资料

[1] 从零到卓越:京东客服即时通讯零碎的技术架构演进历程
[2] 从游击队到正规军(一):马蜂窝旅游网的IM零碎架构演进之路
[3] 瓜子IM智能客服零碎的数据架构设计(整顿自现场演讲,有配套PPT)
[4] 阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处
[5] 新手入门一篇就够:从零开发挪动端IM
[6] 零根底IM开发入门(一):什么是IM零碎?
[7] 基于实际:一套百万音讯量小规模IM零碎技术要点总结
[8] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等
[9] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
[10] 从老手到专家:如何设计一套亿级音讯量的分布式IM零碎
[11] 企业微信的IM架构设计揭秘:音讯模型、万人群、已读回执、音讯撤回等
[12] 阿里IM技术分享(三):闲鱼亿级IM音讯零碎的架构演进之路
[13] 一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实际

(本文已同步公布于:http://www.52im.net/thread-39...)