基于MQ的分布式Serverless多租户任务处理系统架构演进1Serverless异步任务处理系统的诞生与挑战无论是对于云开发者还是试图升级业务的企业客户,Serverless的三大理念“极致弹性、Serverless运维、按量付费”几乎深入人心;但关于Serverless能做什么、怎么做,仍然是我们身边最普遍的声音。在serverless研发初期,技术团队通常会更加关注弹性和冷启动加速,希望通过弹性能力来凸显产品的技术竞争力,确立产品在市场上的领先地位,并依托靠这些能力来吸引开发者和企业客户使用Serverless,现阶段更多的是依靠技术的影响力来引导大家去探索Serverless。随着我们对Serverless的理解不断加深,弹性能力的提升进入深水区,相对来说,在没有本质变化的情况下,我们会更多的考虑触及Serverless弹性以外的其他价值。这个时候弹性就会作为一个系统Serverless的基础能力渗透到产品的方方面面。需要更多地从系统的角度去考虑Serverless能做什么,能给客户带来什么,如何把业务集中在那些必须定制的部分?系统化是指我们需要从资源供给、灵活调度、应用框架、能力评估、运维观察等多个维度来考虑Serverless系统对客户业务的价值,哪些需要用户参与,哪些需要用户参与较少,哪些需要用户参与为需要服务的客户提供定制能力;对于必须参与的客户,平台需要提供便捷的开发工具,满足客户在开发阶段的需求;在具体业务逻辑的实现上,利用Serverless灵活的扩展性,帮助开发者以最快的速度实现和其他业务。云服务的快速连接和提供稳定高效的访问是Serverless能够为客户带来的核心价值。面对客户实际需求,产品需要考虑多种业务场景:离线场景下的耗时任务执行、在线场景下的高并发请求处理、事件驱动场景下的事件处理。如何在一个计算平台上整合多个业务场景满意是我们面临的最大挑战。基于对Serverless的不断深入理解,结合产品在灵活调度方面的不断积累,我们开始构建基于多租户架构的Serverless异步任务处理系统,使用异步访问方式帮助用户托管请求并提供面向服务的方法,帮助用户快速执行任务,处理异常,提供可靠的执行保障。结合异步结果交付能力,希望能够面向事件驱动、在线业务处理、ServerlessJob/Task等复杂业务场景,为客户带来更多价值。.构建面向多租户场景的Serverless异步任务处理系统,需要面对各种挑战;这时候,我们需要简单分析一下任务系统是干什么的:任务分发、任务调度、任务执行。Serverless本质上是一种多租户和分时的商业模式。关于serverless异步任务处理系统的挑战,结合任务处理系统的功能需求,这些挑战可以归纳为三个方面:一是多租户架构本身带来的未来挑战:包括租户隔离、多租户资源管理,如何平衡隔离与成本的矛盾。最后,我们需要关注多租户架构下自动诊断和问题快速定位的挑战;二、业务类型的多样性资源与资源供给矛盾带来的挑战:资源需求多种多样,客户可能需要多种资源,如CPU密集型、IO密集型、内存密集型等;运行环境多样,客户运行业务逻辑时,需要为任务提供相应的运行环境,需要面对多种运行环境;运行时间的不确定性,面对线下和线上场景不同的业务特性,实际任务的执行时间差异较大;最后,不同业务类型的流量特性不同,流量不可预测等问题带来的请求处理、任务调度、流控策略等方面的挑战;第三,任务管理本身需要面对的挑战:包括任务生命周期管理、运行操作、任务去重、任务执行状态、任务结果跟踪和交付等相关问题带来的挑战。以上挑战也是企业在构建分布式业务系统时面临的核心问题。从产品的角度,我们希望通过构建异步任务系统,帮助用户解决分布式系统中这些常见的典型问题。客户只需要关注自己的业务请求提交和执行结果即可。Serverless的灵活性、资源调度、系统流控与可靠执行、错误重试等从请求提交到执行过程中涉及的细节无需用户关注,真正实现了Serverless的倡导。Serverless的几个核心理念:极致的弹性、Serverless运维、按需付费,最终帮助客户实现Serverless的商业价值。在讨论了构建Serverless异步任务系统所面临的各种挑战之后,通过以上分析,Serverless异步任务处理系统的功能可以简单归纳为以下四个核心模块:① 请求托管:负责多租户架构的任务托管、用户请求存储、用户请求获取、用户请求执行,多组架构下如何选择合适的隔离粒度更好的实现用户请求隔离,如何更好的平衡隔离和成本在用户隔离要求之间取得平衡。② 流量控制:通常用户选择异步任务处理系统,大概率是因为请求和消费的矛盾。如何帮助客户解决用户请求与后端资源供给的矛盾,更好的执行用户任务请求是异步系统的核心,流控至关重要。③ 执行管理:执行管理主要分为两个层次。首先,如何更好的执行任务,更好的和流控挂钩,如何更好的调度资源,更好的执行任务,也是对系统底层调度的挑战。其次,如何管理任务请求,比如在任务执行过程中可能需要挂起、删除或者批量操作,还需要对已执行的任务提供状态跟踪,了解其执行状态,提供能力删除重复任务。④ 目标投递:也可以称为结果投递,需要将任务最终的执行结果返回给用户。关于结果的交付,这里有很多思考,一个是如何交付结果;另一个是如何以更好的方式交付结果;前者更直观,而对于后者,我们希望任务执行的结果能够提供更灵活的再处理能力,因此实现支持将结果传递到函数计算、MQ、EventBridge等更通用的产品中.基于这些产品,用户可以使用事件驱动或相关能力,对任务执行结果进行后续的再处理,包括发送短信、webhook等,实现与异步任务系统的上下游联动。2Serverless异步任务处理系统多租户架构演进下图展示了一个典型的异步任务处理系统的基本模型,它使用API??来进行任务提交、任务调度、任务执行,最后交付执行结果。在传统的任务处理框架中,任务调度、负载均衡、流量控制策略的能力构建通常是基于服务网关。这也是分布式系统建设中最基础,也是最核心、最复杂、最耗费人力的重点。施工部分;后端实现通常基于进程粒度的内存队列和运行时级别的线程池模型来完成特定任务的调度和执行。Serverless异步任务处理系统的流程如下:用户通过API分发任务。请求到达无服务器服务网关后,存储在异步请求队列中。AsyncService会开始接管这些请求,然后请求调度获取后端资源。请求被分配给特定的后端资源以供执行。在这个架构图中,AsyncService负责实现传统架构中的请求分发器、负载均衡、流量控制策略和资源调度。这时候函数集群就相当于抽象的分布式线程池模型。函数计算模型下,实例间交互隔离,资源具备水平扩展能力,可以避免传统应用架构下单机资源受限带来的线程池容量和资源调度瓶颈问题。同时,任务的执行环境也不会受到整体业务系统运行时间的限制。Serverless异步任务系统相对于传统任务系统的价值。从Serverless任务处理系统的架构来看,其处理逻辑非常简单。分布式系统所依赖的大部分能力都是由AsyncService系统的角色透明实现的。对于用户来说,更多的是通过函数式编程。通过整体架构提供任务处理的实现逻辑,避免了对基于语言运行时的线程池的依赖。整个函数计算集群提供了一个容量“无限”的“线程池”。通过服务方式,用户只需要提交请求,其他的并发处理、流量控制、积压处理都由Serverless平台完成。当然,在实际执行过程中,还需要结合业务特点配置异步任务处理的并发度、错误重试策略和结果传递。下面重点介绍Serverless异步任务处理系统构建中的一些技术细节。首先,我们从任务分发和请求托管来描述构建一个Serverless异步任务系统的过程。Serverless多租户架构下,异步调用请求首先到达系统的API网关,API网关将接收到的异步请求放入异步队列进行托管;API网关是一个无状态的架构设计,可以支持负载均衡和动态扩展允许。简单的异步任务请求托管,在实际系统实现中,不仅需要考虑租户之间的请求隔离,还需要考虑同一租户下不同功能之间的隔离需求;结合客观的请求隔离需求和请求处理要求的实时性,以及平衡队列资源使用成本,我们设计了一个包含多种类型队列(Queue)并支持动态回收的队列管理系统。隔离成本之间的平衡。这些队列模型包括账户粒度的队列模型、函数粒度的队列模型、多账户共享维度的队列模型;账户粒度的队列作为基本的执行保障。当队列中的某个功能请求执行异常时,可能会影响到其他功能请求,它会为其动态分配一个功能粒度队列,并将与功能相关的请求路由到专用队列进行处理;同时,如果对应的函数长时间没有请求,经过一定时间后,之前分配的队列资源会被动态回收,实现队列资源的高效利用。除了定义多种类型的队列模型,面对任务队列的切换,系统提供了任务请求的动态路由能力,可以自动将请求路由到不同类型的队列中,分发到不同的Partition中进行快速执行。解决NoiseNeighbor问题或请求负载不均导致消费积压导致消费延迟的问题。可能有同学会疑惑,为什么不一开始就给每个函数分配一个独立的请求队列呢?在云计算环境中,队列本身就是一种资源。给每个账号下的每个函数分配一个Queue资源,貌似彻底解决了请求隔离的问题。由于队列系统所能提供的函数和队列的量级是不相等的。考虑到下游系统的具体实现,结合底层满足实时消费处理逻辑,一个函数可能需要分配多个队列资源,并行消费多个队列来满足请求处理的实现需求。从实际角度来说,不仅要考虑Queue的分配性能,还要考虑Queue资源分配对下游系统的影响,以及大量Queue资源本身的管理成本;由于功能不同,为每个功能保留一个队列的成本也很大。负载不同,调用频率不同。为其分配一个独立的Queue在一定程度上是一种资源浪费。与Queue密切相关的后端消费逻辑也会带来大量系统资源的无谓消耗。对于无服务器系统来说,这些都是非常巨大的系统资源浪费。讨论完请求托管的底层设计逻辑,我们再进一步说明异步请求处理环节的流控策略。流量控制主要包括两部分。一是任务请求消费的动态负载能力,主要是Receiver能力的动态扩缩容;另一部分是后端任务执行调度的反馈能力。结果返回给Receiver,然后通过调整Receiver获取任务请求的速率,最终适应系统的后端资源,达到平衡。在具体实现上,系统采用了AIMD的反馈控制算法,即和声增加,乘数减少。该算法可以在Serverless的高频请求或多租户架构下实现更细粒度的控制。整个过程可以把Receiver和Invoker看成一个Pool。通过结合PoolSize的线性增长和遇到后端消费能力不足的负反馈时PoolSize的乘法衰减,可以将PoolSize动态收敛到与后端处理能力相匹配的大小。实现系统流控管理,避免上游请求不断获取对下游资源调度的影响,避免极端情况下后端资源调度问题导致系统饿死。在Job/Task模式下,业务需要跟踪Job和Task请求的执行状态。同时,客户对任务执行、任务暂停、取消、任务去重等高级管理也有一些要求。我们将其添加到Serverless异步任务的基本框架中。介绍了任务执行状态机的设计。通过引入状态机,可以对各个任务进行完整的状态跟踪,可以基于状态跟踪对任务执行进行细粒度控制,也可以基于状态控制实现异步处理的高级操作。例如,任务删除、恢复、去重、状态跟踪等高级任务管理功能,也能更好地反映任务生命周期的运行情况。一个任务处理系统不仅需要帮助客户完成任务的请求和执行,还需要注意任务执行过程中的调试或者任务执行状态和各种执行指标的查询。Serverless系统为客户提供了非常完善的可观察性能力,包括任务请求处理、任务执行时间等,同时也提供了任务执行请求列表的查询。用户可以通过请求ID登录执行上下文。为用户提供接近传统操作习惯的过渡;此外,Serverless系统实现了任务执行过程中生命周期各个阶段的耗时展示,为用户提供从请求到执行的完整跟踪能力。3Serverless异步任务处理系统的更大价值在Serverless异步任务处理系统中,用户请求首先通过网关写入异步队列。异步队列本质上是一个MQ,而异步任务处理系统本质上是一系列的分布式消费策略,构建一个完整的Producer-Consumer模型,最终完成队列中每一个请求的消费;进一步抽象出这样一个系统模型,除了消费函数计算本身的异步请求,对于任何一个MQ系统,都可以构建这样一个通用的消费处理层,意味着客户不需要关注系统的实现逻辑消费本身,而只需要为消息本身提供业务处理逻辑;EventBridge与FunctionComputing的深度融合,正是通过这种系统化的方式。消息消费和消息处理的逻辑分离,就像异步任务系统一样,最终实现serverless消息处理。根据新的Serverless消息架构,用户不需要自己去实现消费端的实现逻辑,也不需要关注和担心负载均衡、流量管理等与消费相关的分布式系统问题。对于消息的业务逻辑和下游数据状态的变化,客户只需要使用函数计算即可快速实现自己的业务逻辑,从而达到快速搭建业务系统的目的。这也是Serverless在面向消息的场景下可以为客户提供的一个新选择。具体实现上,底层基于EventStreaming模式。消费组件直接从消息源拉取消息,直接投递给目标函数,无需中间BUS层转储,实现消息的高效处理;整体架构实现了有状态的消息消费逻辑。与无状态消息处理逻辑分离。功能计算系统以其灵活的扩展性和丰富的链接能力,可以快速帮助客户构建自己的业务系统;当然这也对客户业务系统的构建提出了很多要求,比如需要遵循函数式编程范式。开发需要遵循函数计算的运行方式。整体来看,客户需要基于Serverless架构对业务系统进行改造适配。除了微观层面提供的敏捷开发和弹性扩展能力,我们认为函数式计算系统真正的价值在于其整体的系统原子化能力,可以作为开箱即用的扩展宏观层面的公有云环境下的客户系统。让企业系统架构享受到函数计算带来的资源弹性和弹性扩展能力。为了帮助企业利用Serverless系统的原子化能力,实现业务系统的扩展,我们在Serverless接入和Serverless执行环境的支持方面,实现了更简单的接入方式。在请求提交层面,函数计算提供了HTTP访问方式。客户只需在自己的系统中集成函数提供的URL,即可将任务提交至公有云环境中的函数计算引擎。同时,函数计算基于EventBridge构建了通用的PaaS事件驱动能力。客户业务系统可以将相关事件传递给通用基础设施,然后通过EventBridge触发业务逻辑的执行。在对业务系统的运行时支持方面,Serverless提供了多种接入方式,比如支持传统自定义图片的运行。客户镜像不需要任何修改,只需要简单的配置,就可以将客户的任务和相关镜像托管在函数计算上,实现业务系统的快速接入。系统灵活、快速的扩展能力,正是当前云原生架构所需要的。追求的目标。
