flink原理源码分析(一) 集群与资源@k8s

1 简介

集群和资源模块提供动态资源能力,是分布式系统关键基础设施,分布式datax,分布式索引,事件引擎都需要集群和资源的弹性资源能力,提高扩展和作业处理能力。本文分析flink的集群和资源的k8s模块,深入了解其设计原理,为开发自有的集群和资源组件做技术准备, 同时涉及作业管理器,slot管理,不深入调度器。

本文分析基于flink 1.17版本,不同版本代码差异比较大

2 关键词

作业管理器

资源管理器

任务管理器

3 参考资料

flink官方网站 https://flink.apache.org/

4 flink整体架构

flink原理源码按板块逐一分析,本文分析**++集群和资源++**

API板块 Table&SQL, DataStream,DataSet将被丢弃

作业构建和转换板块

作业提交和接收 client,作业打包,提交,接收和分发

作业调度板块 执行图(Execution Graph), 调度器,作业管理器

作业执行板块 高可用,容错,状态,作业执行

5 flink运行架构

运行架构,按调用顺序展示flink集群启动,作业提交处理组件互动

总体上,集群是mater-worker架构,上图是flink的抽象架构,一个优秀架构可以抽象,第六章介绍架构"具体" k8s实现

6 flink@k8s运行架构

++作业管理器++ 得到**++任务管理器++**提供的资源(slot),启动task,资源申请完成。

7 启动集群

7.1 场景

下面详细分析各用例

7.2 启动k8s集群

k8s集群支持session和application模式,job模式将会被废弃,本文分析session模式集群

Configuration作为配置容器,几乎所有的构建需要从配置类获取配置项,这里不显示关联关系

  1. 用户命令行执行kubernates-session.sh,主入口是KubernetesSessionCli main

2.ClusterClientServiceLoader SPI机制载入ClusterClientFactory,k8s环境下实现类是KubernetesClusterClientFactory

  1. ClusterClientFactory是ClusterClient工厂,首先创建ClusterDescriptor集群描述,该类负责部署集群,最终返回ClusterClient,k8s环境下实现类是

KubernetesClusterDescriptor

4.KubernetesClusterDescriptor新建集群规格ClusterSpecification,该类不是针对k8s,定义了flink master和**++任务管理器++** 的内存容量等技术参数,通用于容器类的集群;

KubernetesSessionClusterEntrypoint类型设置为ENTRY_POINT_CLASS参数,后面《部署集群》使用到

5.KubernetesClusterDescriptor的deploySessionCluster部署k8s集群,参看《部署集群》用例,最后返回ClusterClient,用于后续提交作业和其他集群操作

7.3 部署集群

部署集群是启动的第二步,

KubernetesClusterDescriptor的deploySessionCluster方法的一部分,构建部署规格,flink kubeclient提交到k8s集群管理器,触发flink master构建和启动

  1. 首先更新配置,主要是对外端口,更新为固定的,支持对外Service通讯

  2. 构建

KubernetesJobManagerParameters,该类封装Configuration和ClusterSpecification,为获取参数提供便利

  1. 构建FlinkPod,首先载入pod模板构建KubernetesPod,KubernetesPod是一个包装了k8s Pod对象的Resource类;构建FlinkPod,定义了mainContainer ,podWithoutMainContainer,其中主容器固定名称,用于运行**++作业管理器++** ,++任务管理器++,其他容器运行相关的资源,如ConfigMap,Service等,详细分析参考10 flink kubeclient

4.KubernetesJobManagerFactory《构建作业管理器部署规格》构建部署规格,Fabric8FlinkKubeClient使用部署规格《新建作业管理器组件(flink master)》部署flink master组件,两用例在10 flink kubeclient分析

  1. 最后客户端调用

createClusterClientProvider返回ClusterClient

8 运行时

运行时提供了Flink作业运行过程依赖的基础执行环境,包含Dispatcher、ResourceManager、JobManager和TaskManager等核心组件,本节分析资源相关运行时组件构建和启动。

flink没有使用spring,缺少ioc的构建过程相当复杂,所有依赖手动关联和置入,为了共享组件,flink使用了很多中间持有共享组件的中间对象。

