【融云技术】超大规模并发下自定义属性的设置与分发
一. 自定义属性介绍和应用场景
在移动互联网高速发展的新时代,IM 即时通讯得到了快速的发展。IM 中除了传统的图文聊天,在线秀场、在线教育、直播带货、游戏互动等场景应用也越来越广泛。特别是一些一线主播的直播中,直播间动辄几万甚至几十万上百万人同时观看,这对 IM 的通讯并发能力提出了更高的要求。
融云作为 IM 即时通讯和音视频通讯云服务的代表,提供了直播聊天室 SDK 和音视频直播 SDK。而在提供这些基础功能的时候,业务层可能也需要设置一些自己的属性,比如在语音直播聊天室场景的会场属性同步,主播麦位信息、角色管理等等,亦或者狼人杀等卡牌类游戏场景中记录用户的角色和牌局状态等。这些自定义属性都可以丰富整个 IM 的业务形态。
在本篇文章中我重点介绍以聊天室为背景的超大并发规模下,是如何实现这些自定义属性的设置以及分发的。
二. 海量用户下面临的技术挑战
聊天室和普通的 IM 群相比最大的不同点在于它是一个虚拟的组织,聊天室是无界的,所有的人都可以随意的进出聊天室;而群更像一个房间,它是一个有界的、有上限的私密组织。而随着直播行业的蓬勃发展和观看直播人数的与日剧增,直播房间的聊天室更容易出现那种超高并发场景,例如一线主播直播间的聊天室。
自定义属性在进行了设置后,需要及时的将这些属性同步到聊天室中的各个端上。在这个过程中最大的挑战是在分发上。因为如果聊天室人数巨多,而且很多场景自定义属性是具有时效性的,所以及时的将自定义属性同步到各端就很考验服务的高并发场景下的分发能力了。
三. 高并发下自定义属性设置与分发实现
在分布式系统架构中,为了统一聊天室的行为,我们会利用一致性 hash 将同一个聊天室的所有信令汇聚到一个实例上。这样做是有一定好处的,比如能提升服务的缓存命中率,像聊天室人员进出黑/白名单设置和判断等都可以利用内存中的缓存,不用每次都访问第三方缓存,从而提高了聊天室的响应速度。但是这样带来的问题就是,如果聊天室人数过大,聊天室的分发能力会是系统的瓶颈,而且一旦单台主机下发能力达到上限,是无法通过扩容来解决问题的,因为不管怎么扩容,一个聊天室的所有信令还是会汇聚到这个实例中。
为了提升服务的分发能力,我们独立出一套单独的分发服务(聊天室消息服务),具体如下图所示:
在这套架构系统中,我们将聊天室系统分为聊天室服务以及聊天室消息服务,聊天室服务的作用依然是接收聊天室相关的所有上行信令,比如人员进出,自定义属性设置等等。而聊天室消息服务更专注聊天室消息以及自定义属性等的分发。
用户在加入聊天室后,需要根据用户自身的 ID 进行一致性 hash 来算出需要落在哪个聊天室消息服务中,并进行加入。这样一个聊天室的用户就会被平均分散到了聊天室消息服务中。这样做也解决了系统遇到压力后不能扩容的问题。在自定义属性同步到聊天室消息服务上后,分发节点需要将属性放置到内存中,然后给当前节点的所属用户发送一个通知拉取的信令,客户端在收到通知拉取信令后进行自定义属性的拉取。
四. 自定义属性的内存存储和客户端快速拉取
在聊天室消息服务接收到自定义属性变更请求时,会将这份数据保存到全量属性集合里,这个集合里存的是所有的自定义属性集合,如果这份数据被 LRU 淘汰掉或者服务重启的话,会从第三方缓存中重新构建一份数据出来。内存中的全量数据,比较适合于刚加入聊天室的人,他们加入聊天室后直接拉取这些全量数据即可。但是如果已经在聊天室了也已经拉取过全量属性的话,这时聊天室再设置了新的自定义属性或者删除了某一个自定义属性的话,如果客户端想知道刚才的自定义属性的行为,就需要对客户端的全量自定义属性与服务器端自定义属性进行比对。不管比对行为是放在服务器端还是放在客户端都会增加一定的计算压力。为了解决增量数据的同步,我们构建了一份属性变更记录的集合,具体如图所示:
属性变更记录采用的是一个有序的 map 集合 .key 为变更时间戳,value 里存变更的类型以及自定义属性内容,变更的类型主要为设置和删除。这个有序的 map 提供了这段时间内所有的自定义属性的动作,客户端在收到自定义属性变更拉取的通知后,带着自己本地最大自定义属性的时间戳上来拉取,例如图中场景,客户端传的如果是时间戳 6,则会拉取到时间戳为 7 和时间戳为 8 的两条记录。客户端拉取到增量的内容后在本地进行回放,然后对自己本地的内容进行相关的操作即可。
五. 结束语
文章大体解析了融云聊天室的基础架构以及在此架构下,如何做到了超大规模并发下的自定义属性的设置和分发。而随着互联网的高速发展,自定义属性的设置应用会越来越广泛,而并发规模或许会继续提升,届时我们的架构也会迭代,继续为客户提供低延时高可靠的服务。