IM系统功能-自动智能扩缩容-直播互动场景中峰值流量的应对

业务形态区别和技术挑战

首先,在业务形态上,与传统的即时消息场景不太一样,直播互动的流量峰值具有“短时间快速聚集”的突发性,流量紧随着主播的开播和结束而剧烈波动。另外,直播互动是以房间为单位,传统的群聊业务和聊天室业务虽然也有千人群和千人聊天室,但和直播间动辄几十万、上百万人的规模相比还是小巫见大巫的。而且,直播互动由于房间有时效限制和明星效应,用户发言和互动的积极性会更高,毕竟可能“错过这村就没这店了”。超大的房间规模及高热度的互动导致的一个问题,就是消息下推的并发峰值。这里我们可以简单用数字来直观感受一下:点对点聊天场景,如果两个人每 10 秒说一句话,实际上每秒的消息下推数只有 0.1;群聊或者聊天室场景,假设是一个 500 人群,如果群里每个人也是每 10 秒说一句话,实际每秒的消息下推数是 500 / 10 * 500 = 25000;那么对于一个 10w 人在线的直播互动场景,如果直播间里每个人也每 10 秒说一句话,实际每秒可产生的消息下推数就是 100000 / 10 * 100000 = 10 亿。当然,这里只是用这个例子计算一下理论值,来让你了解直播互动中的并发压力与普通聊天场景的区别之大。实际上,10 万人的直播间一般不会有这么高的发言和互动热度,即使能达到,也会在服务端进行限流和选择性丢弃。一个是考虑服务端的承受能力基本不可能达到这个量级,另一方面,即使消息能全部推下去,客户端也处理不了每秒一万条消息的接收,对客户端来说,一般每秒接收几十条消息就已经是极限了。因此,由于业务形态的不同,直播互动中的高并发挑战与传统的即时消息场景相比要大得多。

直播互动的高并发应对

对于直播互动中高并发带来的技术挑战,我们从架构层面来看有哪些应对手段呢?下面我们先来分析一下直播互动中的一个比较大的挑战:高并发压力。

在线状态本地化

实际上,直播互动中的并发压力主要来自于消息下推环节中消息从一条扇出成十万条后的那部分,消息扇出前相对压力并不大。那么,我们的优化重点主要是在扇出后的逻辑上,对于普通的消息聊天场景,扇出后的推送逻辑主要是:“查询聊天接收方在哪台接入服务器,然后把消息投递过去,最后由接入服务器通过长连接进行投递。” 如果采用这种方式来处理直播互动的消息下推,大概的流程会是下图这样的:

IM系统功能-自动智能扩缩容-直播互动场景中峰值流量的应对_第1张图片

 首先,用户通过接入网关机进入直播间;接着,网关会上报用户的在线状态;假设这时用户 A 发送了一条弹幕消息,这条消息会在业务逻辑处理层进行处理,并且业务逻辑处理层通过查询刚才维护的用户在线状态,会相应地查询用户 A 所在直播间的其他用户都在哪些网关机上,并把相应的消息投递到这些用户所在的网关服务器;最后再由网关服务器推送给用户的设备。

这里存在的一个问题是,在普通的聊天场景中,为了进行精准投递避免资源浪费,一般会维护一个中央的“在线状态”,逻辑层在确定好投递的接收人后,通过这个“在线状态”查询对应接收人所在的网关机,然后只需要把消息投递给这台网关机就可以了。

但是对于直播互动场景来说,如果采用这种模式,一个 10w 人的房间,每条消息需要对这个在线状态进行 10w 次查询,这个量级是非常大的,因此往往这个地方就会成为瓶颈。

那么针对直播互动场景,对于这个“精准投递”应该如何进行优化呢?我们一起来思考一下。一般来说,即使是一个热度较大、在线人数几十万的直播间,房间里的用户实际上也是“无状态的”相对分散在多台网关机上。

以 10w 人的房间来说,假设有 50 台网关机,那么平均每台网关机上这个直播间的用户应该有 2000 人,我们完全没有必要去“精准”确认这个直播间的用户都在哪台网关机上,只需要把这个直播间的消息都全量“投递”给所有网关机即可,每台网关机也只需要在本地维护一个“某个房间的哪些用户的连接在本机”,最终由网关机把消息下推给本机上当前直播间的在线用户。优化后的直播消息下推架构大概是这样:

IM系统功能-自动智能扩缩容-直播互动场景中峰值流量的应对_第2张图片

首先,每一台网关机在启动时会订阅一个全局的消息队列;当用户进入直播间后,会在每台网关机的本机维护一个在线状态;同样的,假设这时用户 A 发送了弹幕消息,这条消息会在业务逻辑处理层进行处理;紧接着再由业务处理层投递给刚才网关机订阅的全局的消息队列,这样所有网关机都能收到消息;最后,每台网关机根据本机维护的某个直播间的在线用户,再把消息下推给用户设备。

通过这个优化,相当于是把直播消息的扇出从业务逻辑处理层推迟到网关层,而且扇出后的下推不需要依赖任何外部状态服务,这样就能大幅提升直播互动消息的下推能力。