8.1 场景

部署集群通过flink kubeclient向k8s集群管理提交flink master的Deployment,触发flink master构建和启动

上图是构建和启动的交互图,参看《构建作业管理器部署规格》的CmdJobManagerDecorator设置了初始容器脚本和参数,集群初始入口ClusterEntryPoint

  1. 容器初始执行kubernetes-jobmanager.sh

ClusterEntryPoint设置为

KubernetesSessionClusterEntrypoint

2.KubernetesSessionClusterEntrypoint继承SessionClusterEntrypoint,只重新实现createDispatcherResourceManagerComponentFactory方法,设置ResourceManagerFactory为KubernetesResourceManagerFactory,就是说集群初始化逻辑与其他session集群区别不大

  1. 经过容错日志,插件文件系统初始化,进入ClusterEntrypoint的runCluster,该方法主要做两个事,initializeServices
    DispatcherResourceManagerComponent

  2. initializeServices构建基础服务,Rpc服务,Jmx服务,ha服务,blob服务,metics等

5.DispatcherResourceManagerComponent运行时组件,高可用组件的初始化/启动;同时也是持有者,用于后面关闭和清理

8.3 构建和启动任务管理器

构建和启动任务管理器是申请资源的一部分,按请求新worker的延申,类型分属于运行时一部分。

  1. createTaskManagerPod与10.2 新建作业管理组件类似,CmdTaskManagerDecorator,装饰器实现了pod装饰,装饰主容器,设置shell执行命令

设置执行脚本

KUBERNETES_TASK_MANAGER_SCRIPT_PATH= "kubernetes-jobmanager.sh"

主入口

KubernetesTaskExecutorRunner main方法

  1. 任务管理器启动比较简单,主要启动rpc服务和高可用组件,高可用触发9.5 注册任务管理器/报告资源

9 资源

本章分析资源管理的场景,服务级实现;核心数据流,资源槽从新增,报告,匹配,分配,到释放的完整生命周,详细了解每个场景下资源槽的状态型态 , 型态指资源类结构,类直接转换,状态属性,存储。

9.1 场景

资源处理有++声明式处理资源++ 和++细粒度处理资源++ 是两个实现,两者不是并行的两种实现策略,声明式是资源申请和分配方式,粒度是指资源分割方式,细粒度按需可变的资源,粗粒度是固定的资源,本文只分析++声明式粗粒度处理资源++

9.2 申请和分配资源(simple allocator)

用户提交作业,++分发器++ 接收并分发作业到**++作业管理器++** ,**++调度器++**确定所需资源,申请资源,检查当前可用资源是否足够,如果不足,请求新资源,动态增加资源;若足够,分配资源给任务。

分配还有另一个实现,slot sharing,有比较复杂的资源分配策略,分配策略跟本文主题无关,因此选了比较简单simple allocator

9.2.1 服务分析

DeclarativeSlotPoolBridge桥接DeclarativeSlotPool,声明式资源池,真正处理资源,用声明式SlotPool实现SlotPool,为了简化描述,描述不区分DeclarativeSlotPoolBridge和DeclarativeSlotPool

  1. **++调度器++**调用PhysicalSlotProvider的allocatePhysicalSlot分配资源

  2. allocatePhysicalSlot首先tryAllocateFromAvailable,从当前可用资源分配;若当前可用资源不够9.3 请求新资源

  3. tryAllocateFromAvailable调用DeclarativeSlotPoolBridge的

getAvailableSlotsInformation获取资源池的可用资源,其实际最终调用AllocatedSlotPool的getFreeSlotsInformation并组装为SlotInfoAndResources,该类组合了SlotInfo,分配信息;ResourceProfile,资源信息

  1. SlotSelectionStrategy选择策略在可用资源选择一个最合适的,目前基于位置策略

  2. 选出最合适的资源后,PhysicalSlotProvider调用DeclarativeSlotPoolBridge的allocateAvailableSlot分配资源

  3. DeclarativeSlotPoolBridge的allocateAvailableSlot分配资源,该方法调用DeclarativeSlotPool的

