关于java:直播活动系统基于消息总线的组合能力

45次阅读

共计 7902 个字符,预计需要花费 20 分钟才能阅读完成。

图片起源:https://unsplash.com/@alistai…

作者:燕十三

问题

所谓组装,就离不开陈词滥调的复用,咱们能够对大部分认为比拟共性的场景做好零碎级别的封装,封装成一个个复用度较高的服务,而后通过接口和扩大点的形式进行一部分的能力凋谢,然而有一种场景是解决不了的,就是当一个性能级别的代码执行完结后,心愿触发到另外一个性能,同时心愿这个性能是能够通过配置去解决的,并且不须要通过开发的伎俩去解决这类问题。
例如,用户送了一个礼物给一个主播,直播间的奉献榜上对该用户做了积分 +1,这是一个很典型的「履约」类场景,与咱们在直播间内下单购买,履约给仓储零碎情理是一样的,然而这都建设在这个流程模式是固化的。而流动往往不是这样的,流动相比这些固化的流程是更为灵便的,笔者的团队已经开发过这样一个场景:
用户通过送礼,去帮忙主播实现一个直播间虚构能量条的冲击,而每充斥这个能量条都心愿做一件事件,这个事件就彰显出业务侧的脑洞大开,第一次的流动是心愿给某个榜单加上分数,第二次的流动心愿是给主播掉落一个虚构的宝箱,第三次的流动是给用户发送一些抽奖券,顺次类推,只有是做过的性能,他都心愿这个事件能够去用,工夫久了,就会面临频繁去批改这个模块的代码,当它「完结」后,if 条件式的去触发各个代码,或者策略模式的去魔改代码,对于长期建设来看这种形式并不敌对,就我看来这只是这个模块完结后要做这么多事件,那么下一个模块如果从这么多事件挑两件岂不是还要再写一堆代码?
因而咱们想到了一个绝对比拟原始的解决方案:总线式服务。

信鸽的组合能力

与其说组合,更偏向于用「履约」这个词形容会比拟失当一点,因为对于流动来说,信鸽只做「履约」这一侧的性能比拟重要,他要解决的是异步场景的散发类问题,而不是对一些零碎做一些 adapter 组合集成的能力。这里以一个流动场景来做示例:

音乐人流动的一个简略的页面次要蕴含了几个模块性能:

  1. 用户通过送礼、观看等行为实现相干工作。
  2. 为青睐的音乐人加进度条积分。
  3. 当进度条积分实现某个档位后,触发宝箱的掉落、飘屏送礼等。每个档位的类型是不同的。
  4. 侥幸锦鲤的模块。

对于这样一个流动,从开发的角度来看,其实它是由几个模块进行组装的,除了 4 是须要独立开发的,1、2、3 都能够通过现有的零碎进行组装,这里 1 形象为工作零碎,2 形象为进度条零碎,3 也能够形象为宝箱零碎、送礼零碎等。下图是对场景抽象化模块的概念:

那么难点来了,通过什么伎俩能够来将这些模块进行组装呢?

通过图中能够看到,当一个模块实现了他的生命周期,能够发送一份数据,路由零碎收到了这个数据之后,会帮咱们做一层路由的转发,决定数据会路由到下一个零碎下来。下一个零碎可能是「处分零碎」也能够是「进度条零碎」。

同时能够对这个行为进一步细化的形象,咱们心愿这个路由零碎充当一个「总线」的角色,「函件」代表了每一个零碎心愿收到的数据,同时对每一个零碎都抽象化成一个目的地,如果咱们配置了一份路由关系(形象为信鸽配置),那么这只「信鸽」能够作为将数据函件为咱们带到咱们想去的任何目的地,那么对于零碎的益处是,零碎只须要提供本人接入这个路由零碎的能力即可,下一次轻易是什么流动,能够间接做一些组合关系。

有了信鸽路由这种思路,针对音乐人流动这种场景,咱们能够将一个流程的残缺链路梳理进去:

图中能够看到,咱们对工作、进度条等根底模块,做了一些扩大点(EXT-POINT)来满足业务流程的编排,这在中台里是比拟惯例的解决问题的伎俩之一,而在零碎模块组组合的场景中,多了一层信鸽服务的概念,在【2】、【3】、【4】的解决流程中,都能够由信鸽来决定数据流向哪个零碎,事实证明这个计划是可行也并且无效的。

