Azkaban容器化 - 设计文档

原创
2021/08/04 12:04
阅读数 519

本文翻译自Azkaban官网文档 Azkaban Containerized Executions - Design Doc

作者/关键贡献者: Arvind Pruthi , Janki Akhani , Shardool , Deepak Jaiswal , Aditya Sharma , Abhishek Nath


老架构(裸金属架构)背景/概览

Azkaban老架构图

  • 每一套Azkaban集群都包含如下组件:一个web server,一组部署在物理机上的executor server,一个mysql(用于保存job状态和历史记录)
  • 每一个executor server大约可以并行执行10个Flow(任务流),具体取决于每个Flow的消耗的资源
  • executor server定期(一般1秒)从mysql拉取处于待执行状态的Flow,mysql相当于是一个队列

Azkaban Executor Server的职责

分发任务

  • Executor Server定期从mysql拉取flows
  • 构建flow:解析所有的配置、在内存中构建一个图、下载依赖文件、分配计算资源(线程池、执行目录等)
  • 触发调度

调度

  • 为了保证任务并行执行,每一个executor server为每一个flow都维护了一个独立的线程池
  • 从hadoop name node获取hadoop tokens以便提交YARN应用
  • 每一个job都是用admin账号独立加载
  • 在内存中维护flow的状态机,并及时更新到mysql中,最后把flow产生的日志都写到mysql中

管理Flow

executor server对外暴露AJAX API,提供暂停、强制停止、恢复等操作,超过10天的flow会被强制停止。

管理日志

AJAX API支持流式日志,可以实时观察执行中的flow/job,当flow/job结束后,所有的日志都会以15MB每块的大小保存到数据库中。

部署

  • 部署executor server,先把新版代码准备好,启动前会先完成一些必要的测试,以便验证环境符合预期
  • 测试通过后,把executor server置为不可用模式,确保不会从数据库拉取flowparticular executor除外)
  • 启动新版代码,状态变为可用,恢复任务的执行

裸金属架构的问题

互相影响(无资源隔离)

Azkaban支持多种Job类型,也允许用户自己上传代码,所以很容易发生部分任务占用过多的资源(CPU、内存、磁盘),进而拖垮整个executor server,影响此server上的所有任务

弹性伸缩/维护问题(僵化的架构)

网站可靠性对弹性伸缩能力具有强烈的诉求,数十年前的架构就已经存储了。但是裸金属架构并不能从最近的新技术上获益,这在云计算领域已经司空见惯了。

缺少金丝雀发布系统

Azkaban的executor server是所有计算的门户,除了它自身的功能代码、配置、任务类型之外,还屏蔽了hadoop、安全管理器、spark等基础计算设施。当前缺少金丝雀机制以支持细粒度的新功能验证。 根据Azkaban在Linkedin的使用的经验看,在缺少合适的金丝雀系统的时候,每次滚动发布代码是多么的痛苦。

无视YARN内部的任务队列

Azkaban有自己的任务队列和分发机制,这样可以最大限度的发挥executor server的能力,但是它自己的队列与YARN的队列并不匹配,这经常导致YARN集群过载。

发布的问题

发布过程中的环境验证环节可能要持续10天,在这期间executor server都是不可用的,并且CPU和内存是闲置的。一次发布如果有问题,需要executor server带病运行的情况下,不断的尝试修复,可能导致GC暂停或者OOM,并且会污染其他的指标。

容器化的关键需求

  1. Azkaban的web server动态的为每一个flow创建一个容器,也就是为每一个flow提供一套完全独立的运行环境。
  2. 快速响应激增的资源需求(可伸缩的架构)
  3. 提供一种机制以支持Azkaban各个组件各自独立进化
    • 把发版的控制权交给对应的用户:运行平台、Azkaban本身、用户Job
    • 让用户自己选择Azkaban或者JobType的版本(在更新基础设施的时候尤其有用)
  4. 提供一套垂直的金丝雀系统以支持Azkaban/jobtypes和运行平台完全控制各自的代码更新

未来的扩展

  1. 为多个组件开发细粒度的金丝雀系统以支持各自独立发版

架构概览

