直播系统聊天技术 (四):百度直播的海量用户实时消息系统架构演进实践
本文原题“百度直播消息服务架构实践”,由百度 APP 消息中台团队原创分享于“百度 Geek 说”公众号,为了让文章内容更通俗易懂,本次已做排版优化和内容重新划分,原文链接在文末。
1、引言
一套完整的直播系统核心功能有两个:
1)实时音视频的推拉流;2)直播间消息流的收发(包括聊天消息、弹幕、指令等)。本文主要分享的是百度直播的消息系统的架构设计实践和演进过程。
实际上:直播间内用户的聊天互动,虽然形式上是常见的 IM 聊天消息流,但直播消息流不仅仅是用户聊天。
除用户聊天外:直播间内常见的用户送礼物、进场、点赞、去购买、主播推荐商品、申请连麦等互动行为的实时提醒,也是通过消息流下发的。
此外:直播间关闭、直播流切换等特殊场景,也依赖消息流的实时下发。
所以,直播系统内的消息流可以认为是直播间内主播与用户间实时互动和直播间实时控制的基础能力,也是系统支撑。如果说实时音视频推拉流是直播系统的灵魂,那消息流可以说是直播系统的骨架,它的重要性不言而喻。
那么,如何构建直播的消息系统,又有哪些挑战需要解决,借着本文我们一起来梳理一下。
2、系列文章
本文是系列文章中的第 4 篇:
《直播系统聊天技术(一):百万在线的美拍直播弹幕系统的实时推送技术实践之路》
《直播系统聊天技术(二):阿里电商 IM 消息平台,在群聊、直播场景下的技术实践》
《直播系统聊天技术(三):微信直播聊天室单房间 1500 万在线的消息架构演进之路》
《直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践》(* 本文)
3、与普通 IM 群聊的区别
直播间内的聊天消息,经常被类比于普通的 IM 群聊功能。
群聊是大家比较熟悉的即时通讯(IM)场景,直播间内聊天和群聊,二者有相似性,但也有本质的区别。
对比二者的特点,直播消息与 IM 群聊主要有以下区别:
1)参与人数不同:IM 群聊的参与人数上千人就是很大的群了。但对于高热度的大型直播场景,例如国庆、阅兵、春晚等,单直播间累计用户是百万甚至千万量级的集合,同时在线人数可达数百万人。
2)组织关系不同:IM 用户进群退群,是相对低频的操作,用户集合相对固定,用户进出的变更频度不会特别高。而用户进出直播间,是非常频繁的,高热度直播的单直播间每秒面临上万用户的进出变更。
3)持续时间不同:IM 群聊建立后,聊天持续时间可能比较长,几天到数月都有。而直播间大部分持续不超过几个小时。
4、核心技术挑战
根据上节中,直播消息和 IM 通聊的类比分析,针对直播中的消息系统,我们可以提炼出两个核心技术挑战。
挑战一:直播间内用户的维护
1)单直播间每秒上万用户的进出变更(实际进入直播间峰值不超过 2 万 QPS,退出也不超过 2 万 QPS);2)单直播间同时数百万用户在线;3)单直播间累计用户达千万量级。支持在线百万、累积千万两个集合,每秒 4 万 QPS 更新,有一定压力,但有支持高读写性能的存储应该可以解决,例如 redis。
挑战二:百万在线用户的消息下发
面对百万在线用户,上下行都有大量的消息,从直播用户端视角分析:
1)消息的实时性:如果消息服务端做简单消峰处理,峰值消息的堆积,会造成整体消息延时增大,且延时可能产生很大的累积效应,消息与直播视频流在时间线上产生很大的偏差,影响用户观看直播时互动的实时性;2)端体验和性能:端展示各类用户聊天和系统消息,一般一屏不超过 10-20 条。如果每秒有超过 20 条的消息下发,端上展示的消息基本会持续刷屏。再考虑到有礼物消息的特效等,大量的消息,对端的处理和展示,带来持续高负荷。所以,对于一个长时间观看直播的用户端来说,如果出现持续的大量消息,端的消息消费会有显著的性能压力,且过多消息会有累积效应。由于技术挑战一不难解决,以下内容主要讨论技术挑战二。
5、技术设计目标
综合考虑上节的技术挑战和直播业务场景,我们对于消息系统的需求目标有比较明显的指标定义。
技术设计目标定义大致如下:
1)实时性方面:端和端的消息要达到秒级;2)性能方面:消息服务能支持同一直播间内百万以上用户同时在线下发;3)峰值处理:对于峰值时的过多消息,丢弃是合理适当的处理方式;4)基于合理的端用户体验,单直播间内每秒消息数假设不超过 N 条。现在:问题的核心是,如何做到把不超过 N 条的消息,在 S 秒内,下发到直播间内的百万用户(假设 N<=20,S<=2)。
6、从普通 IM 群聊的技术实现上找灵感
6.1 普通 IM 群聊消息收发分析 IM 群聊数据流及压力点:
如上图所示,首先具体分析一下普通群聊的消息收发流程:
1)对于群 group-1,分配一个群公共消息信箱 group-mbox-1;2)群 group-1 内的用户 user-1,由手机端 APP-1 上发出消息 msg-1;3)服务端接收到消息 msg-1,检查 user-1 是否有权限,如有权限,将 msg-1 存储到群信箱 group-mbox-1,生成相应 msgID-1;4)服务端查询 group-1 对应的用户列表 groupUserList-1;5)基于 groupUserList-1 拆分出所有独立群用户:user-1、user-2 ... user-n;6)对于每一个用户 user-i 来说,需要查询用户 user-i 的所在设备 device-i-1、device-i-2、device-i-m(因为一个账号可能登录多个设备);7)对于每个设备 device-i-j 来说,长连接通道都会建立一个独立的长连接 connect-j 以服务于该设备;但由于 connect-j 是由端上 APP-1 连接到长连接服务的,具有动态性,所以,查询 device-i-j 与 connect-j 的对应关系时,需要依赖一个路由服务 route 来完成查询;8)在查得 connect-j 后,可以通过 connect-j 下发 msg-1 的通知 groupmsg-notify-1;9)如果用户 user-i 正在使用 device-i-j 的手机端 APP-1,用户 user-i 就可以立即从长连接 connect-j 上收到 msg-1 的通知 groupmsg-notify-1;10)在接收到 groupmsg-notify-1 后,手机端 APP-1 中的消息 SDK 根据端本地历史消息记录的最后一条消息 latestMsg 对应的消息 ID 即 latestMsgID,来向服务端发起拉消息请求 fetchMsg,拉取 group-1 中从 latestMsgID+1 到最新的所有消息;11)服务端收到拉消息请求 fetchMsg 后,从 group-mbox-1 中取出 latestMsgID+1 到最新的所有消息,返回给端;如果消息过多,可能需要端分页拉取;12)端 APP-1 拉取到 group-1 中从 latestMsgID+1 到最新的所有消息,可以做展示;在用户在会话中阅读后,需要设置所有新消息的已读状态或者会话已读状态。6.2 普通 IM 群聊主要压力如果完全重用普通群聊消息的下发通知到端拉取的全过程,对于 user-1 发的一条消息 msg-1,如果需要支持一个实时百万量级的群消息,大概有以下几个每秒百万量级的挑战。
首先:秒级拆分出用户列表 groupUserList-1,需要秒级读出百万的用户列表数据,对于存储和服务是第一个百万级挑战。
第二:对于拆分出群中的所有独立用户 user-i,需要秒级查询出百万量级的 device-i-j,对于存储和服务是第二个百万级挑战。
第三:对于所有 device-i-j,通过动态路由服务 route,需要秒级查询出百万量级的 connect-j,对于存储和服务是第三个百万级挑战。
第四:对于通过长连接 connect-j 下发时,需要支持秒级下发百万量级的群消息通知 groupmsg-notify-1 到对应的 connect-j 上,对于长连接服务是个百万级的挑战。
第五:对于收到消息通知的所有端 APP-1,需要支持百万 QPS 端从服务端拉取消息请求 fetchMsg,对于消息信箱服务,这是也是一个百万量级的挑战;考虑到实际各端 latestMsgID 可能不同,可能的优化方式会更复杂一些,带来的性能影响会更大。
第六:如果在绝大多数用户是在线聊天的场景,设置已读状态也会有百万量级 QPS 对服务端的压力。
显然:完全重用群聊的消息流程,对消息服务和长连接服务带来的压力是巨大的。
6.3 普通 IM 群聊优化方案 IM 群聊数据流优化后的压力点:
如上图所示,现在我们来分析以上每个百万量级的挑战,是否有优化的空间:
1)对于①拆分用户列表和②查询用户对应设备,如果存储上将二者合并集中起来,也就是优化直播间内用户列表的存储,扩展设备信息,可以减少一次 user->device 的百万 QPS 查询,可以优化;2)对于④下行通知和⑤端拉取 fetchMsg 的可靠消息拉取模式,考虑到直播消息允许部分折损丢弃,可以只做单向消息下发,而不做拉取,对于大部分连接保持在线的用户,也是可以接受的。所以可以优化,只保留下行通知(包含消息体),而舍弃端拉取;3)对于⑥消息设置已读,直播场景下可以考虑简化舍弃。如上优化后,减少了②⑤⑥三个百万量级压力请求,但还有①拆分用户列表③动态路由查询④长连接下发,这三个百万量级步骤需要处理。
对于①拆分用户列表:支持百万量级用户列表查询,比较常规的思路是支持基于群 groupID 的批量查询,例如一次可以查出 100 个用户,1 万 QPS 查询就可以支持到百万;基于群 groupID 把用户数据的存储,分散到多个主从实例和分片上,控制好打散粒度不出现热点,基本能做到,只是存储资源可能消耗较多。
对于③动态路由查询:表面上看,面临的问题与①类似,但却有些不同。因为群的用户列表,是基于群 groupID 做 key,建立一个表或多个打散的表;而 device-i-j 的查询是完全分散的,也是需要批量查询能力,但是完全分散的设备信息查询,不能只针对特定 key 做优化,需要动态路由服务支持整体上达到百万 QPS 的查询性能。
对于④长连接服务下发:由于长连接服务不依赖外部的存储服务,如果整体要支持百万量级的下发能力,若长连接单实例能支持 1 万的下发能力,整体上 100 个实例就能支持到百万量级下发。
基于以上分析:支持百万量级的消息下发,初见曙光。似乎只要优化好用户列表、动态路由的存储/查询和长连接的容量扩容,但所有的前提是需要消耗大量存储和机器资源。
考虑到直播业务的实际情况,现实不容乐观:
1)一方面,平时没有热点直播时,可能单场直播并发在线用户数峰值不超过 1 万人,甚至不到 1000;在业务初期,整体直播在线用户峰值可能也不超过 10 万。这就意味着,为了支持百万量级的峰值,资源整体上有几十倍的冗余;2)另一方面,如果突然来了一场热度非常高的直播,可能需要支持的不只是 100 万量级消息下发,可能是 500 万以上的量级(例如国庆阅兵、春晚等)。这样的话,每次大型直播得提前预估可能的在线用户峰值,如果超过当前设计容量,需要对①用户列表③动态路由查询④长连接服务,分别扩容和压测;或者在可接受的情况下,做服务降级或拒绝服务。而实际上:在线用户峰值量级很难估计准确,这样会造成实际资源利用率很低,扩缩容的操作频繁,运维成本高。是否选择这个方案,也是很令人纠结。
6.4 普通群聊多群组方案也有人提过拆分多个群组的方案。
例如:如果一个群组最多支持 1 万用户,开 100 个群就可以支持一百万用户;再建立一个虚拟群,将这 100 个群关联起来,似乎可行。
但如果仔细分析,会发现以上提到的几个问题:“①拆分用户列表、③动态路由查询、④长连接下发”,高压力依然存在,还是不可避免。
除此之外,多群组还会引入其他问题:
1)问题一:多群组消息不同步。如果两个用户在一起看直播,而所属群不同,看到的消息会完全不同;2)问题二:直播场景用户是动态进出的,也就是说群组成员非常不稳定,在线用户峰值波动也比较大。如果是根据在线人数增长,动态新开群组,可能第一个群用户已经很多了,第二个群刚开始用户比较少;或者,在峰值期间开了比较多的群,随着热度降低用户离开,用户变得分散,一些群的用户可能较稀少,聊天互动较少,这时需要缩容合并群。如何平衡多个群的用户,达到好的业务效果,也是比较难做的。基于以上分析,我们并没有选择多群组方案。
7、基于组播 mcast 方案的消息架构实践
经过上节中类比普通 IM 群聊消息的架构设计,本节将介绍我们支持实时高并发百万量级同时在线用户的直播消息架构——组播 mcast 方案的提出及演化。
7.1 跳出原有框架思考是否要采用上节基于 IM 群聊的优化方案,还是可以另辟蹊径?
先暂时抛开群收发消息流程:对于消息下发来说,如果一定要说一个步骤是必不可少的,那一定是长连接下发这步了。没有通过长连接下发,消息就无法最终到达用户。
当然有人说轮询拉取也可以替代长连接下发,来获取消息,但显然轮询拉取的性能压力和实时性与长连接下发相比差很多,故不在讨论范围。
如果能简化为:给长连接服务下发消息时指定一个类似的 groupID,长连接服务能直接拆分到所有群组用户相关的长连接 connect-j,就可以省略掉用户列表拆分和动态路由查询的百万量级查询。
这样的话:消息下发的压力将主要由长连接服务来承受,服务端也不需要对多个系统扩容,直播消息的优化可能会大为简化。
根据这个思路:相当于在长连接服务中,对连接 connect 也建立群组的概念。基于连接组的设想,我们设计了一套长连接的组播 mcast 机制。
7.2 长连接组播 mcast 基本概念基本概念总结如下:
1)每个长连接组播 mcast 有全局唯一的标识 mcastID;2)长连接组播 mcast 支持创建、删除、修改、查询等管理操作;3)长连接组播 mcast 是若干长连接在线用户的连接 connect 的集合;4)一个用户 user-i 在设备 device-i-j 上,对于特定应用 APP-k 来说,建立唯一的一个长连接 connect-j-k(此处暂时不区别登录用户和非登录用户);5)长连接组播 mcast 与组内长连接 connect-j-k 的关系维护,不需要额外的独立存储,是维护在每个长连接服务的实例上。7.3 长连接组播 mcast 的路由概念组播 mcast-m 的路由 route-m,是一个长连接服务实例的集合 LcsList,记录了所有加入 mcast-m 的长连接 connect-i 所在长连接服务实例 lcs-j。
7.4 长连接组播 mcast 路由的记录维护加入组播 mcast 的逻辑流程:
1)客户端调用消息 sdk 加入 mcast-m;2)消息 sdk 通过长连接,发出上行请求 mcastJoin(mcast-m);3)业务层收到来自长连接实例 lcs-i 上的连接 connect-i 的 mcastJoin 请求,校验 mcast-m 的合法性;4)业务层请求路由层建立基于组播 mcast-m 的组播路由 mcastRoute-m,将长连接实例 lcs-i 加入组播路由 mcastRoute-m 中;5)业务层请求长连接服务层,请求 mcastJoin 所在长连接实例 lcs-i,将请求所在连接 connect-i 加入到 mcastConnectList-m 中。离开组播 mcast,与加入组播 mcast 基本类似,由客户端调用消息 sdk 离开 mcast-m,发出上行请求 mcastLeave(mcast-m),长连接服务端更新路由和 mcastConnectList-m 信息。
7.5 组播 mcast 消息推送组播 mcast 数据流及压力点:
基于组播 mcast 的长连接消息推送过程,是一个 1:M * 1:N 的扩散放大过程。
具体过程描述如下:
1)一条消息 msg-1 推送,目的地是 ID 为 mcast-m 组播;2)后端业务模块根据目的 mcast-m,做一致性 hash 选择出 mcast 路由分发模块实例 mcastRouter- i,发送 msg-1 到 mcastRouter-i;3)mcast 分发路由模块实例 mcastRouter-i,根据 mcast-m 的组播路由 mcastRoute-m,查找所对应的接入实例路由记录列表 mcastLcsList-m,拆分出 mcast-m 所有的长连接接入实例 lcs-1..lcs-M,分别并发发送 msg-1 到长连接实例上;4)一个长连接服务实例 lcs-j,收到消息 msg-1 推送后,根据组播 mcast-m 查找组播连接列表 mcastConnectList-m,查出 mcast-m 内所有的连接 connect-m-1..connect-m-N,并发推送 msg-1 到消息客户端 sdk-m-1..sdk-m-N;5)消息客户端 sdk-m-o 收到 msg-1 后,递交给上层业务(例如直播 sdk)。7.6 组播 mcast 机制的性能评估现在分析一下以上的组播 mcast 机制的性能压力:
1)组播 mcast 的路由维护,主要压力在于 mcastJoin 和 mcastLeave,而 Join 的量级峰值请求很难超过 2 万 qps;访问压力比百万低两个数量级;2)组播 mcast 的消息推送流程,在一级路由 mcastRoute 拆分到长连接实例时,一般在几十到百量级,成本很低;3)组播 mcast 在长连接单实例内的消息推送,是单进程内的多连接并发发送,经优化后线上实测,在单实例保持 25W 长连接的情况下,单实例压测可达 8Wqps 的 mcast 稳定下发,保守按 5Wqps 容量评估;多个长连接实例间,是完全的并发,可以较容易的水平扩容。综上可知:对于 100Wqps 的下发,20 个长连接实例就可以完全负荷(20*5W=100W),且有一定裕量。如果 500Wqps 的下发,也不超过 100 实例;1000W 的下发,如果以 8W 单实例较大的负荷承载,125 实例就可以支持。
看上去,基于以上组播 mcast 机制,我们建立了一套高效的支持百万量级 QPS 的长连接下发机制,当前长连接服务的容量就可以支持,基本不用扩容。但是否能完全满足直播业务场景需求,还需要进一步讨论。
7.7 消息峰值问题对于每秒 1 条消息,扩散到 100W 用户,甚至 500W 用户,以上组播 mcast 机制似乎都能应对。
但直播间内消息的实际情况是:热门的直播每秒用户上行聊天消息会有很多,除聊天消息外,直播间还有人数、进场、点赞、分享等定期和不定期发送的很多种类系统消息。
如果假设每秒峰值有 100 条各类消息:100W*100=1 亿,简单按单实例 5Wqps 算,需要 2000 个实例才能支持,虽然比老的群聊系统应该好很多,但系统还是遇到大量资源冗余或应对峰值需要大量扩容的老问题。是否能有更好的解决方式?
这里我们考虑常见的一个优化思路,是通过批量聚合的模式来提高系统性能。
如果将这 100 条消息每秒聚合打包一次来统一下发,QPS 还是 100W,长连接系统的下发 QPS 不变,但每秒下发消息量级可以达到 1 亿,这个聚合方案实测是可行的。
聚合模式,我们付出的成本是消息时延的上升,1 秒的聚合平均时延增加 500ms,用户体验损失不算大,但系统下发消息量级可以提升百倍,综合评估成本收益来看是合理的。考虑到直播的实际场景,大多数场景下秒级的聚合和时延是可以接受的。
7.8 消息带宽问题如上节所分析的,聚合延时下发,长连接单实例 QPS 问题解决了,随之而来的是,长连接单实例下发的带宽压力问题。
例如:长连接单实例需要下发 10000 长连接时,每秒 100 消息,消息平均 2K 字节,实际带宽为 2K10010000*8=15625Mbps,这已经超过单物理机的万兆网卡的带宽容量。
另一方面:从全局带宽来看,也高达 1.5Tbps,带宽资源对于机房出口也会带来压力,这样的带宽成本过高,需要削减带宽使用或有更好的替代方案。
面对下发数据量带宽消耗过大的问题,在不改动业务数据的前提下,我们采用了数据压缩的解决方案。
而压缩是 CPU 密集型的操作,由于直播业务的实时性,不能简单考虑压缩比,在综合平衡压缩比、压缩时延和压缩 CPU 消耗后,调优压缩库后实测的平均压缩比达到 6.7 : 1,数据量压缩到原来的 15%左右,这样 15625Mbps*15%=2344Mbps=2.29Gbps。单机万兆网卡的带宽容量,最多承载 4.27 万的长连接下发,虽然没有达到 5 万,基本也可以接受。
从全局带宽来看,峰值也削减到不超过 230Gbps,收益很明显。
7.9 客户端性能问题进一步考虑,直播场景下,不仅是有较高的峰值消息量级,而是在直播过程中有持续的高消息量级压力。这不仅对于服务端是压力,对于客户端来说也是个挑战。
持续的高消息量级:
1)一方面客户端在接收、展示等方面有明显的压力;2)另一方面直播界面上过多过快的消息刷新,对于用户体验也是有害无益的。所以:在综合平衡用户体验和客户端性能的基础上,消息服务端增加了结合消息优先级的分级频控限速机制,单用户客户端并不需要承受每秒 100 条的压力,削减每秒下发消息后,长连接单实例每秒下发 5-8 万长连接,CPU 和带宽都是可以稳定支持的。
7.10 实时消息问题我们提供了基于消息优先级的实时下发机制:
1)对于高优消息可以立即触发聚合下发,不会增加聚合延时;2)而对于普通中低优消息,还是做延时聚合下发。7.11 用户在线问题组播 mcast 机制的出发点,在百万量级高并发在线的场景下,保障在线用户的消息到达,允许不在线用户接收消息的部分折损,付出合理的技术复杂度和成本,取得服务质量和性能平衡。
而针对在线用户的消息到达,还有个关键问题是如何保障用户的长连接在线。
为了提升长连接服务的接入稳定性和可达性,我们在以下几个方面做了优化。
1)访问点:
长连接服务在国内三大运营商的华北华东华南区域均部署了接入点入口。针对有部分国外用户的直播场景,还增加了香港机房的独立接入点入口。
2)HTTPDNS:
针对部分用户的 DNS 劫持问题和解析错误问题,消息 SDK 接入了 HTTPDNS 服务并优化本地缓存,形成多级域名解析保障体系,提升了域名解析的可靠性,减少了 DNS 劫持和错误率(见《百度 APP 移动端网络深度优化实践分享(一):DNS 优化篇》)。
3)心跳优化:
长连接的心跳是保活探活的重要手段,针对直播场景实时性高的特点,为了尽快发现长连接断链,在组播 mcastJoin 后,长连接心跳也调整为间隔更短、服务端动态可控的智能心跳。
这样在及时发现连接异常后,消息 SDK 可以快速主动重新建连。
4)断链恢复:
在直播间用户已加入组播 mcast 的情况下,如果长连接断链,长连接服务端会主动或被动的触发清除组播 mcast 成员。
而长连接重建连恢复时,直播业务层也需要监听连接恢复信号,重新加入组播 mcast,以恢复组播 mcast 的消息通路。
7.12 小结一下综上所述,组播 mcast 机制:
1)有效的解决了百万量级同时在线用户的消息实时下发问题;2)对于短时断链和消息过多,允许部分消息的丢弃;3)满足了直播场景消息的设计目标。组播 mcast 机制特点是:
1)消息服务和路由层压力较轻,整体压力只由长连接层承载,易于水平扩容;2)基于延时聚合下发,辅以压缩限速,可以很好的解决下行 QPS 与带宽的性能问题;3)系统整体下行的 QPS 和带宽是完全可控的。100W 在线用户的下行最大 QPS 是 100W,500W 在线用户的下行最大 QPS 是 500W。单实例的下发能力 5-8 万 QPS 是稳定的。因此,可以很容易判断整体的系统容量,特殊场景是否需要扩容;4)mcast 机制虽然是针对直播场景提出的,但本身设计具有通用性,可以应用于其他需要实时在线大量用户分组的消息推送场景。
8、基于组播 mcast 方案消息架构的进一步拓展
在组播 mcast 机制解决了百万量级的在线用户实时消息下发后,直播消息的场景不断扩大,不断有直播创新业务提出新的消息需求。
相应的,组播 mcast 的服务机制也需要与时俱进,不断在深度和广度上拓展优化。以下重点介绍一下历史消息和礼物消息。
8.1 直播间历史消息的支持对于刚进入直播间的用户来说,需要看到一些最近的聊天记录,以增强聊天互动氛围并帮助了解直播的进展;对历史聊天记录感兴趣额用户,还可以追溯更多的消息历史。这就产生了聊天历史的需求。
为了支持这类历史消息的需求,拓展方案是对于每个组播 mcast 申请开通一个组播公共消息信箱 mcast-mbox 服务。
逻辑是这样的:
1)对于用户消息和其他有持久化需要的消息,全部写入这个消息信箱;2)用户可以指定组播 mcastID,按时间区间和要拉取得消息条数,来获取组播 mcast 的历史消息。下面补充说明一下消息信息的概念和应用。
什么是消息信箱服务的概念?
1)消息信箱内的一条消息 msg,有唯一的消息标识符 msgID;2)一条消息 msg,还包括有发送方信息、接收方信息、消息类型、消息内容等字段,此处可以暂时忽略;3)每条消息可以设置过期时间,消息过期后不能访问到;4)每条消息可以设置已读状态;5)一个消息信箱 mbox,有唯一的信箱标识符 mboxID;6)一个消息信箱 mbox 是一个容器,存储有序的消息列表 msgList;消息列表 msgList 按 msgID 排序的;7)消息信箱服务,对指定信箱 mbox 支持单条消息或批量消息的写入;8)消息信箱服务,对指定信箱 mbox 支持基于 msgID 的单条消息或批量消息的查找;9)消息信箱服务,对指定信息 mbox 支持从 msgID-begin 到 msgID-end 的范围查找。实际上,最常用的就是基于 msgid 范围的消息拉取。这里的消息信箱服务是时间线 timeline 模型,有兴趣的同学可以进一步参考时间线 timeline 模型的相关信息(见《现代 IM 系统中聊天消息的同步和存储方案探讨》一文中的“4、Timeline 模型”一节)。
8.2 直播间礼物消息的支持礼物消息:
礼物消息场景分析:
1)用户送礼给主播,主播侧需要尽快、可靠地收到礼物消息通知,才能及时的给予用户反馈;2)送出礼物的用户,本地就可及时展示礼物效果,无消息通知强诉求;3)直播间内其他用户,需要收到礼物消息,以展示礼物效果,提升直播间互动氛围,激发其他用户送礼;4)礼物消息涉及用户订单和购买行为,需要由服务端确认发出;5)礼物消息优先级明显高于其他聊天消息、系统消息。基于以上分析,直播消息提出以下技术拓展方案:
1)增加一个独立的可靠消息组播 mcast 通道(如图 4 中组播 mcast-2),专供高优可靠消息的收发;与其他普通消息、系统消息在数据流层面隔离,减少相互干扰;2)对于普通用户侧的端消息 SDK,礼物消息组播 mcast 通道虽然是新增独立通道,消息收发逻辑与普通消息组播 mcast 通道保持一致;3)对于主播侧,端消息 SDK 对于礼物消息组播 mcast 通道,需要支持推拉结合模式,以保障礼物消息的全部到达;即使有短暂的掉线,也需要取到全部礼物消息;4)对于主播侧,在极端情况下,如果长连接建连有异常,消息 SDK 可以通过短连接接口轮询,来拉取礼物组播 mcast 信箱消息来兜底。基于以上独立的可靠消息组播 mcast 通道方案,在未剔除一些异常场景的情况下,如主播下线未关播、数据偶发打点丢失等,礼物消息的触达率已达到 99.9%以上。
8.3 直播消息其他方面的发展在百度直播的发展历程中,直播消息服务还面临着许多其他基础性问题和创新业务带来的其他挑战。
现在这些问题都有了较好的解决方案,以下列举一些,供大家学习参考:
1)如何支持多种客户端场景,安卓、iOS、H5、小程序、PC;2)如何支持同一场直播的消息在百度 APP 和好看、全民、贴吧等矩阵 APP 的打通;3)如何支持非登录用户:IM 一般是支持登录用户,而直播场景也需要支持非登录用户;4)长连接服务如果出了严重问题,是否有端获取消息的降级通道;5)直播消息审核的机审人审如何做,如何支持先发后审和先审后发;6)如何支持跨多个直播间的消息;7)直播消息服务是如何支持创新业务的,如答题直播、直播带货、直播连麦等。限于篇幅,以上问题在此不再做具体讨论,有兴趣同学欢迎探讨。
9、回顾和展望
自百度直播上线以来几年间,直播消息服务迎难而上,一路披荆斩棘为百度直播保驾护航,为百度直播提供了坚实的技术支撑和保障。
未来,在支持直播创新业务、更细粒度的消息分级服务、直播消息基础服务的稳定性和性能等方面,直播消息服务会继续努力,夯实基础,持续创新,以支持直播业务更好更快的发展。
附录:更多相关文章
[1] IM 群聊方面的文章:
《快速裂变:见证微信强大后台架构从 0 到 1 的演进历程(一)》
《如何保证 IM 实时消息的“时序性”与“一致性”?》
《IM 单聊和群聊中的在线状态同步应该用“推”还是“拉”?》
《IM 群聊消息如此复杂,如何保证不丢不重?》
《微信后台团队:微信后台异步消息队列的优化升级实践分享》
《移动端 IM 中大规模群消息的推送如何保证效率、实时性?》
《现代 IM 系统中聊天消息的同步和存储方案探讨》
《关于 IM 即时通讯群聊消息的乱序问题讨论》
《IM 群聊消息的已读回执功能该怎么实现?》
《IM 群聊消息究竟是存 1 份(即扩散读)还是存多份(即扩散写)?》
《一套高可用、易伸缩、高并发的 IM 群聊、单聊架构方案设计实践》
《[技术脑洞] 如果把 14 亿中国人拉到一个微信群里技术上能实现吗?》
《IM 群聊机制,除了循环去发消息还有什么方式?如何优化?》
《网易云信技术分享:IM 中的万人群聊技术方案实践总结》
《阿里钉钉技术分享:企业级 IM 王者——钉钉在后端架构上的过人之处》
《IM 群聊消息的已读未读功能在存储空间方面的实现思路探讨》
[2] 更多直播技术的文章:
《移动端实时音视频直播技术详解(一):开篇》
《移动端实时音视频直播技术详解(二):采集》
《移动端实时音视频直播技术详解(三):处理》
《移动端实时音视频直播技术详解(四):编码和封装》
《移动端实时音视频直播技术详解(五):推流和传输》
《移动端实时音视频直播技术详解(六):延迟优化》
《理论联系实际:实现一个简单地基于 html]5 的实时视频直播》
《实时视频直播客户端技术盘点:Native、html]5、WebRTC、微信小程序》
《Android 直播入门实践:动手搭建一套简单的直播系统》
《淘宝直播技术干货:高清、低延时的实时视频直播技术解密》
《技术干货:实时视频直播首屏耗时 400ms 内的优化实践》
《新浪微博技术分享:微博实时直播答题的百万高并发架构实践》
《实时音频的混音在视频直播中的技术原理和实践总结》
《七牛云技术分享:使用 QUIC 协议实现实时视频直播 0 卡顿!》
《近期大热的实时直播答题系统的实现思路与技术难点分享》
《P2P 技术如何将实时视频直播带宽降低 75%?》
《网易云信实时视频直播在 TCP 数据传输层的一些优化思路》
《首次披露:快手是如何做到百万观众同场看直播仍能秒开且不卡顿的?》
《浅谈实时音视频直播中直接影响用户体验的几项关键技术指标》
《技术揭秘:支持百万级粉丝互动的 Facebook 实时视频直播》
《移动端实时视频直播技术实践:如何做到实时秒开、流畅不卡》
《实现延迟低于 500 毫秒的 1080P 实时音视频直播的实践分享》
《浅谈开发实时视频直播平台的技术要点》
《海量实时消息的视频直播系统架构演进之路(视频+PPT)[附件下载]》
《YY 直播在移动弱网环境下的深度优化实践分享(视频+PPT)[附件下载]》
《从 0 到 1:万人在线的实时音视频直播技术实践分享(视频+PPT) [附件下载]》
《在线音视频直播室服务端架构最佳实践(视频+PPT) [附件下载]》
本文已同步发布于“即时通讯技术圈”公众号。
同步发布链接是:http://www.52im.net/thread-3515-1-1.html,原文链接:点此进入
评论