im即时通讯开发:高可用、易伸缩、高并发的IM群聊、单聊架构方案设计

智极启航
• 阅读 307

要实现一整套能用于大用户量、高并发场景下的IM群聊,技术难度远超IM系统中的其它功能,原因在于:IM群聊消息的实时写扩散特性带来了一系列技术难题。

举个例子:如一个2000人群里,一条普通消息的发出问题,将瞬间写扩散为2000条消息的接收问题,如何保证这些消息的及时、有序、高效地送达,涉及到的技术问题点实在太多,更别说个别场景下万人大群里的炸群消息难题了更别说个别场景下万人大群里的炸群消息难题了。

这也是为什么一般中大型IM系统中,都会将群聊单独拎出来考虑架构的设计,单独有针对性地进行架构优化,从而降低整个系统的设计难度。

所谓的群聊消息系统,就是一种多对多群体聊天方式,譬如直播房间内的聊天室对应的服务器端就是一个群聊消息系统。

系统名词解释:

1)Client : 消息发布者【或者叫做服务端群聊消息系统调用者】,publisher;

2)Proxy :系统代理,对外统一接口,收集Client发来的消息转发给Broker;

3)Broker :系统消息转发Server,Broker 会根据 Gateway Message 组织一个 RoomGatewayList【key为RoomID,value为 Gateway IP:Port 地址列表】,然后把 Proxy 发来的消息转发到 Room 中所有成员登录的所有 Gateway;

4)Router :用户登录消息转发者,把Gateway转发来的用户登入登出消息转发给所有的Broker;

5)Gateway :所有服务端的入口,接收合法客户端的连接,并把客户端的登录登出消息通过Router转发给所有的Broker;

6)Room Message : Room聊天消息;

7)Gateway Message : Room内某成员 登录 或者 登出 某Gateway消息,包含用户UIN/RoomID/Gateway地址{IP:Port}等消息。

当一个 Room 中多个 Client 连接一个 Gateway 的时候,Broker只会根据 RoomID 把房间内的消息转发一次给这个Gateway,由Gateway再把消息复制多份分别发送给连接这个 Gateway 的 Room 中的所有用户的客户端。

这套系统有如下特点:

1)系统只转发房间内的聊天消息,每个节点收到后立即转发出去,不存储任何房间内的聊天消息,不考虑消息丢失以及消息重复的问题;

2)系统固定地由一个Proxy、三个Broker和一个Router构成;

3)Proxy接收后端发送来的房间消息,然后按照一定的负载均衡算法把消息发往某个Broker,Broker则把消息发送到所有与Room有关系的接口机Gateway;

4)Router接收Gateway转发来的某个Room内某成员在这个Gateway的登出或者登录消息,然后把消息发送到所有Broker;

5)Broker收到Router转发来的Gateway消息后,更新(添加或者删除)与某Room相关的Gateway集合记录;

6)整个系统的通信链路采用UDP通信方式。

从以上特点,整个消息系统足够简单,没有考虑扩缩容问题,当系统负载到达极限的时候,就重新再部署一套系统以应对后端client的消息压力。

这种处理方式本质是把系统的扩容能力甩锅给了后端Client以及前端Gateway:每次扩容一个系统,所有Client需要在本地配置文件中添加一个Proxy地址然后全部重启,所有Gateway则需要再本地配置文件添加一个Router地址然后全部重启。

这种“幸福我一人,辛苦千万家”的扩容应对方式,必然导致公司内部这套系统的使用者怨声载道,下一阶段的升级就是必然的了。

接下来迫切要解决的:系统稳定性

系统具有了可扩展性仅仅是系统可用的初步,整个系统要保证最低粒度的SLA(0.99),就必须在两个维度对系统的可靠性就行感知:消息延迟和系统内部组件的高可用。

消息延迟

准确的消息延迟的统计,通用的做法可以基于日志系统对系统所有消息或者以一定概率抽样后进行统计,但限于人力目前没有这样做。即时通讯聊天软件开发可以咨询蔚可云。

目前使用了一个方法:通过一种构造一组伪用户ID,定时地把消息发送给proxy,每条消息经过一层就把在这层的进入时间和发出时间以及组件自身的一些信息填入消息,这组伪用户的消息最终会被发送到一个伪Gateway端,伪Gateway对这些消息的信息进行归并统计后,即可计算出当前系统的平均消息延迟时间。