整体架构

那么如何设计这样一个组合能力的架构呢?研发的重心能够分为四个层面:

  1. 履约能力,当代码完结后做到末端的触发。
  2. SDK 接入能力,Interface 级别的包装,人造的 Autoconfigure 能力。
  3. 全局的标识字典,一份数据如何让所有接入的零碎都能够达成共识。
  4. 零碎的主动注册能力,接入 SDK 后,主动上报到信鸽服务的对立治理,主动激活,不须要人工的染指开启。

基于这四个层面,架构设计如下图:

从图中能够看到,左侧虚线框代表了一个零碎的触发,左边虚线框代表了最终另外一个零碎的触达。信鸽零碎充当了代理的服务,触发的零碎只须要接入信鸽 SDK,当执行完本人的职责之后,对数据做一层组装发送给信鸽零碎,信鸽零碎会依据发送的信鸽 id,寻找到信鸽的相干配置,信鸽 id 决定了数据会流转到那个接入的子系统上,这个流转能够是同步的也能够是异步的(当然大部分都是异步场景),异步次要依赖「RocketMQ」的投递能力,当转发失败后,会对投递的数据后果集进行备份存储,用于定时步长的重试操作。
在以往的实际过程中,大部分场景都是异步的链路,不须要取得下一个子系统提供的返回的后果集,并且「RocketMQ」自身投递音讯的出错率也是小概率事件(毕竟 4 台 broker,出错 3 台的可能性是极低的),相比 RPC 这类通信级别的接口有相对的劣势。

SDK

路由触发

在上图中,咱们能够看到对于子系统分成了大略 2 类场景,一种是流动业务域,另外一种是非流动业务域,这自身与业务的场景无关,咱们心愿所有的子系统都能够依照规范去接入 SDK,然而并不能保障每个子系统提供能力都依附 SDK,对于一些非流动业务域应用了定制化开发的模式来进行桥接工作,这种桥接工作更像是传统的 adapter 和 ESB 总线思路。
而流动业务域的子系统都能够采取接入 SDK 的模式,这里次要会介绍一下异步的设计思路,当一个子系统接入 SDK 后,会在 Spring 容器创立 bean 的时候,默认创立一个 PushConsumer 的 bean,增加监听信鸽「fly」的「Listener」,这样能做到主动生产到路由的音讯,对音讯进行解析,假如这个零碎能够承当的模块能力别离是 S1 / S2 …, SN 等性能,那么整体实现图如下:

主动注册

每一个 Provider 的 Server 都是一个独立的应用服务集群,对于每一个 Provider 来说他提供的能力并不是繁多的,正如上文所说,一个畛域服务(流动 TOY 服务:次要提供各类积木式玩法畛域),他可能提供的模块是十分多样的,诸如宝箱、进度条、留言板等等,「act-toy」服务他具备了许多性能,当「act-toy」服务接入 SDK 后,就须要把本人子域须要公布成 Provider 的性能注册到信鸽上,注册的计划如下图,当一个 Server 拉取 SDK 的启动后,会定时的拉取定义好的 Interface,对实现的 Class,获取自定义注解的 Type 类型,通过程序音讯的形式注册到信鸽服务上,采纳了启动 + 定时推送的形式,信鸽服务收到相干的注册信息能够后会将其存储。

与 ESB 的比拟

从整个组合的能力上看,整体的设计思路是合乎总线式服务,而总线式服务业内比拟经典的,就是 ESB 总线,ESB 总线这个技术用明天互联网的角度来看是比拟过期的,因为他自身更适应用于大型 IT 企业外部的一些跨语言类服务架构计划,而他自身承接了零碎和零碎之间的桥接能力。然而信鸽自身的设计不同于 ESB 总线,他更重视的特点是「哑管道」的概念,疏忽集成的适配转换,也不适宜做中心化同步的集成。那么具体的比拟如下:

适应场景 长处 毛病
信鸽服务 长期短期流动的代码模块集成 微服务体系下的「哑管道」设计思路,不关注数据集成和报文的协定。适配流动域的业务特点,灵便集成,缩短了研发周期 大型 IT 系统集成能力弱
ESB 总线 传统大型系统集成 传统大型 IT 零碎的高度强性集成,适配传统行业非互联网零碎架构 承载沉重的业务逻辑和协定转换,服务治理的瓶颈点高度集中化

