引言
在当下的直播业务中,实时音视频交互已经变成主播与主播,主播与用户之间的主要交流模式。
为了满足用户间互动的需求,B站提供了多种实时互动类产品,比如:语音聊天室,连麦连线,视频PK等功能。
但长期以来因为业务与技术快速发展,团队组织不停变革,系统技术债务不断积累等原因,导致不同互动业务间普遍存在能力重复建设,数据孤立等问题。
同时现有的技术架构已经无法满足我们的需求,作为互动业务负责团队,我们希望通过对互动中心进行平台化架构升级,来融合各种互动业务,降低系统复杂度同时提升系统性能。
以此提高交付效率来更好适应需求变化。
互动业务是什么
我们先了解下B站直播场景下主要的互动业务:
以最典型的是连线业务举例。
视频连线功能允许主播与观众或其他特邀嘉宾之间进行实时视频通话。
主播可以邀请观众或特定用户加入直播,他们的视频画面将以画中画的形式呈现在直播中,与主播进行面对面的互动。
在这个过程中,主播之间通过表演竞争等方式获得观众的礼物打赏。
通过这种功能增强观众的参与感,提升直播的互动性和娱乐性。
互动业务典型架构
介绍了这种互动业务的玩法,接下来我们了解下技术实现:
两个主播通过 RTC 进行视频连线,然后通过各自的开播软件合流后推到 视频云CDN,用于给各自直播间的观众进行直播。
上图为典型的直播场景下互动业务整体架构图,包括直播平面与互动平面2个部分.
推拉流与RTC是两种不同的通信技术,但在直播场景下存在关联和交叉应用。
RTC:在直播场景中,RTC技术负责实时音视频流的接入和处理,以满足参与互动间用户超低延时音视频互动能力。通过RTC技术,主播可以与观众进行实时的音视频通信,实现直播互动,例如观众可以通过语音、视频主播进行即时交流。
推拉流:在直播中,推流是指主播通过开播软件将自己的音视频数据通过网络上传到直播平台,而拉流则是指观众从直播平台获取主播的音视频数据进行播放。以满足观众侧弱互动性、高并发、低成本的直播观看能力。
互动中心是什么
我们接手互动业务时,互动类业务已经迭代了6-7年,历经多个负责人和团队的变更和多次技术架构迭代.
演变为了如今复杂的微服务体系,代码分布在7-8个业务服务中.服务端代码包括php,go等多种语言.同时客户端与rtc对接都是根据业务代码定制.
随着时间迭代,历史债不断积累,性能劣化也需要治理
以下是存在的一些挑战和问题.
重复建设: 不同业务分别迭代,没有抽象出共性功能,导致数据孤岛,重复开发.
技术陈旧:随着时间的推移,技术环境和标准可能已经发生了重大变化,项目所使用的技术可能已经过时或不再被广泛支持。
缺乏文档和知识转移:在长期迭代的过程中,可能没有充分的文档记录和知识转移,导致项目的代码和架构理解变得困难。
低效的开发流程:长期迭代可能导致项目的开发流程变得冗长、混乱或不够高效。缺乏自动化测试、部署流程繁琐、代码质量不佳等问题
高并发和可扩展性问题:项目在过去的几年里没有进行过大规模的负载测试和优化,存在高并发和可扩展性方面的问题。随着用户数量的增长,可能会出现性能瓶颈、系统崩溃或响应时间延迟等问题。
技术债务和代码质量:长期迭代可能导致项目中存在大量的技术债务和低质量的代码,影响项目的可维护性和可扩展性。
面对这些问题,我们进行全面的梳理和评估,通过抽象共性问题, 建立通用能力.将这些共性能力整合为"互动中心"
并希望作为直播平面与互动平面之间的中间业务层.为直播互动业务提供通用的互动场次、互动连结能力等管理能力。
互动中心架构演进
基于这个目标并跟随业务迭代的节奏,我们大致分为二期来演进.
第一期解决通用的互动场次、连结的能力,将rtc与具体业务层抽象剥离,收益为业务不用关心rtc层的细节
第二期解决互动业务之间共性的UI渲染,流管理能力,将客户端与具体业务解耦,使一套通用的客户端代码动态适配多种互动业务.
1.0时期
共性功能
麦位管理
在多人互动的场景,每个用户有在房间中显示的位置;例如语聊房场景,主播固定在上方区域,用户分配在下方的8个小格;以及多人视频连线场景,当前房间主播固定位于左侧,其他连线的主播分配于右侧4个小格。
即使是在双人互动的场景,业务也有位置的要求,例如当前房间主播位于左侧,连线的主播位于右侧。
麦位不仅影响用户的视频或头像在观看端的位置,也可能具有特殊的业务含义,例如语聊房的厅内PK,即将语聊房的上麦用户分为左右侧,左侧和右侧的用户分别计分的玩法。
在语聊房等场景中,对用户上下麦、用户麦位的数据实时性要求较高。我们通过组合使用多个渠道,利用各自特点来平衡实时性、数据最终一致性与性能开销之间的矛盾。
基于长链接消息的全量状态同步。主动push(房间广播),延迟在毫秒级,但无法保证必达。
基于push的推拉结合方案,在长链接不稳定的情况下, 基于接口被动轮询,延迟在秒级,同时服务端性能开销大。(Info接口高峰 1K+ QPS)
针对性能开销大的问题,增加网关层内存缓存,汇聚相同房间的请求,减少透传到业务服务端的压力。
基于视频流里SEI,针对未登录用户,非重点保障场景等场景,使用视频流里SEI携带数据来进行同步,延迟是10秒级别但是性能开销非常小,作为最后的兜底。
客户端收到不同渠道来源的数据,基于数据的版本进行排序,避免消费数据时出现乱序。
计分系统
语聊房等互动业务有丰富的实时计分规则,除了一场互动中,每位参与用户收到的送礼/关注需要计算在互动期间的分数外,互动的不同阶段(例如抢帽子阶段、分组PK阶段)也会有更丰富的计分规则,例如分组分、麦位分,分数根据用户的上下麦也会有对应的影响。
在最初的业务实现时,我们依赖单一的消息队列实现计分,具有较高延迟(接近3s),影响用户体验,并且单一的链路缺少可靠性保障。为此我们重新设计了计分系统。
在新的系统中,营收事件会有同步和异步两条调用链路,计分相关的事件流水会落表存储;
实时链路保障分数计算的结果快速落缓存,同时有计算脚本根据存储的事件流水计算和对账。
角色管理
在不同的场景中,一场互动的参与者可能具有不同的身份,例如发起者(主播)、参与者(麦上用户)、管理员和观众。
不同身份具有不同的权限,例如对于语聊房来说,主播和管理员具有接受申请、邀请用户、踢人等操作的权限。
为此我们设计了基于RBAC模型的权限管理方案。
用户所属角色可根据互动场次的数据获取(例如发起者、参与者),也有落库存储和读写能力(例如房间管理员)。
用户可能关联多个角色,角色和权限的关系由系统定义。
局限性与问题
举个例子,产品希望能支持用户在双人连线场景时,邀请新的用户加入时自动切换到多人连线,但是现有技术实现无法支持
原因是在互动联结层面缺乏足够的通用性应,每个业务类似的功能都是重复开发 ,缺乏扩展性 不同模式无法组合使用,所以难以适应业务需求快速变化
这个问题使我们互动中心进一步进行迭代, 我们需要对互动连接层面做进一步抽象
2.0时期
通用联结管理
术语定义:
互动中心和 RTC 流媒体服务对接,在 RTC 的频道和会话基础上,有如下领域能力:
频道:直接和 RTC 的通讯通道对应,每个频道根据 channel_id 可以串联客户端、RTC服务(过去互动中心曾封装了自研和声网两套RTC服务,目前已全面切换到自研,当前已升级到自研的RTCV2版本)、业务服务端的通信上下文。互动中心还管理了频道成员的流水数据,包括用户进出频道的时间和会话信息。
场次:逻辑上的【一场互动】的概念,用来将多个用户圈在一个场次中开展业务(这里的场次和直播场次无关,一场直播可能发起多场互动场次),一般来说,场次和频道是对应的,但业务发展和扩展设计上,场次和频道不强耦合
互动中心提供了多人互动(如语聊房)和双人互动(如邀请PK)的通用能力,例如双人互动一方离开会自动结束,多人互动在最后一个人/创建者离开结束。
联结:场次中的具体用户,会话主要用于管理用户加入互动后的状态数据,以及状态流转,状态流转的控制由状态机管理(状态是单向流动的,例如只能从发起联结流转为建立连接中/取消联结/超时取消联结)。
联结的状态包括【发起联结】【取消联结】【超时取消联结】【建立连接中】【建立连接超时失败】【联结成功】【离开】【被关闭】和【结束】。
互动中心提供了邀请/申请、接受、拒绝的通用能力。
针对1.0存在的问题,我们将服务端和客户端的能力进行进一步组件化封装.
从服务端能力中提取出如下的概念:
场次管理:逻辑上的【一场互动】的概念 联结管理:场次中的具体用户,用于管理用户加入互动后的状态数据以及状态流转
频道管理:直接和 RTC 的通讯通道对应,每个频道根据 channel_id 串联客户端、RTC服务、业务服务端的通信上下文。统一数据模型:屏蔽不同业务的差异性
动态模板渲染
在这些不同玩法中, 虽然都基于通用的rtc互动能力,但各个玩法的UI布局都有很多区别.所以需要基于不同的玩法单独实现不同的布局样式.
不同的布局样式都需要不同平台的客户端,比如(ios,Android,web,pc)单独进行开发,
一方面需要大量的开发时间,另一方面改动成本比较高,还需要考虑到新老版本兼容的问题.
通过开发一种可配置的、自适应的UI布局系统,可以根据不同的玩法和用户需求下发不同的配置,从而达到动态调整和优化UI布局。
之前做麦位管理是抽象了每个格子是哪个人以及对应的状态,这次我们将一共多少个格子,每个格子对应的能力也进行抽象
同时为了能够支持我前面提到的如双人连线切换到多人连线的需求,那么我们势必就需要一套数学描述语言动态下发同步给客户端
我们通过json配置文件,根据业务场景动态计算动态下发来告诉客户端渲染UI界面所需的配置
同时通过将智能算法应用于UI布局系统,我们能根据用户的偏好和行为进行自动优化。
通过分析用户的交互数据和用户反馈,系统可以学习并适应不同用户的布局偏好,提供个性化的UI布局体验。
流状态控制
实现界面动态渲染后,下一步就是动态控制客户端与rtc推拉流的行为.
目前我们是基于客户端合流的方案,每个客户端在加入互动时,都需要注册到服务器,然后拉取频道内所有人的媒体数据.
一方面当频道内人数变多时,性能开销和带宽消耗都会逐渐变大,比如5个人进行互动,一共存在10路数据流.
另一方面,当我们的业务场景需要某些人不推流只拉流,某些人只推音频不推视频等这些业务场景时,动态推拉流控制就可以帮我们实现.
主播端使用WebRTC或其他实时通信技术,将音视频数据实时推送到媒体服务器。
推流的参数和行为可以根据网络状况和设备性能进行动态调整,包括码率、分辨率、帧率等。
整体架构图
当前已经接入的互动业务包括【语聊房】【视频PK】【多人连线】【视频连线】【连麦】【OGV观影房】等
互动中心提供了通用的事件处理能力,并处理对应的联结状态,向业务服务回调;包括处理RTC频道的加入/离开,以及自动检查和处理发起联结的超时状态和建立连接的超时状态。
同时互动中心提供了通用的业务互斥能力,例如用户正在互动中则不能发起新的互动。
互动中心具有对账和异常处理能力,例如检查 RTC 中的频道和会话数据是否和互动中心的存储一致。
互动的场次和联结数据、以及状态流转的数据入离线 Hive 库,可在观远平台分析。
同时通用的埋点和监控,例如互动在线用户数据、超时数据、RTC回调数据的监控告警。也能赋能业务,提高系统稳定性.
视频PK业务接入互动中心
经过前期我们对互动中心的沉淀,我们结合PK业务接入互动中心的例子,了解了当前技术架构带来的收益.
PK业务现状
如上图中所示
链路复杂:之前线上已有4种PK玩法的各种能力分别在不同服务和技术架构中实现了3-4遍,而且其中还涉及到一部分逻辑从PHP重构到Go,导致链路长系统复杂
过时的技术实现:互动建联逻辑也发生了2次大的变更,从声网sdk迁移到自研rtc,从客户端控制合流过程到服务端收拢.不同的PK玩法接入了互动中心不同层级的API能力.
数据孤岛:我们仅仅共用了PK主表(ap_pk_room),其余次要的表,广播消息,事件消息等都是分开实现的
同时PK业务做完直播场景下营收重要的工具,技术稳定性意味着业务稳定性,玩法不可用、状态延迟等都会引起极大的社区舆情、客诉反馈、商业化行为的损失。
架构分层
术语定义:
运营玩法层: 建立在PK玩法之上的运营活动.包括大乱斗,吃鸡赛,加倍玩法等活动,吸引更多的观众参与,提高平台的活跃度
PK层:负责管理PK的核心玩法,包括 开始,胜负,绝杀,惩罚规则等各个阶段的流转.同时负责PK匹配逻辑,这一层的设计直接影响到PK的公平性和观赏性
互动层: 最基础的层次,建立RTC层面的联结,处理直播PK的实时通信问题
接入互动中心
同时我们对架构长期演进目标达成了一致.我们期望在多人PK这一套架构上,通过组件化的方式抽象PK共用能力,然后通过多人PK的能力来覆盖邀请/随机/经典PK等业务,最后逐步移除老的代码.
具体的工作内容包含3部分:
1. 底层RTC联结部分统一以[多人连线能力]为基础,目前互动层有3种实现方式
a. pk服务端直接与rtc接口交互(随机PK)
b. 通过互动中心1.0 create channel接口与rtc交互 (邀请PK)
c. 通过互动中心2.0 universal [多人连线能力]与rtc交互 (多人PK,经典pk语音)
2. 运营玩法层重新组件化封装
a. 目前的运营玩法大都与PK业务绑定,导致同一个玩法的改动在不同的PK玩法上需要重复开发多遍b. 另外玩法的设计与实现都只考虑了1V1,不支持多人,多人场景下的逻辑需要重新梳理
3. PK层与新的玩法层,互动层对接
a. 我们将互动层与玩法层从PK业务中剥离后,PK层将变得更加精简,专注与PK流程本身b.长期来说,4中PK玩法可能会一直保持,同时也很难用一种通用的PK模型去描述4种PK流程,所以继续保持4种PK模型从ROI上可能更适合演进方向
统一数据
数据分散带来的一致性问题:
频道数据、interact 中维护的场次和连线记录、各个业务(视频PK,老多人连线/语聊房,双人连线,连麦)各自维护的场次和连线记录分散在 interact、biz、av 三个库,难以保障一致性;
数据不一致时有业务异常和客诉风险
统一状态机
通过多种业务共用状态机,将相同的业务逻辑抽象为可重用的状态机组件。避免为每个业务单独实现和维护状态机,从而节省开发和维护成本。
同时,当需要进行状态机的调整、bug修复或功能扩展时,只需在共用的状态机上进行修改,而不需要逐个业务进行修改。
无论是哪个业务,都会遵循相同的状态转换规则和错误处理逻辑,从而确保系统的稳定性和可靠性。
互动中心平台化挑战
性能问题
质量监控指标
系统可用性的关键在于首先建立客观事实的技术指标,先了解当前的可用性状态,才能进行针对性的优化
我们当前建立了如下等质量指标的监控
加入/离开连线相关
加入RTC成功率/超时数量/超时UV/超时率
加入RTC耗时
RTC推流成功率
邀请/申请触达率,邀请/申请超时数量/超时率
RTC与互动中心一致性检测
服务稳定性相关
互动操作 QPS、可用性
读接口 QPS、可用性
业务质量相关
分互动业务在线人数
前置检查成功率/失败原因/失败次数
RTC质量相关
RTC服务健康度/重连弹窗触发次数/重连调用次数/重连成功率
RTC推流质量/黑屏/卡顿检测
系统容量目标
按照当前约3倍预估需从下面几个维度的指标进行评估
实时互动场次
实时互动人数(已连线状态)
申请/邀请/连接中人数
峰值互动操作QPS
读操作QPS
压测接口
FastCreate (发起连线)
Invitation (邀请)
Apply (申请)
Handle (接受、拒绝)
RtcEvent/OnPeerChange(rtc状态回调)
UniversalInfo(获取互动信息)
压测JOB
CheckChannelStatusTask(检查频道状态)
CheckLinkTimeoutTask(检查连麦超时)
CheckUserRecordTimeoutTask(邀请/申请超时检查)
压测任务流
1)互动操作QPS的任务:
FastCreate(A邀请B)-> Handle(B接受)-> OnPeerChange(A加入)-> OnPeerChange(B加入)-> Apply(C申请)-> Handle(A同意C申请)-> OnPeerChange(C加入)-> Invitation(A邀请D)-> Handle(D接受)-> OnPeerChange(D加入)-> OnPeerChange(A离开)-> OnPeerChange(B离开)-> OnPeerChange(C离开)-> OnPeerChange(D离开)
2)读操作QPS的任务:
UniversalInfo 单接口任务
复杂系统治理
链路追踪
主播对于pk送礼加分很敏感,但这个链路涉及营收送礼,订单结算 ,PK业务 ,异步消息等多业务多时序多维度的流程,遇到具体问题排查不方便。
我们通过期望打通多业务模块之间的trace,提升解决问题效率
数据上报
通过在业务系统种埋入数据点
数据串联
通过建立「场景」- 「模块」 - 「关键节点」的概念
场景:聚焦 trace 范围,eg:pk、语聊房、送礼
模块:业务场景下的不同业务模块,eg:pk加分,pk连线等。
模块需要事先的「预定义」,预定义只关注「关键节点」,以满足「粗粒度进度」,重点是多业务模块衔接部分。
模块一定有「成功与否」的属性,模块链路的节点是否都完成,是否中间有错误出现。
节点:只关注「关键事件」,其他普通的事件可以通过 trace_id 串联并查询到。
关键节点一定有「成功与否」的属性,level是info、error才能反馈给模块整体是否完成。
数据检索
数据查询
问诊系统
在互动中心业务上线后,研发需要投入大量精力排查和解决客诉,由于系统的技术栈和业务单元丰富,每次定位问题需要各端大量人力处理。
为此我们建设了问诊台,聚合服务端、客户端、RTC等事件和业务数据,提供一站式的全链路追踪、观测、排障、监控和离线分析能力。
目前问诊台包括互动用户快查、互动巡检、互动状态快修、语聊房巡检、房间离线分析、在线业务大盘、关键事件监控、关键事件全链路查询等模块。
总结
开发一个好的平台关键还是看能否更好更简单的解决当下的问题和需求,但平台化和业务多样性又往往是矛盾的.
预先设计式的架构由于前期的输入不足,后期会难以适应需求的变化,而演进式的架构,由于需求的不确定性,随着系统的规模增大后期又会比较难以维护。
我们要为可以预见的未来设计,为系统预留扩展点,尽量保障系统低耦合高内聚,不要期待有一劳永逸的解决方案。
-End-
作者丨皮皮鸭
这是一个从 https://www.bilibili.com/read/cv38615651/ 下的原始话题分离的讨论话题