当前位置: 首页 > 科技观察

复杂分布式架构下的计算治理之路

时间:2023-03-17 17:55:36 科技观察

引言在当前的复杂分布式架构环境下,服务治理成为热门话题。但是往下看下一层,从上层的APP、Service,到底层的计算引擎层,各个引擎还是各干各的,Client-Server模型紧耦合,满天飞的情况天空。如何做好“计算治理”,让复杂环境下的各类大型计算任务更简洁、灵活、有序、可控地提交和执行,并确保结果的成功返回?计算中间件Linkis就是针对上述问题实践的答案。1、复杂分布式架构环境下的计算治理存在哪些问题?1、什么是复杂的分布式架构环境?分布式体系结构是指系统的组件分布在通过网络连接的不同计算机上,组件之间通过网络连接。通过消息进行沟通和协调,合作完成某个目标。一般来说,有两个拆分方向,水平(集群)和垂直(功能模块切分),解决高内聚、低耦合、高并发、高可用等问题。多个分布式架构系统组成一个分布式系统群,形成一个相对复杂的分布式架构环境。它通常包括各种上层应用服务和各种底层基础计算和存储引擎。如下图所示:2.什么是计算治理?《微服务设计》一书中提到,就像规划、设计和治理一样,一个庞大复杂的软件系统环境中的各个领域、要素、角色、关系也需要整改和管理,才能协同工作以更加简洁、优雅、有序、可控的方式进行,而不是变得一团糟。在当前复杂的分布式架构环境下,大量APP和Service之间的通信、协调和管理已经有了从SOA(Service-OrientedArchitecture)到微服务的成熟概念,以及从ESB到ServiceMesh的诸多实践。实现从服务注册发现、配置管理、网关路由、到流控熔断、日志监控等一系列完整的服务治理功能。服务治理框架的“中间件”层设计可以很好的实现解耦、异构屏蔽和服务之间的互操作性,并提供路由、流量控制、状态管理和监控等治理功能的通用提取和重用。增强整个架构的灵活性、管控能力、扩展性和可维护性。但是如果往下看一层,你会发现,从APP、Service,到后台引擎这一层,各个引擎依然各司其职,Client-Server模式与飞行情况紧耦合。在大量的上层应用和大量的底层引擎之间,缺乏一个通用的“中间件”框架设计。类似于下图所示的网格。计算治理主要集中在紧耦合、缺乏灵活性和控制能力、缺乏可重用性、可扩展性、可维护性差等问题。需要让复杂的分布式架构环境中的各类计算任务更加简洁、灵活、有序、可控地提交和执行,并成功返回结果。如下图所示:3.计算治理问题描述更详细地看计算治理问题,可以分为架构(architecturelevel)和洞察(refinementfeatures)两个层次。(1)ArchitectureofComputingGovernance——架构层面的问题。紧耦合问题,上层应用与底层计算存储引擎之间的CS连接方式。所有的APP&Service和底层的计算和存储引擎都通过Client-Server模式连接起来,处于紧耦合状态。以AnalyticsEngine的Spark为例,如下图所示:这种状态会带来以下问题:引擎客户端的任何变化(如版本升级)都会直接影响到客户端内嵌的每一个上层应用;当应用系统数量多、规模大时,变更一次的成本会非常高;直连模式导致上层应用缺乏跨底层计算存储引擎实例级、路由选择、负载均衡等能力;或者取决于特定底层引擎提供的特定连接有些引擎有,有些没有;随着时间的推移,不断有新的上层应用和新的下层引擎加入,整体架构和调用关系会越来越复杂。减少维护。重复造轮子问题,每个上层应用工具系统都要重复解决计算治理问题。每个上层应用都必须反复集成各种客户端,创建和管理客户端到引擎的连接和状态,包括底层引擎元数据的获取和管理。当并发用户数增加,并发计算任务量逐渐增加时,各个上层应用不得不反复解决多个用户之间的资源争用、权限隔离、计算任务超时管理、客户端故障恢复等问题。尝试并等待计算治理问题。想象一下,你有10个上层应用,有数百个并发任务,无论是基于Web的IDE开发环境、可视化BI系统、报表系统、工作流调度系统等,每一个都连接着3个底层计算引擎。上面的计算治理问题你可能要一个一个解决10*3=30次,而这就是目前各个公司正在发生的现实,由此造成的人力浪费不容小觑。扩张困难。上层应用新接入底层计算引擎,维护成本高,变更大。在CS的紧耦合模式下,上层应用程序每次新连接到下层计算引擎时,都需要进行重大更改。以对接Spark为例,上层应用系统中每台需要提交Spark作业的机器都需要部署维护Java和Scala运行环境和变量,下载部署SparkClient包,配置维护Spark相关环境变量。如果要使用SparkonYARN模式,还需要在每台需要提交Spark作业的机器上部署和维护Hadoop相关的jar包和环境变量。而如果你的Hadoop集群需要启用Kerberos,不幸的是,你还需要在上述每台机器上维护和调试一堆Kerberos相关的配置,比如keytab和principal。这只是一个对接Spark的底层引擎。随着上层应用系统和下层引擎的增多,需要维护的关系将呈笛卡尔式增长,客户端的部署维护和配置将成为一个令人头疼的问题。应用孤岛问题,不同应用工具和不同计算任务之间的互通问题。多个相互关联的上层应用,以及提交给后台引擎执行的不同计算任务,往往是相关的、共同的,比如需要共享一些用户自定义的运行时环境变量、函数、包、数据文件等。目前的情况往往是各个应用系统就像一座孤岛,相关的信息和资源无法直接共享,需要在不同的应用系统中进行人工定义和维护。一个典型的例子就是在数据批处理程序开发过程中,用户在数据探索开发IDE系统中定义的一系列变量和函数,往往要在数据可视化系统中重新定义;IDE系统运行生成的数据文件的位置和名称,不能直接方便的传递给可视化系统;还需要从IDE系统下载依赖包,重新上传到可视化系统;当涉及到工作流调度系统时,这个过程又得重复一遍。不同上层应用之间,计算任务的运行依赖于缺乏互通和复用能力。(2)ComputationalGovernance(insight)-Refinementfeatureissues:除了上述的架构问题,还需要在复杂的分布式架构环境中,让各类计算任务更加简洁、灵活、有序、高效。提交和执行可控,结果成功返回,计算治理还需要关注高并发、高可用、多租户隔离、资源控制、安全增强、计算策略等细节特征。这些问题都比较直白易懂,这里就不一一讨论了。二、基于计算中间件Linkis的计算治理-架构1.Linkis架构设计引入核心功能模块和流程计算中间件Linkis,微众银行专为解决上述紧耦合、重复造轮、扩容计算治理问题而设计比如困难和应用孤岛。目前主要解决复杂分布式架构的典型场景——数据平台环境下的计算治理问题。Linkis作为一个计算中间件,在上层应用和底层引擎之间建立了一个中间层。可以帮助上层应用快速连接底层各种计算和存储引擎(如Spark、Hive、TiSpark、MySQL、Python等)类型的计算任务,实现运行时上下文和依赖的互通共享跨上层应用程序的计算任务。并通过提供多租户、高并发、任务分发与管理策略、资源管控等特性支持,更灵活、可靠、可控地提交和执行各种计算任务,并成功返回结果,大大减轻了上层应用对计算治理层的负担。开发和运维成本,以及整个环境的架构复杂度,填补了通用计算治理软件的空白。为了更详细地了解计算任务通过Linkis的提交和执行流程,我们先来看看Linkis核心的“计算治理服务”部分的内部架构和流程。如下图所示:ComputingGovernanceService:计算中间件的核心计算框架,主要负责作业调度和生命周期管理、计算资源管理、引擎连接器的生命周期管理。PublicEnhancedServices:通用公共服务,提供基本的公共功能,可以服务于各种Linkis服务和上层应用系统。计算治理服务的主要模块如下:入口服务,负责接收作业请求,将作业请求转发到对应的Engine,实现异步队列、高并发、高可用、多租户隔离的应用管理服务AppManager,负责用于管理所有的EngineConnManager和EngineConn,并提供EngineConnManager级别和EngineConn级别的标签能力;加载新的引擎插件,向RM申请资源,要求EM根据资源创建EngineConn;根据标签功能,将可用的EngineConn分配给作业。资源管理服务ResourceManager接收资源申请,分配资源,提供系统级和用户级的资源管控能力,为EngineConnManager和EngineConn提供负载控制。引擎连接器管理服务EngineConnManager负责启动EngineConn,管理EngineConn的生命周期,定期向RM报告资源和负载情况。引擎连接器EngineConn负责与底层引擎交互,解析转换用户作业,向底层引擎提交计算任务,实时监控底层引擎的执行,将相关日志、进度、状态推送回入口.如上图所示,一个作业的提交和执行主要分为以下11个步骤:1.上层应用向计算中间件提交作业,微服务网关SpringCloudGateway接收作业并转发到入口处。2.入口消费job,向AppManager申请job可用的EngineConn。3.如果没有可重用的Engine,AppManager尝试向ResourceManager申请资源,并为该作业启动一个新的EngineConn。4.申请资源后,需要EngineConnManager根据资源启动一个新的EngineConn。5、EngineConnManager启动一个新的EngineConn,并主动推送新的EngineConn信息。6.AppManager将新的EngineConn分配给Entrance,Entrance将EngineConn分配给用户job,job开始执行,将计算任务提交给EngineConn。7.EngineConn向底层计算引擎提交计算任务。8、EngineConn实时监控底层引擎的执行状态,将相关日志、进度、状态回馈给Entrance,Entrance通过WebSocket主动将EngineConn传递过来的日志、进度、状态回馈给上层应用系统。9.EngineConn执行完成后,回推计算任务的状态和结果集信息,Entrance会将作业和结果集信息更新到JobHistory中,并通知上层应用系统。10、上层应用系统访问JobHistory,获取Job和结果集信息。11、上层应用系统访问Storage,请求作业结果集。计算任务管理策略支持,在复杂的分布式环境中,一个计算任务往往不仅仅是简单的提交执行和返回结果,还可能需要面临提交失败、执行失败、挂起等问题,并且在大量的并发场景中。需要通过计算任务的调度和分配来解决租户之间的相互影响、负载均衡等问题。Linkis通过对计算任务进行标注,支持在任务调度、分发、路由等方面的计算任务管理策略,并可按需配置超时、自动重试、灰度、多活等策略支持。说完了基于SpringCloud微服务框架的业务架构,现在来说说技术架构。在计算治理层环境中,很多类型的计算任务的生命周期都很短。例如,一个Spark作业可能会在几十秒到几分钟内执行完毕,EngineConn(EnginConnector)会处于动态启停状态。Linkis中的前端用户和其他管理角色的服务需要能够及时动态发现相关服务实例的状态变化,获取服务实例的最新访问地址信息。同时需要考虑模块间的通信、路由、协调,以及各模块的水平扩展、负载均衡、高可用等能力。基于以上需求,Linkis其实是基于SpringCloud的微服务框架技术。将上述每一个模块/角色封装成一个微服务,构建多个微服务组,形成Linkis完整的计算中间件能力。.从多租户管理的角度来看,上述服务可以分为租户相关服务和租户独立服务两种。租户相关服务指的是一些逻辑处理负载大、资源消耗大的任务,或者需要按照特定的租户、用户、物理机等进行隔离划分,避免相互影响的服务,比如Entrance、EnginConn(EnginConnector)经理,EnginConn;AppManger、ResourceManager和ContextService等其他服务是独立于租户的。Eureka承担了微服务的动态注册和发现中心,以及所有租户无关服务的负载均衡和故障转移功能。Eureka有个限制,就是在它的客户端,后端微服务实例的发现和状态刷新机制是客户端主动轮询刷新,最快可以设置每秒一次(实际需要几秒)完成刷新)。这样,在需要快速刷新EnginConn等大量后端服务状态的Linkis中,时效性得不到满足,而且Eureka服务器和后端微服务实例定期轮询刷新的成本非常高。为此,我们修改了SpringCloudRibbon,封装了Eureka客户端的微服务实例状态刷新方法,使其成为满足条件的主动请求刷新,而不是频繁的周期性轮询。这样在满足时效性的同时,大大降低了状态获取的成本。SpringCloudGateway承担了外部请求Linkis的入口网关的角色,有助于简化前端用户的调用逻辑,在服务实例不断变化的情况下,快速方便的获取最新的服务实例访问地址信息。SpringCloudGateway有一个局限性,即一个WebSocket客户端只能将请求转发给特定的后台服务,而一个WebSocket客户端不可能通过网关API在后台连接到多个WebSocket微服务,这在我们的入口HA等场景需要使用。为此,Linkis对SpringCloudGateway做了相应的修改,在Gateway中实现了一个WebSocket路由转发器,用于与客户端建立WebSocket连接。连接建立成功后,会自动解析客户端的WebSocket请求,根据规则判断将请求转发给哪个后端微服务,然后将WebSocket请求转发给对应的后端微服务实例。详见Github上Linkis的Wiki文章《网关的Multi-WebSocket请求转发实现》。SpringCloudOpenFeign提供的HTTP请求调用接口和解析模板能力帮助Linkis构建底层RPC通信框架。但是基于Feign的微服务间的HTTP接口调用只能满足简单的A微服务实例按照简单的规则在B微服务中随机选择一个服务实例,如果B微服务实例要异步回传信息给调用者,是不可能。同时,由于Feign只支持简单的服务选择规则,无法将请求转发到指定的微服务实例,也不可能将一个请求广播到接收微服务的所有实例。Linkis基于Feign实现了自己的底层RPC通信方案,集成到所有Linkis微服务中。微服务既可以是请求调用者,也可以是请求接收者。作为请求调用者,会通过Sender请求目标接收者微服务的Receiver;作为请求接收者,会提供一个Receiver来处理请求接收者Sender发送的请求,完成一次同步或异步响应。如下图所示。详情参见Github上LinkisWiki中的文章《LinkisRPC架构介绍》。至此,Linkis介绍了上层应用与底层引擎解耦的原理,其核心架构和流程设计,以及基于SpringCloud微服务框架的实现。介绍了各模块的微服务动态管理、通信路由、水平扩展能力。2.解耦:Linkis如何解耦上层应用和底层引擎Linkis作为一个计算中间件,在上层应用和底层引擎之间建立了一个中间层。上层应用的所有计算任务首先通过HTTP、WebSocket、Java等接口提交给Linkis,再由Linkis传递给底层引擎。解除了原来上层应用在CS模式下直连底层引擎的紧耦合,实现了解耦。如下图所示:通过解耦,底层引擎的变化被Linkis中间件层缓冲。例如,引擎客户端的版本升级,不需要为每一个连接的上层应用一个一个地改变,在Linkis层就可以完成。并且在Linkis层,可以实现对上层应用更加透明友好的升级策略,比如灰度切换、多活等策略支持。并且即使接连接入更多的上层应用和下层引擎,整个环境的复杂度也不会发生太大变化,大大降低了开发和维护的工作量。3、复用:对于上层应用,Linkis如何将计算治理模块进行压缩复用,避免重复开发上层应用复用Linkis实例(Scriptis)有了Linkis,上层应用可以基于Linkis快速实现多个后台计算和存储引擎对接支持,以及变量和函数的定制和管理、资源控制、多租户、智能诊断等计算治理特性。好处:以微众银行和Linkis同时开源的交互式数据开发探索工具Scriptis为例。Scriptis开发者只需专注于WebUI、多种数据开发语言支持、脚本编辑功能等纯前端功能的实现。支持存储读写、计算任务提交与执行、作业状态日志更新、资源管控等几乎所有的后台功能,基于Linkis的大量计算治理层能力的复用大大降低了开发难度Scriptis项目的成本,使得Scritpis目前只需要有限的前端人员即可完成维护和版本迭代工作。如下图所示,Scriptis项目中99.5%的代码都是前端的JS和CSS代码。后台基本上完全复用了Linkis。4、快速扩展:对于底层引擎,Linkis如何以少量的开发实现新底层引擎的快速对接。模块化可插拔的计算引擎接入设计,新引擎简单快速连接典型的交互模式计算引擎(提交任务,执行,返回结果),用户只需要buildApplication和executeLine2个方法,是的,2个方法,2个方法,一个新的计算引擎可以用极少量的代码连接到Linkis。例子如下。(1).AppManager部分:用户必须实现的接口是ApplicationBuilder,用于封装新引擎连接器实例的启动命令。//用户必须实现的方法:用于封装新引擎连接器实例启动命令defbuildApplication(protocol:Protocol):ApplicationRequest(2)。EngineConn部分:用户只需要实现executeLine方法即可将执行计算任务提交给新引擎://用户必须实现的方法:用于调用底层引擎提交并执行计算任务defexecuteLine(context:EngineConnContext,code:String):ExecuteResponse引擎相关的其他函数/方法已经默认实现,无需自定义需求,直接复用即可。5、连通性,Linkis如何打通应用孤岛通过Linkis提供的上下文服务,以及存储和素材库服务,环境变量、函数、程序包、数据文件等可以方便地实现多个上层应用之间连接,以及相关信息资源共享复用,打通应用孤岛。上下文服务上下文服务简介上下文服务(CS)为不同的上层应用系统和不同的计算任务提供统一的上下文管理服务,可以实现上下文的定制和共享。在Linkis中,CS需要管理的上下文内容可以分为三部分:元数据上下文、数据上下文和资源上下文。元数据上下文定义了底层引擎元数据在计算任务中的访问和使用规范。主要功能如下:为用户提供所有元数据信息读写接口(包括Hive表元数据、在线数据库表元数据、其他NOSQL如HBase、Kafka等Metadata);计算任务所需的元数据的注册、缓存和管理。数据上下文,定义了数据文件在计算任务中的访问和使用规范。管理数据文件的元数据。Runtimecontext管理各种用户自定义的变量、函数、代码段、包等。同时,Linkis还提供统一的素材管理和存储服务,可以按需接入上层应用,实现脚本文件、程序包、数据文件等存储层的连接。3.ComputingGovernanceBasedonComputingMiddlewareLinkis-从高并发、高可用、多租户隔离、资源控制、计算任务管理策略等方面介绍了Insight的LinkisComputingGovernance特性的详细设计和实现。大量的细节考虑和实现确保了复杂条件下计算任务的成功执行。1、计算任务的高并发支持。Linkis的Job基于多级异步设计模式。服务通过高效的RPC和消息队列方式进行快速通信,任务可以通过给Job打上creator、user等各类标签来执行。转发和隔离,提高Job的并发性。通过Linkis,一个入口服务(Entrance)可以同时承接超过10,000+个在线工作请求。多级异步设计架构图如下:如上图所示,Job从GateWay到Entrance之后,Job从生成到执行再到信息推送经历了多个线程池,每个环节都经过异步设计模式。每个线程池中的线程都采用了运行一次就结束的方式,减少了线程开销。整个作业从请求-执行-到信息推送都是异步完成的,大大提高了作业的并发能力。这里解释一下计算任务中最关键的作业调度层。作业调度层如何实现海量用户千并发任务的压力?在请求接收层,在请求接收队列中,会缓存前端用户提交的上万个计算任务,按照调度组划分到下游Job调度池中的调度队列系统/用户级别;到Job调度层,多个调度组对应的调度器,会同时消费对应的调度队列,获取Job提交到Job执行池执行。在这个过程中,多线程、多级异步调度和执行等技术得到了广泛的应用。示意图如下:2.其他细节特性Linkis在高可用、多租户隔离、资源管控、计算任务管理策略等方面也做了很多细致的考虑和实现。限于篇幅,这里不再详细描述各个细节特性的实现。可以参考Github上的LinkisWiki。稍后,我们将专门介绍Linkis的计算治理-Insight的详细特性。