increaseResourceRequirementsBy增加资源请求(声明),该方法触发异步处理资源请求,9.2.21深入分析

  1. 最后保留资源,真正的分配在处理资源请求,保留资源AllocatedSlotPool的reserveFreeSlot登记未已分配资源AllocatedSlot

  2. 最后调整资源,保留不一定是最终分配,最终分配后调整实际资源情况

9.2.1.1 notifyNewResourceRequirements

最后分析一下

notifyNewResourceRequirements

notifyNewResourceRequirements类型Consumer,函数方法

图1

上图是

notifyNewResourceRequirements设置和调用的方法,函数是怎么设置?

图2

图1是图2的 connect调用,设置Service

设置方法是哪里调起?

ResourceManagerLeaderListener监听**++资源管理器++**选主,获取新主节点的地址

ResourceManagerLeaderListener通知JobMaster,调用JobMaster的

notifyOfNewResourceManagerLeader方法

notifyOfNewResourceManagerLeader启动rpc(重新)连接

  1. rpc连接后,触发onRegistrationSuccess事件方法,然后

DeclarativeSlotPoolService的

connectToResourceManager方法,而后者即图1,设置Conumer

总结,++请求新资源++ 主要是调用**++资源管理器++**的declareRequiredResources方法,该方法用

ResourceManagerLeaderListener和DeclareResourceRequirementServiceConnectionManager绕一下,是为了适应分布式环境下**++资源管理器++**上线下线,主节点选举后获取新主的地址,重新连接,每次连接完成重新设置ResourceManagerGateway

9.3 请求新资源(request new slots)

请求新资源是9.1 分配资源的延申,当前没有足够的可用资源,调度器请求新的资源

9.3.1 服务分析

类图跟9.2 申请和分配资源基本相同,场景实现由相同的类实现

**1. ++调度器++**在9.11 分配资源没有获得足够可用资源,调用SlotPool的requestNewAllocatedSlot,请求新的资源;这里的SlotPool是DeclarativeSlotPoolBridge桥接 DeclarativeSlotPool实现的SlotPool,实现声明式管理的资源池,下面不区分两者

2. DeclarativeSlotPoolBridge调用

increaseResourceRequirementsBy增加资源请求,触发检查资源请求,参看9.2.2.1深入分析

9.4 请求新worker(require new worker)

请求新worker是**++请求新资源++** 的一部分,检查资源声明判断需要新增资源,向集群管理请求部署新worker,触发**++任务管理器++**部署,任务管理器启动后报告新的资源。

  1. **++检查资源声明++**是9.2请求新资源的延申,判断需要增加资源时调用requestNewWorker

  2. requestNewWorker调用ResourceManagerDriver的requestResource方法,k8s环境下,ResourceManagerDriver的实现

KubernetesResourceManagerDriver,requestResource使用kubeclient向k8s集群管理发起《构建和启动任务管理器》,任务管理器启动后,9.5 注册任务管理器/报告资源

9.5 注册任务管理器/报告资源

++任务管理器++ 启动后注册到**++资源管理器++**,报告自身资源,资源通过这个方式新增的

9.5.1 服务分析

  1. ++任务管理器++ 启动,同时启动高可用组件,触发

ResourceManagerLeaderListener监听机制,注意,ResourceManagerLeaderListener有两个,一个是**++作业管理器++** ,一个是**++任务管理器++**,这里毫无疑问用任务管理器相关的那个

ResourceManagerLeaderListener调用TaskExecutor的notifyOfNewResourceManagerLeader方法

notifyOfNewResourceManagerLeader方法使用RegisteredRpcConnection连接到**++资源管理器++**

  1. RegisteredRpcConnection连接完成后,触发事件onRegistrationSuccess,onRegistrationSuccess调用**++资源管理器++**的sendSlotReport(rpc)方法报告资源

  2. ResourceManager的sendSlotReport方法,调用SlotManager注册**++任务管理器++**和登记资源

  3. 最后采用延时异步方式执行《检查资源请求》,登记新资源,触发处理资源请求

9.6 请求使用资源(request slots)/提供资源(offer slots)

