当前位置: 首页 > 后端技术 > Java

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

时间:2023-04-01 13:32:37 Java

图片来源:https://unsplash.com/@alistai...场景在系统层面封装,封装成高复用的服务,然后通过接口和扩展点暴露部分能力,但是有一个场景是解决不了的,就是在执行一段功能级代码的时候,希望能触发另一个功能。同时希望这个功能可以通过配置来解决,没有必要通过开发手段来解决这类问题。比如用户给主播送礼物,直播间的贡献榜给用户+1分。这是一个非常典型的“履约”场景。仓储系统的原理是一样的,只不过是基于这个流程模型的固化。活动通常不是这种情况。与这些固化的过程相比,活动更加灵活。笔者团队曾经开发过这样一个场景:用户通过赠送礼物的方式帮助主播在直播间完成一个虚拟能量棒的冲击,每次满了这个能量棒就想做一件事,而这个东西表明业务方脑洞很大。第一个活动是给某个榜单加分,第二个活动是给主播掉落。一个虚拟宝箱,第三个活动是给用户送一些彩票,等等。只要是做过的功能,他都希望这东西能用上。时间长了,他就会面临这个模块的频繁修改。代码,在“结束”的时候,如果有条件的去触发各个代码,或者在策略模式下修改代码,这种方式对长期构建不友好。在我看来,这只是本模块的结尾。做这么多事情,那么下一个模??块从那么多事情中选择两个,那岂不是要写一堆代码?于是我们想到了一个比较原始的解决方案:公交服务。用“履行”这个词来形容信鸽的组合能力而不是组合更合适,因为对于活动来说,信鸽只执行“合同履行”的功能更为重要,他要解决的是异步的scenarios分布问题,而不是针对某些系统做一些适配器组合集成的能力。举一个活动场景的例子:一个简单的音乐人活动页面,主要包含几个模块功能:用户通过赠送、观看等行为完成相关任务。为最喜欢的音乐家添加进度条点。当进度条点数完成某个档位时,会触发宝箱掉落、浮屏礼物等,每个档位类型不同。幸运锦鲤模块。对于这样一个activity,从开发的角度来看,其实是由几个模块组装而成的,除了4需要独立开发外,1、2、3都可以通过现有系统组装,这里将1抽象为Task系统,2被抽象为进度条系统,3也可以被抽象为宝箱系统、礼物系统等。下图展示了场景抽象模块的概念:那么难点来了,这些模块通过什么方式可以抽象出来?组装?从图中可以看出,当一个模块完成了它的生命周期后,就可以发送一段数据了。路由系统收到数据后,会帮我们转发一层路由,决定将数据路由到下一个系统。.下一个系统可能是“奖励系统”或“进度条系统”。同时,我们可以进一步细化这个行为的抽象。我们希望这个路由系统起到“总线”的作用。“信件”代表各个系统想要接收的数据,将各个系统抽象成一个目的地。如果我们配置一个路由关系(抽象为鸽子配置),那么这个“鸽子”就可以作为一个数据信,带我们去任何我们想去的目的地,那么对系统的好处就是系统只需要提供自己的只需要访问该路由系统的能力。下次你做任何活动的时候,你可以直接做一些组合关系。有了信鸽路由的思想,我们可以为音乐家活动的场景梳理出一个流程的完整链接:如图所示,我们对任务、进度条等基础模块做了一些扩展点(EXT-POINT)满足业务流程的编排,这是中台比较常规的解决问题的手段之一,而在系统模块组组合的场景下,多了一层信鸽服务的概念,在[2]、[3]、[4],信鸽可以决定数据流向哪个系统。事实证明,这个解决方案是可行的,也是有效的。整体架构那么如何设计这样的组合能力架构呢?研发的重点可以分为四个层次:执行合约的能力,代码完成时实现结束触发。SDK接入能力,接口级封装,天然的Autoconfigure能力。全球识别字典,一条数据如何让所有连接的系统达成共识。系统自动注册能力,接入SDK后,自动上报信鸽服务统一管理,自动激活,无需人工干预。基于这四个层次,架构设计如下:从图中可以看出,左边的虚线框代表一个系统的触发,右边的虚线框代表另一个系统的最终到达。鸽子系统充当代理服务。触发系统只需要连接信鸽SDK即可。在履行完自己的职责后,它会将数据组装起来,发送给信鸽系统。鸽子系统会根据发送过来的鸽子ID找到鸽子ID进行相关配置,鸽子id决定了数据将传输到哪个子系统。这种传输可以是同步的,也可以是异步的(当然大部分是异步场景)。异步主要依赖于“RocketMQ”的交付能力。当转发失败时,将对转发的数据结果集进行备份保存,以备定时步的重试操作。在以往的实践过程中,大部分场景都是异步链接,不需要获取下一个子系统提供的返回结果集,而且“RocketMQ”本身在传递消息时的错误率也是小概率事件(毕竟,4broker,3错误的可能性极低),相对于RPC等通信级接口有绝对优势。SDK路由触发在上图中,我们可以看到子系统大致分为两类场景,一类是活跃的业务域,一类是非活跃的业务域,本身与业务场景相关。我们希望所有的子系统都能按照标准接入SDK,但不保证每个子系统提供的能力都依赖于SDK。对于一些不活跃的业务领域,采用定制化的开发模式进行桥接工作。这种桥接工作更像是传统的Adapter和ESB总线的思路。活跃业务域中的所有子系统都可以采用接入SDK的方式。这里主要介绍异步设计思想。当子系统连接到SDK时,在Spring容器中创建bean时,默认会创建一个PushConsumerbean,添加一个监听信鸽“飞”的“Listener”,让它自动消费路由消息并分析消息。假设本系统可以承担的模块能力为S1/S2……、SN等功能,那么整体实现图如下:自动注册各个Provider的Server是一个独立的应用服务集群。对于每一个Provider来说,它提供的能力都不是单一的。上面说了一个domainservice(activeTOYservice:主要提供各种积木式的游玩区),他可以提供各种模块,比如宝箱、进度条、留言板等等,“act-toy”服务有很多功能,当“act-toy”服务接入SDK后,需要在信鸽上注册自己需要发布为Provider的子域的功能。注册方案如下图所示。Server拉取SDK启动时,会定时拉取定义的Interface。Class获取自定义注解的Type类型,通过顺序消息向信鸽Service注册,采用启动+定时推送的方式,信鸽Service收到后会存储相关注册信息。与ESB对比从整体组合能力来看,整体设计思路符合总线服务,总线服务行业经典的就是ESB总线。ESB总线的技术从今天的互联网来看是比较落伍的,因为它比较适合大型IT公司内部的一些跨语言的服务架构方案,本身就承担了系统之间的桥接能力。但是Pigeon本身的设计和ESB总线是不一样的。它更注重“哑管道”的概念,忽略了集成的适配转换,不适合集中同步集成。那么具体对比如下:适应场景优缺点鸽子服务临时短期活动的代码模块,集成了微服务体系下的“哑管道”设计思想,不关注数据集成和消息协议.适应活动领域业务特点,灵活集成,缩短研发周期大型IT系统集成能力弱ESB总线传统大型系统集成传统大型IT系统高度强集成,适应传统行业非互联网系统架构承载繁重的业务逻辑和协议转换,服务治理的瓶颈点高度集中,所以我们可以从两个ESB场景来介绍信鸽的优势。我所了解的ESB总线技术大致可以分为两类:开源ESB解决方案:这一类是开源解决方案。该框架技术部署在同一个Tomcat容器中,可以开发多个bundle在容器中运行,可以实现热替换的功能,但是每个bundle的通信方式需要自定义私有协议。由于这类开源框架较早,提供的通信协议大多是WebService,所以在开发过程中开发成本会非常高,比如Apache早期开源的ServiceMix。关于协议,通信需要编写大量的“wsdl”,而且大部分还依赖于WebService发布的接口。自研ESB集成能力,笔者曾经参与过一个企业级项目,大致ESB总线集成了各种系统,包括Rest协议接口,C++服务发布的WebService协议,以及海外第三方公司发布的WebService协议,为了连接公司内部的C++服务、JavaWeb服务和海外第三方系统,使用了集成总线,协议转换太多,包括如何解析“wsdl”文件读取节点数据,转成Json等,这种场景在企业级服务中很常见。不适合互联网场景。重点更多的是同步接口协议的转换。同时我们不知道编排的能力,大部分都是靠hardcoding来解决。不管是1还是2,都和我们Pigeon的设计思路不一样。Pigeon的本质是异步的做终端事件。它采用轻量级的协议结构,在技术上属于同一语系。因此,字典的定义也规范了,也就是说,userId和anchorId分别代表用户id和锚点id,任何一方都没有必要随意定义uid、aid等词。统一字典由信鸽定义,编排统一采集到信鸽服务来确定,可视化,不需要编写复杂的XML节点文件。与Pipeline的比较从总线的概念上看,它或多或少类似于“管道”。Pipeline的思想被广泛应用于很多技术领域:CI/CD持续集成场景。开源框架中的流水线设计模式,如Netty框架中的网络字节流处理等。业务定制的一些工作流传输技术。第一种场景更倾向于DevOps方案,从持续集成、持续交付、持续部署,到过程工程快速、自动化、可重复,这与我们要解决的上层业务编排场景完全不同今天两个领域。第二种场景本质上是一种代码实现设计模式。和Netty一样,采用“责任链”设计模式来实现。网络字节流经过“工厂流水线”后,进行打包,最终得到一个成品。,也不是我们今天要解决的业务领域。第三种场景是业务开发过程中经常遇到的问题,尤其是流程复杂的场景,包括流程和服务的编排,每个代码块和服务可能被当作一个“节点”串联起来实现整个pipeline来完成业务,它和我们的信鸽有什么区别||适应场景||---|---||信鸽服务|临时短线代码的尾部“履行”||Pipeline流线|流程域的业务编排,可以对审批流、营销等核心流程进行编排调度activities等|在我看来,两种技术方案是可以同时存在的,针对已经稳定的domain场景,我们做一些灵活定制化的流程安排,这些流程可以实现为“流水线”的思路.末端的流程节点可以定位为“鸽子”节点,这个节点可以继续自由组合定制的活动场景。信鸽转发能力问题直播活动不同于营销活动。大多数触发场景都偏向于平台下游。所以很多topic都需要监控来实现自己的业务编码。但是,在表单不成熟的背景下,Activity必须面对大量的短期代码,而短期代码的生命周期往往仅限于Activity周期。这种代码代表着探索和开拓。现场活动在领域建模方面有两个方面。一方面要根据历史经验进行复制和积累,另一方面要有短期代码快速部署的能力。随着服务数量的增加,很多服务需要监控topic,而这些topic可能已经为服务A监控,也有可能为服务B监控。面对这样的问题,我们需要连接topic来做一个代码复制代码或者做一些包来解决,但这不是一个友好的解决方案。同时,这也面临着另一个问题。另一个问题是,当一个代码块完成它的任务并且再也不会打开时,它访问的主题将一直处于空闲状态以供消费。Nydus”(RocketMQ云音乐版)管控平台部分消费下线。时间长了,消息管理就越来越难了,就像我们去一层层解决服务的循环依赖一样。没想到有一天异步链接也乱了。下图代表了“开发”过程中遇到的问题:解决思路希望信鸽能够继续发挥优势。它不仅仅是一个只执行业务端契约的总线服务,它应该在活动领域帮助我们。做好消息治理,首先需要研发思路的转变,即开发者需要将自己的topic提供给自己的“dev”模块。这个话题和自己的“dev”模块是一个技术闭环,如果每个“dev”模块都具备这个能力,信鸽只需要发挥自己的优势,把需要监控的话题变成话题转发即可通过Pigeon到模块。根据这个方案的前提,我们希望信鸽需要具备转发消息的能力,转发场景可以抽象为三种:业务定义分发场景:这个场景必须做一些具体的业务处理,通过原消息,做一些业务清洗工作,然后转发给一些业务场景,这些都是定制化的场景。注册上报自动分发场景:该场景下,信鸽服务的接收者只要监测到足够多的话题,就可以将信鸽自动分发到各个业务模块的话题上。消费者自宅选择性拉取,根据标签的区分,也可以解决上图提到的某个话题消息过多导致饿死的场景。消息存储场景:不是所有的消息都需要存储。在这种情况下,我们认为需要备份比较重要的消息,以便以后可以回放。例如,礼品消息在任何场景中的使用率都很高。为了提高书写输入的能力可以使用批量消费的消费方式来批量书写。这里写的初步选择是使用TiDB。与DDB(网易分布式数据库)相比,TiDB更适合存储此类消息。同时,这种类型的消息在大多数情况下是不需要阅读的。根据提到的三种场景,整体架构如下:我们的receiver可以根据配置的topic在spring容器中动态创建consumerbean,兼容新的接入topic,需要修改信鸽服务代码。同时,在收到主题消息的那一刻,消息转发分为如图所示的三个路径。这三个路径分别代表:自动转发、自定义转发、消息存储。这里选择了三个不同的消费者,保证消费线程池足够宽,转发主题队列足够消费。收到消息后,会根据源主题的类型再次自动转发,转发到配置的主题关系中。同时,这种转发关系可以由R&D自行管理。还可以配置它的生存周期,非常适合活动时间短的场景。活动结束后,减少服务的闲置消费。当然,毕竟还要考虑另一个问题。多一跳操作将导致转发失败。对于这种场景,我们会将失败的消息作为异常进行存储,并进行重试处理。同时,我们对信鸽的转发能力进行了压力测试。队列的长度设置得足够宽。在简单转发能力的场景下,IO的消耗主要集中在broker通信的场景。如果考虑到所有的消息都是异步放置的,那么系统的吞吐量会更好。选择“8U16G”服务器配置。在32个docker云容器的支持下,接收端可以处理300w/min的消息量,cpu可以保持在45%左右。虽然信鸽的转发能力解决了我们的问题,但不代表这是最优解。我希望的最优方案是让信鸽承载FaaS平台。毕竟FaaS可以提供??很多关于消息清洗的场景,而且FaaS在机器上。在资源调度上会有更好的表现。FaaS+BaaS的结合是未来系统技术变革的趋势。总结花时间搭建系统有什么好处,遇到了哪些困难?开发与维护这里用一个案例来说明研发使用信鸽服务进行业务开发后的收益。作为业务研发的学生,大勇今天需要开发一个活动。活动涉及榜单推广、直播杀怪、直播间飘屏、主播任务,本次活动的流程思路是:主播完成“xx”任务后,会掉落一个“怪”直播间,会发送悬浮屏通知。主播完成“xx”任务后,会在列表中添加一些积分。榜单跨日晋级topN,topN发送悬浮屏通知。好在上面涉及的功能之前都开发过,这次只需要完成组合即可。不幸的是,大勇需要培养这种组合能力。直到遇到信鸽,一切都迎刃而解。每个功能都与信鸽有关。那么大勇只需要通过信鸽背景,配置飞向信鸽的“杀怪”、“飘屏”等任务即可。对于大勇来说,可能只需要很短的测试时间,发布过程也减少了,不需要一次性的胶水组装代码。毕竟做完任务掉落怪物。看来这个逻辑写在任务系统里不是很合适。困难在处理消息管理等问题时,我们在实现业务覆盖时遇到了很多困难。我们必须对已连接到现有系统的主题进行一些更改。已经在新的业务场景中进行了尝试和测试,但是在老系统中(比如任务系统),提供了一个新的任务主题来发送和接收路由的旧消息。虽然我们也根据SDK的方式,根据tag(来源topic)区分了一些不同的服务,但是还是绕不开数据。清洗和数据结构协议转换问题,此类问题可能与任务系统本身的清洗思路有问题,解决此类问题的最佳方案一般可以采用脚本语言进行消息清洗,这样会更加灵活。同时在做容量测评的时候,一开始的压测也不是很顺利。由于写表链路和信鸽服务存在于同一个服务中进行压测,如果针对部分消息将数据写入TiDB,即使批量消费和写入也难以压制整体服务的吞吐量,所以写表的服务到TiDB链路是独立测试的,该区域的压力测试是单独进行的。信鸽原来的服务只做转发,写入和存储部分可以单独写入。评估。去掉写TiDB链接的场景,单独对服务进行吞吐量压力测试。一开始使用的“4U8G”服务器资源,因为整体转发性能比较cpu密集,在规范提升后,整体吞吐量增加。明显翻了一倍,而且由于在线消息量的评估,100w/min的消息可能是我们现有业务的极限。我们根据不同的消息量进行压测,最后输出一个压测结果集。会根据不同的消息量区间进行适当的扩容和缩容。未来展望本文针对云音乐直播活动技术团队在日常研发过程中遇到的业务场景组合、消息管理等问题提供系统设计思路,希望能帮助读者在日常开发中提供一些参考意见.目前主要集中在解决现有技术方面的问题。后期会把消息回放作为修复数据的重要手段和解决方案。从异常处理的角度,如何帮助研发同学快速修复线上问题。同时,面对未来的国际化场景,在消息用户区机房不够敏感的场景下,希望可以通过一些手段帮助业务方消息转发到相关电脑上机房,并协助“坑道”国际化,解决业务端的路由问题什么不清楚,以及在未来国际路由机房的基础上,模块间的消息是否能准确路由到用户电脑房间也是我们需要更深入思考的问题。我们希望信鸽能够作为赛事业务领域直播相关产品的重要解决方案之一,帮助更多相关同学解决“复用”和“组合”的烦恼。同时,我们希望它能够国际化,适应更多的产品场景。中间。团队引进云音乐大型直播赛事技术团队,主要负责直播相关产品的赛事业务研发,为Look直播、声波、新语提供一站式赛事中台解决方案等相关产品,以大直播为主,在活动架构体系上的建设为方向。欢迎有兴趣的同学相互交流。本文由网易云音乐技术团队发布。未经授权禁止任何形式的转载。我们常年招聘各种技术岗位。如果你要跳槽,恰好喜欢云音乐,那就加入我们staff.musicrecruit@service.ne...