随着直播应用的普及,特别是直播带货概念的普及,大用户的直播场景已经正常化。
大用户直播室的实时互动非常频繁,具体体现在各种用户聊天、弹幕、礼物、拇指、禁止、系统通知等实时信息上。
如此大量的实时信息,如何处理分发不会打破服务端,到客户端不会让应用程序疯狂刷新和卡住(不会影响用户体验),这显然需要特殊的技术手段和实现策略来处理。
事实上,直播室的实时消息分发在技术上与传统的在线聊天室概念相同,但在传统的互联网时代,聊天室的在线用户数量不会那么大。虽然数量级不同,但技术模型可以完全应用。
我们以百万人观看的直播间为例,看看需要面对哪些技术挑战。
1)直播中会有一波又一波的新闻高峰,比如直播中的刷新新闻,即大量用户同时发送的大量实时新闻。一般来说,这种刷新新闻的内容基本相同。如果所有信息都显示在客户端,客户端很可能会卡住、延迟等问题,严重影响用户体验。
2)在大量消息的情况下,如果服务端的每一条消息都长期存储,就会导致服务缓存就会激增,内存就会成为性能瓶颈。
3)在其他场景中,如直播室房间管理员操作后的通知消息或系统通知。一般来说,这类消息更为重要。如何优先保证其到达率。
基于这些挑战,我们的服务需要根据业务场景进行优化。
下面将简要说明主要服务。
1)直播间服务:
主要功能是:缓存直播间的基本信息。包括用户列表、禁言/禁言关系、白名单用户等。
2)新闻服务:
主要功能是:缓存本节点需要处理的用户关系信息、消息队列信息等。
具体来说,这是以下两件大事。
直播间用户关系同步:
A)成员主动加入退出:直播间服务同步至==>消息服务;
b)发现用户已离线时:消息服务同步至==>直播间服务。
发送消息:
a)直播间服务经必要验证通过后,将消息广播到消息服务;
b)直播间服务不缓存消息内容。
3)Zk(即Zookeeper):
主要功能是将所有服务实例注册到ZK,并在服务间流通时使用数据进行落点计算。
具体就是:
a)直播间服务:按直播间ID落点;
b)消息服务:根据用户ID落点。
4)Redis:
主要用于二次缓存,以及服务更新(重启)时内存数据的备份。
我们的消息分发过程主要如下:
1)用户A在直播间发送消息,首先由直播间服务处理;
2)直播间服务将消息同步到各消息服务节点;
3)消息服务向本节点缓存的所有成员发出通知;
4)如上图所示的消息服务-1,将向用户B发出通知。
此外,由于消息量过大,我们在分发过程中有通知合并机制,通知合并机制主要提到上述步骤3。
上述步骤3通知合并机制的原理如下:
a)将所有成员加入待通知队列(如有,更新通知时间);
b)下发线程,轮训获得待通知队列;
c)向队列中的用户发出通知。
通过通知合并机制,我们可以确保线程只向同一用户发送一个通知,即多个消息合并为通知,有效提高服务端性能,降低客户端和服务器的网络消耗。
我们的消息提取过程主要如下:
1)收到通知后,用户B将向服务端发送拉取消息请求;
2)该请求将由消息服务-1节点处理;
3)消息服务-1将根据客户端传输的最后一条消息时间戳,从消息队列中返回消息列表;
4)用户B获取新消息。
对于直播室的用户来说,很多消息其实并没有太大的实际意义,比如大量重复的刷新消息和动态通知。为了提升用户体验,这类消息可以有策略地丢弃(这与IM中的实时聊天消息最大的区别,IM中不允许丢失)。
PS:直播间消息分发的丢弃策略,结合节中的通知合并机制,可以稳定直接间大量消息,顺利分发。
我们的丢弃策略主要由以下三部分组成:
1)上行限速控制(丢弃)策略;
2)下行限速控制(丢弃)策略;
3)重要消息防丢弃策略。
让我们一一解释一下。
1)上行限速控制(丢弃)策略:
对于上行限速控制,默认为200条/秒,可根据业务需要进行调整。达到限速后发送的消息将在直播间丢弃,不再与每个消息服务节点同步。
2)下行限速控制(丢弃)策略:
对下行限速控制,即对消息环队列长度的控制(见5.2消息提取过程中提取消息的详细逻辑图),达到最大值后最老的消息将被淘汰和丢弃。
每次发出通知后,服务器都会将用户标记为拉取中,用户实际拉取消息后将标记删除。
拉中标记的功能:例如,用户在产生新消息时有拉中标记,如果距离设置标记时间2秒内不发出通知(降低客户压力,丢弃通知不丢弃消息),2秒以上继续发出通知(连续多次通知触发用户踢出策略,此处不重复)。
因此,消息是否丢弃取决于客户端的提取速度(受客户端性能和网络影响),而客户端没有丢弃消息。
3)重要消息防丢弃策略:
如前文所述:在直播间场景中,对某些消息要有较高的优先级,不能丢弃。
例如:直播间房间管理员操作后通知消息或系统通知。
针对这一场景:我们设置了信息白名单和信息优先级的概念,以确保不被丢弃。如本节开头的图所示,可以有多个消息环队列,与普通直播间的消息分离保证了重要消息不被丢弃。