移步公众号文章 预约纸质版《作战地图》
5 月 26 日-27 日,QCon 全球软件开发大会落地广州。关注【融云全球互联网通信云】了解更多
融云 IM 服务架构师罗伟受邀分享“实时社区的海量消息分发实践”,从实践中来的前沿技术分享,收获现场开发者的热烈响应和一致好评。
移步公众号后台回复“QCon”获演讲 PPT~
实时社区的代表性平台 Discord 近期又收获了一波热度,这次是源于谈论 AIGC 无法绕开的“网红”Midjourney。
Midjourney 直接内置集成在 Discord 里,以频道的形式提供服务,上线不到一年已经实现了近 1500 万用户和 1 亿美元营收。
这便是实时社区的神奇之处。它拥有高度灵活性和可扩展性,可以适配多样玩法。无论是虚拟聚会、游戏组队,还是 AIGC 新技术、新应用和新场景,都可以从频道中延展而出,慢慢沉淀。
起初,Discord 被定义为永远在线的聊天室,里面有各种复杂的业务概念,比如子区、公有频道、私有频道。
但从产品形态来说,构建实时社区所使用的融云超级群产品,是完全区别于聊天室和群聊的一种 IM 即时通讯会话类型。(点此了解 IM 产品全形态)
或者说,它可以被简单定义为普通群与聊天室的集合。
先说成员关系:群组有上限,聊天室没有上限;实时社区像聊天室一样无成员上限,同时又像普通群一样,其成员关系是存储落地的,是永久存在的。
再说消息可靠性:普通群离线再连时,服务端会把离线期间产生的消息都同步到端上;聊天室用户一般只关心实时消息,且海量观众同时发同样的内容(如,赞、666),可以对消息执行一定丢弃策略。而实时社区是既有大量实时消息,但同时又要保证可靠性,每条消息都需要收到。
无成员上限且需要保证实时消息可靠性,这就让高并发架构成为实时社区产品设计的关键。
简单来说,高并发架构就是要在正确响应业务请求的情况下,将时长及并发量的拐点后移。这对系统设计、代码都有极高要求,同时也是一个不断迭代、持续优化的过程。
融云高并发架构图,移步公众号后台回复“QCon”看完整 PPT
一个复杂的业务系统,必然需要一个足够复杂的系统来支撑,接入层、服务层、存储层都要分别做最优的考虑和设计。
具体到融云超级群的实践方案上,以下是它的一个简化版本架构图,包括访问接入、内部服务和数据存储及运行维护部分。
在这里,Group 就是上行的主节点,主要负责信息的校验,比如群成员关系、禁言等,是我们实现高可用的关键。
融云采用弱状态服务实现高弹性伸缩,通过哈希算法,根据落点(如以用户 ID 为落点)将用户固定在一台机器上,让本地内存去缓存一些热点数据、消息。过程中,需要解决以下问题。
1. 实时消息如何解决?
在实时社区中,用户可以同时加入无数个“聊天室”,并且每个聊天室还有频道的概念,面临巨大的消息爆炸挑战。我们通过消息驱动、增量拉取、订阅式会话驱动的组合拳来解决这个问题。
消息驱动就是分发消息的时候写入到内存消息环,而非直接放到缓存中。然后通过内存里去读取,基于时间戳通知、拉取,基于用户落点读扩散,保障实时性。
增量拉取就是为用户建立消息索引,保障单个用户消息时间戳线性增长,保障消息不丢。
订阅式会话驱动,不再基于消息通知,而是把会话的变更同步到客户端。客户端按订阅规则,拉取对应会话消息。服务与客户端之间的网络交互,都被大大降低了,它们的时序也有了相应的保证。
图说实时消息解法,移步公众号后台回复“QCon”看完整 PPT
2. 海量离线消息如何落地?
实时社区中的用户可能加入多个群,每个群又有海量消息。用户离线再上线后,如果所有消息都做同步,会是一个漫长的过程。我们通过几个核心机制来解决这个问题。
会话驱动,用户离线期间产生的消息由服务端计数,包括未读数、未读@数、首条未读、最后一条消息等。再次上线时,通过会话驱动直接一次同步至客户端,而不是一条一条拉取消息,以解决海量离线消息的高并发问题。
消息断档,服务端基于拉取时间戳判断,消息环外的时间戳则标记断档,消息断档前的消息,需要用历史消息补全。这个机制主要解决会话驱动可能会产生的历史消息不全问题。
历史消息补全,不是服务端主动下发,而是由客户端根据最后一条消息,向前补全,或者由客户端根据断档标记自动补全。
假设一个有 80 万成员的实时社区,每秒发布 5 条消息。在 10 台节点支持下,单节点能够处理 10 万用户。
那么,单节点需要每秒处理 40 万分发消息,也就是每秒需要 40 万次的内存计算更新。这将对 CPU 和网络造成巨大压力。
图说实时消息分发压力,移步公众号后台回复“QCon”看完整 PPT
融云在内部实践中把它做成了一个实时会话,引入了读更新和写更新两个机制来完成流量削峰任务。
读更新,也就是说,不在分发的时候计算,而是在拉取的时候由服务端计算。因为在上行的时候已经存储了会话的消息索引,可以按用户所在的群和频道,根据会话的消息索引计算未读数,也可以理解为是一个懒加载的模式。
实际业务中会有一些个人用户相关的特性,需要做到写更新。比如,个人未读数变更时更新(@消息),会话当日首条消息时更新以及会话首次激活时更新。
这样,原来分发时需要做的 40 万次内存计算就直接被砍掉了,也就不会再消耗大量的 CPU 了。
与之对应的,用户上线时同步会话,主节点会在上行时保存一条占用存储非常小的消息索引。
最终,就可以做到把高峰流量计算和 CPU 占用转化为在用户拉取时才占用内存和网络,实现了削峰的目的。
作为国内第一款超级群 PaaS 产品和原生技术架构,融云超级群是专为打造类 Discord 实时社区而创建的全新会话类型。
这款产品目前已经支持某大型游戏用户社区、某出海元宇宙社区、某会展元宇宙平台等多类业务上线并持续运营,在帮助应用提升用户粘性和拓展社交属性方面释放出了巨大能量