直播后台架构选型

超核直播后台架构选型过程

Posted by Ted on August 2, 2023

一、项目背景

【超核直播间】是一个提供给腾讯游戏管家与超 R 用户直播互动的平台。有以下主要功能:

  • 主播:主播是直播平台的核心,负责内容的创作和与观众的互动,包含主播的上下架管理、主播资料、主播直播信息、数据分析等功能
  • 直播:直播模块是平台的核心功能,提供实时视频流和互动体验。包含到直播推拉流、直播间聊天/弹幕等功能。
  • 券:券模块用于吸引用户消费和提高用户粘性。包含券资源管理,券上下架、玩家领券、玩家抢券等功能。
  • 商品:商品模块是直播平台的商业化部分,主播可以通过直播销售商品。包含商品资源管理、商品上下架、商品购买等功能
  • 积分:积分模块用于增强用户的参与感和忠诚度,包含积分获取、积分查询、积分排名、积分活动等功能。
  • 抽奖:抽奖模块用于增加用户的参与感和娱乐性,包含抽奖创建、抽奖参与、抽奖结果公布、奖品发放、抽奖统计分析等功能。
  • PK对战:PK对战用于增加玩家互动性,包含PK创建、规则设定、参与PK、PK实时更新、PK结果、历史与统计。
  • 其他功能:投票,公众号订阅。

平台面向的用户是300万超核玩家,单场直播在线人数同时最高1万左右,多场直播同时在线总计最高5万左右。

二、业界典型架构对比

2.1 传统三层架构:

传统三层架构的核心理念是分离关注点,通过分层来实现代码的模块化和可维护性。

分层结构

img

  • 接口表示层:用户与系统交互的界面,负责展示数据和接收用户输入,处理请求接口的参数以及简单的封装。
  • 业务逻辑层:负责处理业务规则和逻辑。接收来自表示层的请求,进行相应的处理,并将结果返回给表示层。
  • 数据访问层:层负责与数据库或其他数据存储进行交互,提供数据的持久化和检索功能。它将数据存储的细节与业务逻辑层隔离开来。
  • 基础基础层:基础结构层提供系统所需的基础设施服务,支持其他层的功能实现

架构流程

  1. 第一步考虑的是数据库设计,数据表如何建,表之间的关系如何设计;
  2. 第二步就是搭建数据访问层,如选一个ORM框架或者拼接SQL操作;
  3. 第三步就是业务逻辑的实现,由于我们先设计了数据库,我们整个的思考都会围绕着数据库,想着怎么写才能把数据正确地写入数据库中,这时CRUD的标准作法就出现了;
  4. 第四步表示层主要面向用户的输出。

优势:

  • 结构清晰,职责分明,易于理解和维护。三层各处理各自的事务,上层向下层引用接口与方法,下层向上层提供接口服务,各层之间调度方法时可能通过Model传值,也可以返回值Model。
  • 各层可以独立进行单元测试,便于发现和修复问题,提高软件质量。

劣势:

首先,为各个层面提供服务的“基础结构层”的职责比较紊乱,它可以是纯粹的技术框架,也可以包含或处理一定的业务逻辑,这样一来,业务逻辑层与“基础结构层”之间就会存在依赖关系;

其次,这种结构过分地突出了“数据访问”的地位,把“数据访问”与 “业务逻辑”放在了等同的地位,也就没有太多考虑面向对象,解耦的事情了,这样的代码对日常的维护自然是越来越困难的

试用场景:

  • 简单业务逻辑:三层架构适用于业务逻辑相对简单、系统功能明确的场景。
  • 快速开发:三层架构适合需要快速开发和交付的项目,因为其结构简单,容易实现。

2.2 DDD(领域驱动设计)

DDD的核心理念是将业务领域的复杂性作为设计的中心,通过领域模型来反映业务逻辑和规则,通过领域来驱动开发。DDD强调划分限界上下文,每个上下文内有独立的领域模型,避免不同上下文之间的概念冲突。

img

  • 领域层:先从业务逻辑入手开始,设计时不再考虑数据库的实现。将以前的业务逻辑层(BLL)拆分成了领域层和应用层。领域层聚焦业务对象的业务逻辑实现,体现现实世界业务的逻辑变化。它用来表达业务概念、业务状态和业务规则包含了业务所涉及的领域对象(实体、值对象)、领域服务以及它们之间的关系。这部分内容的具体表现形式就是领域模型(Domain Model)。领域驱动设计提倡富领域模型,即尽量将业务逻辑归属到领域对象上,实在无法归属的部分则以领域服务的形式进行定义。
  • 应用层:该层不包含任何领域逻辑,但它会对任务进行协调,是各聚合的协调和编排,并可以维护应用程序的状态,因此,它更注重流程性的东西。在某些领域驱动设计的实践中,也会将其称为“工作流层”。它以较粗粒度的封闭为前端接口提供支持。除了提供上层调用外,还可以包括事件和消息的订阅。
  • 表现层:跟三层里的表现层意思差不多,是对接口和交互的处理。
  • 基础结构层:基础设施层不涉及业务,是数据的出向接口,封装数据调用的技术细节。可为其它任意层提供服务,但为了解决耦合的问题采用了依赖倒置原则。其它层只依赖基础设施的接口,于具体实现进行分离。