通过所有消息的平均延迟可以评估系统的整体性能。同时,因为系统消息路由的哈希方式已知,当固定时间内伪Gateway没有收到消息时,就把消息当做发送失败,当某条链路失败一定次数后就可以产生告警了。

高可用

上面的方法同时能够检测某个链路是否出问题,但是链路具体出问题的点无法判断,且实时性无法保证。

im即时通讯开发:高可用、易伸缩、高并发的IM群聊、单聊架构方案设计

为了保证各个组件的高可用,系统引入了另一种评估方法:每个层次都给后端组件发送心跳包,通过心跳包的延迟和成功率判断其下一级组件的当前的可用状态。

譬如proxy定时给每个Partition内每个broker发送心跳,可以依据心跳的成功率来快速判断broker是否处于“假死”状态(最近业务就遇到过broker进程还活着,但是对任何收到的消息都不处理的情况)。

同时依靠心跳包的延迟还可以判断broker的处理能力,基于此延迟值可在同一Partition内多broker端进行负载均衡。

进一步优化:消息可靠性

公司内部内部原有一个走tcp通道的群聊消息系统,但是经过元旦一次大事故(几乎全线崩溃)后,相关业务的一些重要消息改走这套基于UDP的群聊消息系统了。这些消息如服务端下达给客户端的游戏动作指令,是不允许丢失的,但其特点是相对于聊天消息来说量非常小(单人1秒最多一个),所以需要在目前UDP链路传递消息的基础之上再构建一个可靠消息链路。

UDP通信的本质就是伪装的IP通信,TCP自身的稳定性无非是重传、去重和ack,所以不考虑消息顺序性的情况下可以通过重传与去重来保证消息的可靠性。

im即时通讯开发:高可用、易伸缩、高并发的IM群聊、单聊架构方案设计

基于目前系统的可靠消息传输流程如下:

1)Client给每个命令消息依据snowflake算法配置一个ID,复制三份,立即发送给不同的Proxy;

2)Proxy收到命令消息以后随机发送给一个Broker;

3)Broker收到后传输给Gateway;

4)Gateway接收到命令消息后根据消息ID进行重复判断,如果重复则丢弃,否则就发送给APP,并缓存之。

正常的消息在群聊消息系统中传输时,Proxy会根据消息的Room ID传递给固定的Broker,以保证消息的有序性。

当线上需要部署多套群聊消息系统的时候,Gateway需要把同样的Room Message复制多份转发给多套群聊消息系统,会增大Gateway压力,可以把Router单独独立部署,然后把Room Message向所有的群聊消息系统转发。

Router系统原有流程是:Gateway按照Room ID把消息转发给某个Router,然后Router把消息转发给下游Broker实例。新部署一套群聊消息系统的时候,新系统Broker的schema需要通过一套约定机制通知Router,使得Router自身逻辑过于复杂。

类似于Broker,Router Partition也以2倍扩容方式进行Partition水平扩展,并通过一定机制保证扩容或者Partition内部各个实例停止运行或者新启动时,尽力保证数据的一致性。

Router Replica收到Gateway Message后,replica先把Gateway Message转发给Partition内各个peer replica,然后再转发给各个订阅者。Router转发消息的同时异步把消息数据写入Database。

