大厂的工程效能CI/CD之流水线引擎的建设实践(下)
本帖最后由 草帽路飞UU 于 2022-10-27 15:57 编辑4.2 资源池划分设计
1)整体方案
我们采用多队列的设计,结合标签建立作业队列与资源池的匹配关系,以保障不同队列资源的有效划分,在出现队列积压、资源池故障、无可扩资源等情况时,最大限度地降低影响范围,避免所有作业全
局排队等待的现象。
图9 资源池架构
2)模型关系
图10 资源池模型对象
作业队列与标签的关系:队列与标签采用1对1的关系,降低业务理解和运维成本。
当队列积压时,能快速定位到某个标签没资源了。
标签资源不足时,也能快速判断影响的具体队列情况。
标签与资源池的关系:标签和资源池采用多对多的关系,主要从资源整体利用率和对核心队列的资源可用性保障考虑。
对于一些作业量较少的队列,单独分配一个资源池会造成大部分时间资源是空闲状态,资源利用率低。我们通过给资源池打多标签的方式,既保证了队列有一定的资源配额,同时也能处理其他标签的作
业,提高资源的利用率。
对于核心场景的队列,通常标签资源会分配到多个资源池上,保证资源的一定冗余,同时也降低单个资源池整体故障带来的影响。
3)标签设计
标签的目的是建立资源(池)与作业(队列)的匹配关系。在设计上,为便于标签管理和后期维护,我们采用二维标签的形式,通过组件和流水线两个维度,共同决定一个作业所属标签及对应的资源。
第一维度:组件维度,对资源做通用划分。结合组件的业务覆盖情况、作业执行量、对机器和环境的特殊要求(如SSD、Dev环境等),对需要独立资源的组件进行打标,划分出不同的公共资源池(每个
公共资源池执行一类或多类组件作业),在引擎层面统一分配,保证所有作业都有可正常运行。
第二维度:流水线维度,根据业务场景进行划分。结合业务对资源隔离/作业积压敏感度的诉求,按需进行划分。有些希望资源完全独立的业务,会从所有的公共资源池进行切分;有些仅对部分核心场景
下的资源需要保障,根据链路上涉及的组件,选择性地从部分公共资源池进行划分,实现业务隔离和资源利用率的平衡。
注:每个维度都会设一个other的默认值用来兜底,用于处理无资源划分需求的场景。
图11 标签设计
4)队列拆分设计
根据作业所属标签不同拆分出多个队列,保证每个队列的独立性,降低作业积压的影响范围。整个拆分过程可以分为入队和出队两部分:
入队过程:通过计算作业在组件和流水线两个维度的属性值,来确定作业对应的标签。结合模型关系中标签与队列(1对1)的关系,为每个标签按需创建一个队列,存储该标签作业,不同队列间作业做排
他处理,简化出队的实现复杂度。
出队过程:队列拆分后,因为标签和资源池(多对多)的关系,资源池的一次作业拉取请求往往会涉及多个队列。出于拉取效率的考虑,采用轮询的方式依次对单队列进行出队操作,直到达到该次请求的
作业数上限或所有可选队列为空时返回结果。该方式可以避免同时对多个队列加锁,并且在前置环节会对多标签进行随机排序,降低多个请求同时操作一个队列的竞争概率。
图12 队列拉取设计
4.3 组件分层设计
1)分层架构
图13 组件架构设计
业务层:引入适配层,满足组件开发中多样化的需求场景,同时避免上层差异污染到下层。
系统交互层:设立统一的流程标准,保证引擎和组件交互过程的一致性,便于统一处理非功能性的系统优化。
执行资源层:提供多种资源策略,向上层屏蔽不同资源类型的差异。
2)标准的交互流程设计
在系统交互层,组件与引擎交互的过程中,有两个环节是确定的,①组件作业的状态机流转,这涉及到组件执行的整个生命周期管理,若允许存在不同的状态流转关系,整个管理过程会十分混乱;②引擎
对外提供的接口范围,从服务间解耦的角度,对外提供的接口主要是组件作业维度的接口操作,不应该耦合任何组件内部的实现细节。
结合作业状态机 + 引擎提供的接口,确定了组件执行基本的系统交互流程。利用模版模式,抽象出init()、run()、queryResult()、uploadArtifacts() 等必要方法供业务实现,整个交互流程则由系统统一
处理,业务无需关心。
图14 组件标准流程设计
3)扩展基础能力
组件执行除了正常的执行流程外,随着业务场景的丰富,还会涉及组件中止、回调(人工审批场景)等操作,这些操作的引入势必会改变原先的交互流程。为了不增加额外的交互复杂度,在拉取作业环
节,增加作业的事件类型(运行、中止、回调等事件),Worker根据拉取到的不同事件,执行相应的扩展逻辑。同时,引入新的扩展也不会影响到已有的交互流程。
图15 组件扩展能力设计
基于上述扩展,我们可能更好地将一些通用能力下沉到Daemon Thread层。如结果查询流程,通过守护线程的方式,取消了原先同步等待的查询限制,这对于需要异步化处理的场景(如组件作业逻辑已执行
完,仅在等待外部平台接口返回结果)可以提前释放资源,提高资源执行的利用率。并且,当执行资源故障重启后,结果查询线程会自动恢复待处理异步作业。这部分能力的支持在业务层是透明的,不改变整
个交互流程。
4)引入适配器
业务虽可以通过必要方法完成自定义组件,但这些方法过于基础,业务在一些特定场景下实现成本较高。如对于组件支持Shell的脚本化调用,业务其实仅需提供可执行的Shell即可,通用约定的方式,其
他必要方法的实现都可以交由系统完成。
针对业务个性化的处理,采用适配器模式,通用引入不同Command(ShellCommand、xxCommand)来默认实现特定场景下的必要方法,降低业务的开发成本。同时,保持系统侧流程的一致性,通过
动态注入 Command的方式,防止对业务个性化处理的耦合。
图16 组件适配器设计
5)效果
目前已支持Shell组件、服务组件、容器组件等多种接入方式,平台上已提供数百个组件,组件开发方涉及数十个业务线。组件库覆盖源码域、构建域、测试域、部署域、人工审批域等多个环
节,打通了研发过程所涉及的各个基础工具。
图17 组件库
5. 后续规划
借助Serverless等云原生技术,探索更轻量、高效的资源管理方案,提供更精细化的资源策略,从资源的弹性、启动加速、环境隔离三个方面为业务提供更优的资源托管能力。
面向组件开发者,提供从开发、上线到运营的一站式开发管理平台,降低组件开发、运营成本,使更多工具方、个人开发者能参与其中,共同打造丰富多样的业务场景,形成良性的组件运营生态。
页:
[1]