领域对象

确定领域对象,通常为业务描述中的名词,这种方式是以对象驱动行为的发生,这种是最常见的一种方式。对象是行为能力的拥有者,也是行为能力的参与者。

  • 实体对象:具有唯一标识,能单独存在且可变化的对象
  • 值对象:不能单独存在或在逻辑层面单独存在无意义,且不可变化的对象
  • 聚合:多个对象的集合,对外是一个整体
  • 聚合根:聚合中可代表整个业务操作的实体对象,通过它提供对外访问操作,它维护聚合内部的数据一致性,它是聚合中对象的管理者

领域服务

领域服务是领域对象拥有的行为能力,它必须是以现实业务的角度去识别,不以技术或数据的角度去分析

  • 领域服务是对外可提供哪些服务,需要遵循现实业务的操作,这种服务的定义是粗粒度且高内聚的,不以程序逻辑或数据库逻辑来设计定义出增删改查。
  • 服务接口的定义,输入输出参数尽量考虑以对象的形式,充分兼容各种场景变化
  • 领域服务的实现主要关注逻辑实现,切勿包含技术基础类代码,比如缓存实现,数据库实现,远程调用等

领域边界:

领域边界的划分就是划分功能的实现范围,行为能力的归属,对象间的解耦,明确系统结构关系。划分的标准也是以现实业务对象为参考点。 每个领域相对独立,各自的作用、结构与地位也不一样,有核心域,支撑域,通用域等。各域间明确通讯方式,根据不同的使用场景,有同步的也有异步的,并确认通讯的标准。

优势

  • 增强业务和技术的对齐:DDD通过将重点放在核心业务领域和逻辑上,帮助开发团队更好地理解业务需求。这种方法鼓励使用业务领域的语言(通常称为“通用语言”或“Ubiquitous Language”)来定义所有的业务规则和流程,从而确保技术解决方案与业务目标紧密对齐。
  • 提高软件的灵活性和可维护性:DDD推动设计聚焦于领域模型,这使得软件架构更加模块化,每个模块(或称为领域)负责处理特定的业务逻辑。这种模块化的结构不仅有助于代码的重用,还使得系统更容易理解、维护和扩展。当业务需求发生变化时,可以更容易地对系统进行调整,而不会影响到其他不相关的部分。

劣势

  • 实现复杂性:DDD的实施通常比传统的软件开发方法更为复杂。它要求开发团队具有较高的设计技能和对业务领域深入的理解。此外,构建一个准确的领域模型需要大量的前期工作和持续的维护,这可能会增加项目的初期成本和时间。
  • 过度工程的风险:在某些情况下,尤其是在较小或较简单的项目中,采用DDD可能会导致过度工程。如果项目的复杂性不足以证明采用DDD所需的额外努力和资源,那么这种方法可能会导致不必要的复杂性和开发延迟。

适用场景

  • 复杂业务领域:当业务逻辑复杂且变化频繁时,DDD能够帮助团队更好地理解和应对这些复杂性。
  • 大型项目:在大型项目中,DDD的分层架构和领域模型能够提供良好的组织结构,便于团队协作。
  • 需要高可维护性的系统:当系统需要频繁更新和维护时,DDD的设计原则能够降低维护成本。

2.3 两个架构对比

设计焦点和目的

  • 传统三层架构:通常包括表示层(用户界面)、业务逻辑层和数据访问层。这种架构的主要目的是将应用程序分解为逻辑上的层,以便管理依赖关系和分离关注点,从而简化开发和维护。它主要关注于技术实现和层次分离,而不深入到业务规则或领域逻辑的细节。
  • 领域驱动设计(DDD):DDD关注于创建一个反映业务领域复杂性的丰富的领域模型。它强调的是深入理解业务领域,并将这种理解融入到软件设计中。DDD使用通用语言来桥接技术人员和非技术业务专家之间的沟通,确保软件紧密地与业务需求对齐。

模块化和组件划分

  • 传统三层架构:层与层之间的分界明确,每层负责特定的功能。表示层负责处理用户交互,业务逻辑层处理业务规则,数据访问层管理与数据源的交互。这种分层有助于开发和维护,但可能导致业务逻辑分散在多个层次中,从而难以管理复杂的业务规则。
  • 领域驱动设计(DDD):在DDD中,软件的划分基于业务领域的边界,形成多个领域模型或有界上下文(Bounded Contexts)。每个有界上下文内部可能包含多个层(如UI、应用层、领域层、基础设施层),但这些层都服务于同一个领域模型。这种方法更便于管理复杂的业务逻辑,并保持模型的内聚性。