++调度器++ 申请和分配资源,匹配了合适的空闲资源,++资源管理器++ 请求资源所属的**++任务管理器++** 使用资源,**++任务管理器++**确认提供资源

资源请求使用和提供两步操作,++资源管理器++ 不直接使用资源,主要让资源使用情况放在**++任务管理器++** ,++资源管理器++ 下线, 选出新**++资源管理器++** master,**++任务管理器++**重新注册,恢复资源使用情况

9.6.1 服务分析

  1. ++调度器++ 分配资源完成,向资源所在的**++任务管理器++**TaskExecutor发出使用请求requestSlot

  2. TaskExecutor调用allocateSlotForJob,登记资源使用jobId, slotId, allocationId, resourceProfile, targetAddress

  3. TaskExecutor rpc-offerSlots通知JobMaster,确认提供资源

  4. JobMaster转交SlotPool的offerSlots处理,同样,最终处理是DeclarativeSlotPool

  5. DeclarativeSlotPool的

matchOfferWithOutstandingRequirements匹配offerSlot与未完成的资源请求,构建AllocatedSlot

  1. 最后AllocatedSlot放入资源slot分配池AllocatedSlotPool,返回接收的offerSlots给TaskExecutor处理,一部分没有匹配不接收

关于

matchOfferWithOutstandingRequirements(TBD)

9.7 检查资源需求/检查资源声明

检查资源请求/检查资源声明是flink声明式资源管理 的关键方法,上面的资源场景分为两类,++提出资源需求++ 和**++提供资源++**, 检查资源请求/检查资源声明是交汇点,处理资源请求,该分配的分配,该请求新的请求新的资源;检查资源声明,哪些资源可以释放,需要新资源请求新worker。

本章深入分析两方法,上游提出资源需求和下游提供资源的串联,资源状态演变,存储型态

9.7.1 检查资源请求(checkResourceRequirements)

**++检查资源请求++**是真正的分配资源,上面说的分配实际只是请求分配,增加请求

1) 获取作业的未完成资源请求

2) 尝试分配可用资源到作业

之所以尝试,资源变更触发调用检查资源请求,但不一定是增加,可能是无效分配

slotTracker获取所有可用资源,与请求匹配,合适的分配allocateSlot,该方法对应场景9.6 请求使用资源/提供资源

3) 尝试使用待定的资源

待定资源是指申请了新的worker或者将要申请新worker所产生的资源,目前没有物理上的对应资源,通俗说就是先占个"坑",等申请的资源下来填回去

同样,首先匹配现有的待定资源,若还有未分配打开新的待定资源

tryAllocateWorkerAndReserveSlot调用TaskExecutorManager的allocateWorker,预先挖好"坑"

declareNeededResourcesWithDelay方法下节介绍,按需要申请新的worker,增加物理资源

到此还有一个问题,物理资源到位后怎样填"坑"

首先,自然想到9.5 注册任务管理器/报告资源,使用新增资源抵消待定

TaskExecutorManager的registerTaskManager方法

9.7.2 检查资源声明(checkResourceDeclarations)

声明资源,要申请多少资源,可释放多少资源,上一节检查资源请求打开新待定资源,最终调用checkResourceDeclarations,实际申请新worker获得物理资源,为了支持动态/静态资源申请,中间ResourceAllocator转接了一下,这里不详细分析

现有的worker数量-需要的worker数量,大于0,worker多了可以释放;反之,worker少了,需要打开新worker

requestNewWorker参看9.4 请求新worker

ResourceDeclaration怎么来?

主要是计算totalWorkerNum,目前worker总数量

totalWorkerNum = pendingWorkerNum + neededRegisteredWorkers

pendingWorkerNum 待定的slots除以每个worker的slots,向上修正,只多不少

neededRegisteredWorkers是已经注册的worker减去待释放的worker

flink kubeclient是面向flink应用的fabric8 kubeclient的封装,本节分析flink如何封装kubeclient,核心组件是装饰器,资源 和ServiceType,下面通过分析业务**++创建作业管理器组件(createJobManagerComponent)++**了解flink kubeclient