容器化架构概览

  1. Azkaban采用Disposable Container(一次性容器)的模式,这意味着每当flow被调度之前都会创建一个新的POD,并且在flow结束之后销毁。
  2. 资源隔离体现在flow级别(而非job),jobssubflows都是flow的一部分;Job级别的资源也探索过,但是最终放弃了:
  • 它会极大的破快原来的架构,为了实现job级别的资源隔离,大部分的代码都需要重写;
  • 为每一个job创建一个pod会造成过多的资源消耗,还有一种做法是在一个POD里面包含多个容器,但是这也会导致大部分flowjob相关的代码被重写;也许未来会重新考虑这个设计;
  1. 创建POD的时候使用默认的cpu、内存资源,也可以通过参数指定需要申请的资源
  2. 在这样的设计下,web server必须部署在k8s之外,这样做并不妨碍它与flowlog之间的通信,它们之间的通信通过Ingress Controller实现,这样就不需要导出Flow的POD了;
  3. 为了实现上述第三点需求,flow的pod的执行环境必须动态创建:
  • 在任务分发的环节,会提供动态选择组件版本的功能,以便提供executor server的运行环境
  • 一系列的容器初始化工作将通过众多组件的不同版本的组合来完成
  • 动态选择的功能可以用来实现组件的金丝雀发布
  • 需要一些Admin API来完成镜像的管理工作

详细设计

镜像管理

  • 使用docker镜像来创建flow的执行环境,为了实现上述第三个需求,要使用预制的container模板来创建POD,下文的分发逻辑一节会详述;
  • Azkaban的运行环境由以下依赖组成:
依赖类型 描述
平台依赖 Hadoop、Hive、Spark、Pig、Dali、Ksudo等
Azkaban核心 Azkaban代码包、配置、安全项,由Azkaban管理
JobTypes JobType开发人员开发的代码/配置,由Azkaban管理,如KafkaPushJob, SparkJob
  • Azkaban核心在基础镜像(RHEL7)上加一层,形成Azkaban基础镜像
  • 其他的平台依赖、JobTypes各自在Azkaban基础镜像之上新增独立的层。为了保持镜像体积小,节约下载时间,可以使用busybox或者alpine技术来实现
  • 有的开发者的job-types镜像需要特别定制,不依赖Azkaban。比如Kafka Push Job
FROM container-image-registry.mycorp.com/rhel7-base-image/rhel7-base-image:0.16.9

ARG KPJ_URL=https://artifactory.mycorp.com/kafka-push-job/kafka-push-job/0.2.61/kafka-push-job-0.2.61.jar

RUN curl $KPJ_URL --output ~/kafka-push-job-0.2.61.jar
  • 每个job-type都会基于一个公共的预制镜像,这个预制镜像会把所有的代码包和配置文件都放到容器的外部卷上,此外部卷也会被挂载到应用容器(基于Azkaban基础镜像
  • job-type开发者使用镜像管理API构造job-type镜像,构造出来的镜像可以作为默认的job-type镜像,flow的开发者可以使用DSL指定job-type镜像的版本
  • flow执行的过程中使用version-setversion-number来唯一标识它的依赖的组件的状态;这也有助于在测试环境复现失败的flow,便于排查问题

镜像管理API

为了让众多的镜像开发者管理镜像的生命周期,我们开发了一批Admin API

  • 记录镜像类型和它们的开发者
  • 记录已存在的镜像类型的新版本
  • 为以注册的镜像版本创建/更新热身计划

API使用流程图

API使用流程图

详见 imageMgmtAPI.rst 文件

为了实现这些API,镜像的元数据必须及时更新到数据库中,下面是镜像相关的数据库ER图:

数据库ER图

分发逻辑

分发逻辑

  1. 当一个flow准备执行时,Azkaban Web Server会把它的状态标记为READY,并且把它队列中(execution_flows表)
  2. QueueProcessor(任务处理类)会根据优先级和提交的时间从数据库拉取待执行的flow,此时的状态是DISPATCHING,为防止K8S创建大量的容器,这里需要有限流机制,然后flow经过如下的分发过程:
    • 获取K8S的配置,安全认证
    • 根据jobtypes读取image_ramp_upimage_versions两个表,它们记录了本次任务应该使用哪个镜像以及版本

状态流程图

状态流程图

kubernets的安全性

初始化容器

初始化k8s pod

运行Flow的容器

Ingress控制器

日志

状态页面

使用裸金属架构解决上述问题如何?

在kubernets上debug Azkaban

待解决事项

  1. 搁置了通过参数指定flow使用的镜像的版本
  2. 搁置了通过参数设置版本
  3. 搁置了通过参数指定flow容器需要的CPU和内存
  4. debug问题
  5. 更多关于配置的技巧
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
1
分享
返回顶部
顶部