适用性和复杂性管理

  • 传统三层架构:适用于多种类型的应用程序,特别是那些业务逻辑相对简单或标准化的项目。它的结构简单、直观,易于实现和维护,但可能在处理复杂的业务逻辑时显得力不从心。
  • 领域驱动设计(DDD):特别适合于业务规则复杂、业务逻辑深度与广度都很大的系统。DDD能够有效地管理复杂性,但其实施难度较高,需要团队具备较强的业务理解能力和设计能力。此外,DDD可能在项目初期增加额外的开发成本和时间。

业务和技术的对齐

  • 传统三层架构:虽然提供了技术层面的清晰结构,但可能缺乏与业务需求的深度对齐。业务规则可能被分散在多个层中,使得对业务逻辑的更改更加困难。
  • 领域驱动设计(DDD):强调与业务需求的紧密对齐,通过在设计和开发过程中使用通用语言和深入的领域模型,确保软件解决方案能够准确反映业务逻辑。这种方法有助于确保任何技术实现都能直接支持业务目标,使得对业务规则的更改更加直接和高效。

总结

  • 对于那些业务逻辑较为简单或标准化的应用程序,传统三层架构提供了一个清晰、易于管理的结构,可以快速实施并容易维护。
  • 对于业务规则复杂、需要深入业务领域以支持持续发展和迭代的项目,DDD提供了更好的解决方案。它通过深化对业务的理解和反映这种理解在软件设计中,帮助创建更灵活、可扩展的系统。

三、超核直播平台实施的方案

鉴于直播平台的业务功能和复杂性,在传统的三层架构基础上,融入了DDD的设计原则,以实现系统的高内聚、低耦合、易维护和高扩展性。

原则:

按照DDD的原则定义业务功能的有界上下文,确保每个领域内部的模型是一致的。这有助于明确不同业务领域的边界和职责,同时并不完整复用DDD全套概念,不过度设计。

3.1 整体设计过程

1. 定义有界上下文,划分微服务

首先,根据业务功能和需求,将系统分为几个主要的有界上下文(Bounded Contexts):

  • 主播管理:处理主播的注册、资料更新、上下架等。
  • 直播管理:涵盖直播的创建、推拉流管理、直播信息更新、聊天/弹幕等互动功能。
  • 营销工具:处理券的管理、发放和使用等。
  • 商品与交易:包括商品的管理、购买以及与之相关的交易处理。
  • 用户互动:包括积分系统、抽奖、PK对战、投票等增加用户参与感和互动性的功能。

并且将完整服务分为,直播服务,商品服务,券服务,互动服务四个微服务。不同微服务直接通过RPC和消息组件来进行通信

2. 应用三层架构

在每个领域内,我们应用分层架构:

  • 表示层(Presentation Layer):负责前端应用(H5、小程序,管理端)与后台的交互。接口处理,如API端口、WebSocket连接等。
  • 应用层(Application Layer):协调各个业务流程,如直播的创建流程、直播定时任务等。
  • 领域层(Domain Layer):包含业务逻辑和领域模型,如主播、直播、游戏商品、券、积分等领域实体和相关业务规则。
  • 数据访问层(Persistence Layer):负责数据的持久化,与数据库、Redis交互。

3. 设计领域模型

对于每个有界上下文,设计详细的领域模型,确保模型能够准确反映业务规则和逻辑。例如:

  • 主播:属性包括ID、姓名、描述、状态(在线、离线)、统计数据等。
  • 直播:属性包括直播ID、主播ID、开始时间、状态(准备中、进行中、已结束)、观众互动数据等。
  • …等等

3.2 架构图

img

3.3 架构目标

1、清晰的责任分离

通过三层架构,系统的表示层、业务逻辑层和数据访问层各自的职责清晰分离。这种分离使得开发和维护各层都更为简单和高效,因为每层都只关注于其责任范围内的问题。

2、深入的业务理解

DDD的应用使得设计更加聚焦于业务需求和业务逻辑。通过建立丰富的领域模型和使用有界上下文来封装业务规则,系统能够更好地反映和支持实际业务操作,提高了业务和技术的对齐度。

3、增强的模块化和可维护性

将系统划分为多个有界上下文,每个上下文内部应用三层架构,不仅提高了代码的模块化,还降低了不同模块间的依赖。这种高度的模块化使得系统更易于扩展和维护,同时也简化了团队的并行开发工作。

4、灵活的数据管理和性能优化

在数据访问层,可以根据每个有界上下文的具体需求选择最合适的存储和查询策略。例如,对于需要高速读写的直播聊天功能,可以选择使用高性能Redis。这种灵活性使得系统能够更好地满足不同业务场景下的性能需求。

5、更好的扩展性和并发处理

通过微服务架构的思想,每个有界上下文可以独立部署和扩展,这对于处理高并发和大规模用户基础尤为重要。此外,系统内部使用消息队列和缓存等技术可以有效地处理并发请求,提高系统的响应速度和可用性。