10.1 场景

10.2 新建作业管理器组件

KubernetesJobManagerFactory构建KubernetesJobManagerSpecification

KubernetesJobManagerSpecification有两属性Deployment和accompanyingResources,前者Deployment是k8s资源对象,后者是类型是List<HasMetadata>,用来管理发布的控制器,详情可参考k8s文档;accompanyingResources定义k8s资源对象,如 ConfigMap,Service等

  1. KubernetesStepDecorator装饰器,装饰器列表实现责任链模式,装饰用模板构建的FlinkPod,包括主容器和其他容器,增加其特性,用户使用此机制定制pod,后面几章分析几个典型的装饰器

  2. Fabric8FlinkKubeClient的createJobManagerComponent,请求k8s集群构建和启动flink master组件,输入参数是

KubernetesJobManagerSpecification,其Deployment属性直接用于Fabric8 kubeclient创建Deployment对象

下面分析几个作业管理组件重要的容器装饰器

10.2.1InitJobManagerDecorator

读入配置属性,设置pod的容器

10.2.2CmdJobManagerDecorator

装饰器只实现了pod装饰,装饰主容器,设置shell执行命令

设置执行脚本

KUBERNETES_JOB_MANAGER_SCRIPT_PATH = "kubernetes-jobmanager.sh"

deploymentTarget kubernetes-session或kubernetes-application

10.2.3ExternalServiceDecorator

装饰器构建k8s Service对象

读入ServiceType,flink对应k8s Service的抽象类,实现

buildUpExternalRestService方法,构建k8s Service

10.2.4FlinkConfMountDecorator/PodTemplateMountDecorator

两个装饰器功能相同,构建ConfigMap,非主容器作为存储卷,主容器挂载存储卷

10.3 总结

flink kubeclient要点

  1. 模板构建初始的FlinkPod,拥有初始的完整的特性和属性

  2. 可配置的/可扩展的装饰器增加FlinkPod的特性和属性,以及相应的资源,ConfigMap,Service等

  3. Resource是k8s资源的简单封装;ServiceType是 k8s Service对象的构建器基类

11回顾

最后,本章以运行架构图串联起分析场景

1 7.2 启动k8s集群,7.3 部署集群,10.2 新建作业管理器组件

2 8.2 构建和启动flink mater组件

3 提交作业,N/A

4 分发作业,N/A

5 9.2 申请和分配资源

6 9.3 请求新资源

7 9.4 请求新worker,8.3 构建和启动任务管理器

8 9.5 注册任务管理器/报告资源

9 /10 9.6 请求使用资源/提供资源

12 附录

flink分析系列

Ø 系列(二) 作业提交,接收和分发

Ø 系列(三) 作业执行,高可用,状态,容错

Ø 系列(四) 作业调度

Ø 系列(五) 作业构建和转换

Ø 系列(六) 作业API-DataStream

Ø 系列(七) 作业API-Table&SQL

Ø 其他,内存管理,rpc

相关推荐
登云时刻33 分钟前
Kubernetes集群外连接redis集群和使用redis-shake工具迁移数据(一)
redis·kubernetes·bootstrap
吴半杯1 小时前
gateway漏洞(CVE-2022-22947)
docker·kubernetes·gateway
zmd-zk3 小时前
flink学习(2)——wordcount案例
大数据·开发语言·学习·flink
holywangle3 小时前
解决Flink读取kafka主题数据无报错无数据打印的重大发现(问题已解决)
大数据·flink·kafka
Code_Artist4 小时前
使用Portainer来管理并编排Docker容器
docker·云原生·容器
Eternal-Student4 小时前
【docker 保存】将Docker镜像保存为一个离线的tar归档文件
运维·docker·容器
码农小丘4 小时前
一篇保姆式centos/ubuntu安装docker
运维·docker·容器
灼烧的疯狂6 小时前
K8S + Jenkins 做CICD
容器·kubernetes·jenkins
大数据编程之光6 小时前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
wenyue11217 小时前
Revolutionize Your Kubernetes Experience with Easegress: Kubernetes Gateway API
容器·kubernetes·gateway