那么能够从 2 个 ESB 场景来介绍信鸽的劣势所在,笔者了解的 ESB 总线技术大抵分两类:

  1. 开源的 ESB 解决方案:这类是提供开源的一种框架技术,部署在同一个 Tomcat 容器中,开发若干个 Bundle 能够运行在容器中,并且能做到热替换的作用,然而每个 bundle 须要通信的模式须要定制公有协定。因为这类开源框架较早,提供的通信协议大部分是 WebService 类的,因而在开发过程中,开发的老本会十分高,例如 Apache 晚期开源的 ServiceMix。对于协定,须要写大量的「wsdl」做通信,大多数也是依赖 WebService 公布的接口。
  2. 自研的 ESB 集成能力,笔者已经加入过一个企业级的我的项目,大抵是 ESB 的总线集成了各路零碎,包含了 Rest 协定接口、C++ 服务公布的 WebService 协定、海内第三方公司公布的 WebService 协定,为了买通公司外部 C++ 服务、Java Web 服务与海内第三方零碎,采纳的就是做一个集成的总线,这里须要太多的协定转换,包含如何解析「wsdl」文件读取节点数据,转换成 Json 等等,这类场景在企业级服务是常见的事件,自身不实用互联网场景,侧重点更偏差于同步接口协议的转换,同时还不晓得编排的能力,大部分依附硬编码来解决。

无论 1 还是 2 与咱们信鸽设计思路都是不同的,信鸽实质上强调的是异步去做末端的事件,选用轻量的协定构造,在技术上属于同语言系,因而对于字典的定义也是标准化的,也就是说,userId、anchorId 别离代表了用户 id 和主播 id,并不需要任何一方突发奇想定义 uid、aid 这类的字样,由信鸽来定义统一化的字典,同时编排对立收拢到信鸽服务来确定,是可视化的,不须要编写简单的 XML 节点文件。

与 Pipeline 的比拟

从总线这个概念来看,或多或少同「管道」是相似的,Pipeline 的思维被广泛应用在诸多技术畛域中:

  1. CI/CD 继续集成的场景。
  2. 开源框架中的流水线设计模式,例如 Netty 框架中的网络字节流解决等。
  3. 业务自定义的一些工作流流转技术。
  • 第一种场景更偏向于 DevOps 的解决方案,从继续集成,继续交付,继续部署,为了疾速、自动化、可反复的形式的去解决工程,与咱们明天要解决的下层业务编排场景是齐全不同的两个畛域。
  • 第二种场景实质上是一种代码实现的设计模式,像 Netty 中,采纳的是「责任链」的设计模式去实现,网络字节流通过「工厂流水线」后,进行包装,最初失去一个成品,与咱们明天要解决的业务同样不是一个畛域。
  • 第三种场景是业务开发过程中常常遇到的问题,尤其是有简单流程的场景中,这里蕴含了对流程的编排、服务的编排,每个代码块和服务都可能作为一种解决的「节点」,在整个流水线中进行串排实现业务的实现。与咱们的信鸽有什么不同呢?

| | 适应场景 |
| — | — |
| 信鸽服务 | 长期短期流动的代码的尾部「履约」,不关注外围流程的串排,解决末端的场景多样化。|
| Pipeline 流水线 | 流程畛域业务编排,对外围流程能够进行编排和调度,例如审批流、营销流动等。|

在我看来,两种技术计划是能够同时存在的,咱们对曾经稳固的畛域场景,做一些灵便自定义的一些流程编排,这些流程能够作为「流水线」的思路去实现,在「流水线」开端的一个流程节点上能够定位为「信鸽」的节点,这个节点能够再持续自由组合定制化的流动场景。

信鸽转发能力

问题