点赞
收藏
评论区
推荐文章
Stella981 Stella981
4年前
IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的
1、引言好久没写技术文章了,今天这篇不是原理性文章,而是为大家分享一下由笔者主导开发实施的IM即时通讯聊天系统,针对大量离线消息(包括消息漫游)导致的用户体验问题的升级改造全过程。文章中,我将从如下几个方面进行介绍:1)这款IM产品的主要业务及特点;2)IM系统业务现状和痛点;3)升级改造之路;
Wesley13 Wesley13
4年前
IM中的万人群聊技术方案实践总结(转)
1、引言在不了解IM技术的人眼里,群聊是再平常不过的功能而已,万人群聊?应该也不难实现吧?!确实,从前端功能界面上来看,群聊无非就是个循环向群员发送消息的一对多聊天消息分发模式而已,难在何处?真实的情况是,群聊是IM系统中的高难度技术点之一。难在哪?难在服务端!从某种角度上说,群聊功能的架构设计和技术实现的品质,可以代表这款IM软件
Wesley13 Wesley13
4年前
IM开发干货分享:如何优雅的实现大量离线消息的可靠投递
1、点评IM聊天消息的可靠投递,是每个线上产品都要考虑的IM热点技术问题。IM聊天消息能保证可靠送达,对于用户来说,就好比把钱存在银行不怕被偷一样,是信任的问题。试想,如果用户能明显感知到聊天消息无法保证送达,谁还愿意来用你的APP?谁也不希望自已的话就像浮云一样随风飘逝。必竟用IM聊天,虽然很多时候是费话,但总有关键时刻存在——比如向
Wesley13 Wesley13
4年前
IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?
1、前言IM的群聊消息,究竟存1份(即扩散读方式)还是存多份(即扩散写方式)?上一篇文章《IM群聊消息的已读回执功能该怎么实现?(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.52im.net%2Fthread161111.html)》是说,
Stella981 Stella981
4年前
IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)
1、引言在中大型IM系统中,聊天消息的唯一ID生成策略是个很重要的技术点。不夸张的说,聊天消息ID贯穿了整个聊天生命周期的几乎每一个算法、逻辑和过程,ID生成策略的好坏有可能直接决定系统在某些技术点上的设计难易度。有中小型IM场景下,消息ID可以简单处理,反正只要唯一就行,而中大型场景下,因为要考虑到分布式的性能、一致性等,所以要考虑的问题
Wesley13 Wesley13
4年前
IM消息送达保证机制实现(二):保证离线消息的可靠投递
1、前言本文的上篇《IM消息送达保证机制实现(一):保证在线实时消息的可靠投递(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.52im.net%2Fthread29411.html)》中,我们讨论了在线实时消息的投递可以通过应用层的确认、发送方的超时重传、接收
Stella981 Stella981
4年前
IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?
1、前言在IM这种讲究高并发、高消息吞吐的互联网场景下,MQ消息中间件是个很重要的基础设施,它在IM系统的服务端架构中担当消息中转、消息削峰、消息交换异步化等等角色,当然MQ消息中间件的作用远不止于此,它的价值不仅仅存在于技术上,更重要的是改变了以往同步处理消息的思路(比如进行IM消息历史存储时,传统的信息系统作法可能是收到一条消息就马上同步存
程序员小五 程序员小五
2年前
单聊、群聊、聊天室、超级群在融云端历史消息存储时间分别是多长?
单聊历史消息与群聊历史消息在融云为同一项存储服务:单群聊历史消息云存储。需自行在开发者后台IM服务管理页面的普通服务标签下开通,开通后单聊、群聊历史消息默认存储6个月。
程序员小五 程序员小五
1年前
融云IM干货丨【 IM 服务】如何下载历史消息?如何获取历史消息日志?怎么下载消息日志
要下载IM服务的历史消息或获取历史消息日志,您可以按照以下步骤操作:开通服务:首先,需要确保您的AppKey已经开通了相关的历史消息日志下载服务。例如,融云提供的单群聊消息云端存储服务需要在控制台IM服务管理页面为当前使用的AppKey开启服务。使用服务端
程序员小五 程序员小五
1年前
融云IM干货丨在Electron中实现获取历史消息,需要注意以下几点
在Electron中实现获取历史消息时,需要注意以下几点:服务开通:从远端获取单群聊历史消息需要AppKey已启用融云提供的单群聊消息云端存储服务。请在融云控制台IM服务管理页面为当前使用的AppKey开启服务。注意,仅IM旗舰版或IM尊享版可开通该服务。
程序员小五 程序员小五
1年前
融云 IM 干货丨如何开通单群聊云存储服务?
如何开通单群聊云存储服务融云平台1、登录融云控制台:访问融云开发者文档页面,登录融云控制台。2、进入IM服务管理页面:在控制台的左侧导航栏中,选择IM服务管理。3、开通单群聊消息云端存储服务:在IM服务管理页面,找到单群聊消息云端存储服务,点击开通按钮。该