写点什么

一套十万级 TPS 的 IM 综合消息系统的架构实践与思考

作者:JackJiang
  • 2022 年 6 月 28 日
  • 本文字数:5021 字

    阅读完需:约 16 分钟

一套十万级TPS的IM综合消息系统的架构实践与思考

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

1、引言

如何设计一款高性能、高并发、高可用的 im 综合消息平台是很多公司发展过程中会碰到且必须要解决的问题。比如一家公司内部的通讯系统、各个互联网平台的客服咨询系统,都是离不开一款好用且维护的方便 im 综合消息系统。

那么,我们应该怎么样来设计一款三高特性的 im 系统,并能同时支持各个业务线的接入(比如:内部 OA 通讯、客服咨询、消息推送等等功能)有呢?

下面就由我来介绍一下我所负责的公司 IM 综合消息系统所经历的架构设计历程,以及架构设计过程中的一些思路和总结,希望能给你带来启发。

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群聊、单聊架构方案设计实践

学习交流:

- 移动端 IM 开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源 IM 框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

(本文已同步发布于:http://www.52im.net/thread-3954-1-1.html

用户头像

JackJiang

关注

还未添加个人签名 2019.08.26 加入

开源IM框架MobileIMSDK、BeautyEye的作者。

评论

发布
暂无评论
一套十万级TPS的IM综合消息系统的架构实践与思考_网络编程_JackJiang_InfoQ写作社区