直播的流动与营销流动的不同,大部分触发的场景偏差于平台的上游,因而须要监听许多 topic,去实现本人的业务编码,而流动在非成熟的模式背景下,必然要面临大量的短期代码,短期代码的生命周期往往只局限于流动周期内,这类代码代表了摸索,代表了开荒。直播流动在领域建模上是具备双面性的,一方面要在历史的教训去做教训复制和积淀,另一方面要具备疾速开展短期代码的能力。而随着服务数量的增多,就面临着许多服务要监听 topic,而这些 topic 对于 A 服务可能是监听过的,对于 B 服务可能也是监听过的,面临着这类问题,咱们须要把 topic 接入的代码做一次代码的 Copy 或者做一些包来解决,然而这并不是一个敌对的解决方案。同时,这也面临着另外一个问题,另外一个问题就是当一个代码块实现他的使命后,再也没有开启的那天,他接入的 topic 会始终进行空转的生产,咱们不可能常常的对「Nydus」(云音乐版 RocketMQ)管控平台去做一些生产下线,工夫久了,音讯治理就变得比拟辣手起来,就如同咱们去分层解决服务循环依赖,没成想有一天异步链路中也呈现了一团乱麻。上面这个图代表了「dev」过程中遇到的问题:

解决思路

咱们心愿信鸽能够持续施展他的劣势,它不仅仅是一个只做业务末端履约的一个总线服务,他更应该帮忙咱们流动域内的服务做好音讯治理这方面的工作,首先须要有一个研发思路的转变,就是开发同学须要为本人「dev」的模块去提供他的 topic,这个 topic 与本人「dev」的模块是一个技术闭环的,如果每一个「dev」的模块都具备这样的能力,信鸽只须要施展他的劣势,对原本须要监听的 topic 变成由信鸽转发给模块的 topic。

依照这个解决思路的前提下,咱们心愿信鸽须要具备的就是音讯转发的能力,而这个转发的场景能够形象为三种:

  1. 业务自定义的散发场景:这个场景是肯定要做一些特定业务解决的,通过原始音讯,做一些业务荡涤工作,再去转发到一些业务场景中,属于定制化的场景。
  2. 注册上报主动散发的场景:这个场景只有保障信鸽服务的 receiver 监听的 topic 足够,那么信鸽就能够主动散发到各个业务模块的 topic 上,其中散发的音讯构造是具备同样的,能够通过 tag 的不同让 consumer 自住选择性拉取,依据 tag 的辨别,同时也能解决某类 topic 音讯过多,导致饿死的场景,犹如上图提到的一样。
  3. 音讯存储的场景:并不是所有的音讯都须要存储,在流动中咱们认为较为重要的音讯是须要做备份,不便前期去做回放,例如礼物音讯,是任何场景使用率较高的,为了晋升写入的能力,能够采纳批量生产的生产形式,做 batch 的写入,在写入这里初步选型是用 TiDB,TiDB 绝对 DDB(网易分布式数据库)比拟适宜去存这类音讯,同时,这类音讯大部分时候是不须要做读操作。

依照提到的三个场景,整体的架构如下:

咱们的 receiver 能够依据配置过的 topic 动静的在 spring 容器里创立 consumer 的 bean,兼容了新接入 topic,须要批改信鸽服务代码的问题,同时在收到了 topic 音讯的那一刻,音讯转发如图中所形容一样,分成了三条路,这三条路代表了:主动转发、自定义转发、音讯存储,这里选用三个不同的 consumer,保障生产线程池的足够宽,和转发 topic 队列足够可生产,主动转发收到音讯后会依据源 topic 的类型再一次做 Tag 辨别的转发到配置的 topic 关系上,同时这个转发关系是能够让研发自助治理的,也能够配置他的存活周期,十分实用于流动短期场景,在流动完结后,缩小了服务的空转生产的状况。当然毕竟也要思考到另外一个问题,多了一跳的操作会导致到转发的失败,对于这种场景,咱们会对失败的音讯做 exception 的存储,进行重试解决。

同时,咱们对信鸽的转发能力做了压力测试,队列的长度设置的足够宽,不思考写表链路的场景下,单纯的转发能力,耗费 io 的点次要还是集中在 broker 通信的场景上,如果思考音讯都采纳异步落盘的状况下,零碎的吞吐量会更优,选用了「8U16G」的服务器配置,在 32 台 docker 云容器的撑持下,receiver 是能够承当到 300w/min 的音讯量,并且 cpu 还能放弃到 45% 左右。

尽管信鸽的转发能力解决了咱们的问题,但并不代表这是个最优解,我心愿的最优解是能够让信鸽搭载 FaaS 平台,毕竟 FaaS 能够提供很多对于音讯荡涤的场景,而且 FaaS 在机器资源调度上会有更好体现。FaaS + BaaS 这样的组合,是将来零碎技术转型的趋势。

小结

破费工夫做一个零碎到底带来什么样的益处,又遇到什么难点呢?