至于直播间里极少数的点对点类型的消息扇出下推(比如主播对某个用户禁言后下推给这个用户的提醒消息),可能会有一定的资源浪费,但这类消息数量相对较少,整体上看收益还是比较大的。

微服务拆分

对于直播互动的高并发场景来说,仅仅有架构和设计层面的优化是不够的。比如,下推消息还受制于网关机的带宽、PPS、CPU 等方面的限制,会容易出现单机的瓶颈,因此当有大型直播活动时,还需对这些容易出现瓶颈的服务进行水平扩容。

此外,为了控制扩容成本,我们希望能够区分出直播互动场景里的核心服务和非核心服务,以进一步支持只针对核心服务的扩容。同时,对于核心服务,我们需要隔离出“容易出现瓶颈点的”和“基本不会有瓶颈的”业务。

基于这些考虑,就需要对直播互动的整个服务端进行“微服务拆分”改造。首先,我来分析一下对于整个直播互动的业务来说,哪些是核心服务、哪些是非核心服务。比如:发弹幕、打赏、送礼、点赞、消息下推,这些是比较核心的;其他的如直播回放和第三方系统的同步等,这些业务在直播时我们是不希望干扰到核心的互动消息和行为的收发的。

除此之外,在核心服务里,消息的发送行为和处理一般不容易出现瓶颈,一个 10w 人的直播间里每秒的互动行为一般超不过 1000,在这一步,我们不希望和容易出现瓶颈的消息下推业务混在一起。因此,我们可以把消息的发和收从接入层到业务处理层都进行隔离拆分。整个系统进行微服务化改造后大概就是下面这样:

IM系统功能-自动智能扩缩容-直播互动场景中峰值流量的应对_第3张图片

 核心服务通过 DB 从库或者消息队列的方式与非核心服务解耦依赖,避免被直接影响;容易出现瓶颈的长连接入服务独立进行部署,并且和发送消息的上行操作拆分成各自独立的通道,这样一方面能够隔离上行操作,避免被下行推送通道所影响,另一方面,轻量、独立的长连接入服务非常便于进行扩容。

自动扩缩容

通过微服务拆分后,你就需要考虑如何对拆分出来的服务进行扩容了,因为在平时没有高热度的直播时,考虑到成本的因素,一般不会让整个服务的集群规模太大。当有大型直播活动时,我们可以通过监控服务或者机器的一些关键指标,在热度快要到达瓶颈点时来进行扩容,整个过程实际不需要人工参与,完全可以做成自动化。对于直播互动场景中的监控指标一般可以分为两大类:

业务性能指标,比如直播间人数、发消息和信令的 QPS 与耗时、消息收发延迟等;

机器性能指标,主要是通用化的机器性能指标,包括带宽、PPS、系统负载、IOPS 等。

我们通过收集到的业务性能指标和机器性能指标,再结合模拟线上直播间数据来进行压测,找出单机、中央资源、依赖服务的瓶颈临界点,制定相应的触发自动扩缩容的指标监控阈值。

大概的自动化扩缩容的流程如下:

IM系统功能-自动智能扩缩容-直播互动场景中峰值流量的应对_第4张图片

了解了自动扩缩容的整体流程,还有一个在扩容中需要你关注的问题。对于直播互动的消息下推来说,长连接入服务维护了房间和用户的长连接,那么这里的问题在于:扩容前的机器已经存在的长连接可能已经处于高水位状态,新扩容的机器却没有承载用户连接,而对于长连接入服务前端的负载均衡层来说,大部分都采用普通的 Round Robin 算法来调度,并不管后端的长连接入机器是否已经承载了很多连接,这样会导致后续新的连接请求还是均匀地分配到旧机器和新机器上,导致旧机器过早达到瓶颈,而新机器没有被充分利用。在这种情况下,即便是让负载均衡层支持自定义的复杂的均衡算法,也可能无法解决流量不平衡的问题。因为很多情况下,负载均衡层本身也是需要扩容的,自定义的均衡算法也只能在某一台负载均衡机器上生效,无法真正做到全局的调度和均衡。

一个更好的方案是接管用户连接的入口,在最外层入口来进行全局调度。比如,在建立长连接前,客户端先通过一个入口调度服务来查询本次连接应该连接的入口 IP,在这个入口调度服务里根据具体后端接入层机器的具体业务和机器的性能指标,来实时计算调度的权重。负载低的机器权重值高,会被入口调度服务作为优先接入 IP 下发;负载高的机器权重值低,后续新的连接接入会相对更少。通过这种方式,我们就基本能解决旧机器和新机器对于新增流量负载不均衡的问题了。

 小结

我们可以从几个方面来进行针对性的优化:

首先,在线状态本地化维护,降低远程资源依赖,提升单机处理能力。

其次,对服务整体进行拆分,区分核心和非核心服务,隔离“容易出现瓶颈”的服务。

接着,通过收集业务和机器两类指标,建立容量评估模型,自动进行服务扩缩容。

最后,根据后端机器负载水平调度全局,接入服务入口,解决扩容后新接入流量在新扩容机器和旧机器间流量不均衡的问题。

你可能感兴趣的:(IM系统功能-自动智能扩缩容-直播互动场景中峰值流量的应对)