开发维护性

这里用一个 case 来形容研发在应用信鸽服务做业务开发后会带来怎么的益处,大勇作为一名业务研发同学,明天他须要开发一个流动,流动波及到榜单升级、直播间杀怪、直播间飘屏、主播工作,这个流动的流程思路是:

  1. 主播实现了「xx」工作后在直播间掉落一个「怪物」,并发送飘屏告诉。
  2. 主播实现了「xx」工作后给榜单加上一些分数。
  3. 榜单跨日升级 topN,topN 发送飘屏告诉。

很侥幸的是、以上波及到的性能,以前都开发过了,这一次只须要实现组合,很可怜的是,大勇须要开发这类组合能力。
直到他遇到了信鸽,所有迎刃而解了,每个性能都接入了信鸽,那么大勇只须要通过信鸽后盾,配置好工作实现要飞向「杀怪」、「飘屏」等等信鸽,对于大勇可能只须要很短的工夫提测了,公布流程也缩小了,一次性的胶水组装代码也不须要,毕竟实现工作掉落怪物,这个逻辑写在工作零碎如同也不是很适合。

艰难

在做音讯治理这类问题解决的时候,实现业务笼罩的时候遇到了很多难点,咱们要对现有零碎曾经接入的 topic 做一些革新,在新业务场景中是屡试不爽的,然而在旧零碎中(例如工作零碎),新提供了一个工作的 topic,收发路由的旧音讯,尽管咱们也依照 SDK 的形式做了依据 tag(源 topic)做一些不同 service 的辨别,然而这里仍然防止不了对于数据荡涤和数据结构的协定转换问题,这类问题可能与工作零碎自身的荡涤思路是有问题的,而这类问题最佳的解决方案个别能够选用脚本语言去做音讯荡涤会更加灵便一点。
同时在做容量评估的时候,初期的压测并不是很顺利,因为写表链路与信鸽服务存在一个服务中进行压测,如果对某些音讯进行数据写入 TiDB 的话,即使是批量生产写入整体服务的吞吐量也是难以压下来的,因而对写 TiDB 链路的服务独自进行独立,独自进行这方面的压测,信鸽原始服务只做转发,而写存储这一块能够独自去做写能力的评估。去掉了写 TiDB 链路的场景,独自对服务的进行吞吐量压测,起初选用的「4U8G」的服务器资源,因为整体的转发性能较为吃 cpu,当晋升了规格之后,整体的吞吐量有了很显著翻倍,而介于线上音讯量的评估,100w/min 的音讯可能是咱们现有业务的极限情况,咱们别离依照不同音讯量做了压测,最初输入了一个压测后果集,会依据不同的音讯量区间做适当的扩容和缩减。

将来瞻望

本文就云音乐大直播流动中台技术团队在日常研发过程中遇到对于业务场景组合、音讯治理这类问题,提供了一种零碎设计的思路,心愿能够帮忙读者在日常开发提供一些参考的意见。目前次要还是围绕着解决现有技术侧问题所开展的,前期会思考对音讯回放这一块作为修复数据的一个重要伎俩和解决方案,站在异样解决的视角上,如何帮忙研发同学疾速修复线上问题。
同时,面对将来国际化的场景下,对于音讯用户地区机房不够敏感的场景下,心愿能够通过一些伎俩来帮忙业务侧音讯转发到相干机房,帮助「Nydus」国际化后,解决业务侧路由的不清晰之处,而在将来的国际化路由机房的根底上,如果做到模块之间音讯能够精确的路由到用户所在机房也是咱们须要更加深刻思考的问题。
咱们心愿信鸽能够作为直播相干产品在流动业务域的重要解决伎俩之一,帮忙更多相干同学解决「复用」、「组合」的懊恼,同时心愿它能够国际化,适应更多的产品场景之中。

团队介绍

云音乐大直播流动中台技术团队,次要负责直播类相干产品的流动业务研发,为 Look 直播、声波、心遇 等相干产品提供一站式的流动中台解决方案,重点围绕着大直播流动架构体系中台化建设为方向。欢送有趣味的同学一起交换。

本文公布自网易云音乐技术团队,文章未经受权禁止任何模式的转载。咱们长年招收各类技术岗位,如果你筹备换工作,又恰好喜爱云音乐,那就退出咱们 staff.musicrecruit@service.ne…

正文完
 0