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作为配置容器,几乎所有的构建需要从配置类获取配置项,这里不显示关联关系
- 用户命令行执行kubernates-session.sh,主入口是KubernetesSessionCli main
2.ClusterClientServiceLoader SPI机制载入ClusterClientFactory,k8s环境下实现类是KubernetesClusterClientFactory
- 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构建和启动
-
首先更新配置,主要是对外端口,更新为固定的,支持对外Service通讯
-
构建
KubernetesJobManagerParameters,该类封装Configuration和ClusterSpecification,为获取参数提供便利
- 构建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分析
- 最后客户端调用
createClusterClientProvider返回ClusterClient
8 运行时
运行时提供了Flink作业运行过程依赖的基础执行环境,包含Dispatcher、ResourceManager、JobManager和TaskManager等核心组件,本节分析资源相关运行时组件构建和启动。
flink没有使用spring,缺少ioc的构建过程相当复杂,所有依赖手动关联和置入,为了共享组件,flink使用了很多中间持有共享组件的中间对象。
8.1 场景
8.2 构建和启动flink master组件
部署集群通过flink kubeclient向k8s集群管理提交flink master的Deployment,触发flink master构建和启动
上图是构建和启动的交互图,参看《构建作业管理器部署规格》的CmdJobManagerDecorator设置了初始容器脚本和参数,集群初始入口ClusterEntryPoint
ClusterEntryPoint设置为
KubernetesSessionClusterEntrypoint
2.KubernetesSessionClusterEntrypoint继承SessionClusterEntrypoint,只重新实现createDispatcherResourceManagerComponentFactory方法,设置ResourceManagerFactory为KubernetesResourceManagerFactory,就是说集群初始化逻辑与其他session集群区别不大
-
经过容错日志,插件文件系统初始化,进入ClusterEntrypoint的runCluster,该方法主要做两个事,initializeServices 和
DispatcherResourceManagerComponent -
initializeServices构建基础服务,Rpc服务,Jmx服务,ha服务,blob服务,metics等
5.DispatcherResourceManagerComponent运行时组件,高可用组件的初始化/启动;同时也是持有者,用于后面关闭和清理
8.3 构建和启动任务管理器
构建和启动任务管理器是申请资源的一部分,按请求新worker的延申,类型分属于运行时一部分。
- createTaskManagerPod与10.2 新建作业管理组件类似,CmdTaskManagerDecorator,装饰器实现了pod装饰,装饰主容器,设置shell执行命令
设置执行脚本
KUBERNETES_TASK_MANAGER_SCRIPT_PATH= "kubernetes-jobmanager.sh"
主入口
KubernetesTaskExecutorRunner main方法
- 任务管理器启动比较简单,主要启动rpc服务和高可用组件,高可用触发9.5 注册任务管理器/报告资源
9 资源
本章分析资源管理的场景,服务级实现;核心数据流,资源槽从新增,报告,匹配,分配,到释放的完整生命周,详细了解每个场景下资源槽的状态 和型态 , 型态指资源类结构,类直接转换,状态属性,存储。
9.1 场景
资源处理有++声明式处理资源++ 和++细粒度处理资源++ 是两个实现,两者不是并行的两种实现策略,声明式是资源申请和分配方式,粒度是指资源分割方式,细粒度按需可变的资源,粗粒度是固定的资源,本文只分析++声明式粗粒度处理资源++
9.2 申请和分配资源(simple allocator)
用户提交作业,++分发器++ 接收并分发作业到**++作业管理器++** ,**++调度器++**确定所需资源,申请资源,检查当前可用资源是否足够,如果不足,请求新资源,动态增加资源;若足够,分配资源给任务。
分配还有另一个实现,slot sharing,有比较复杂的资源分配策略,分配策略跟本文主题无关,因此选了比较简单simple allocator
9.2.1 服务分析
DeclarativeSlotPoolBridge桥接DeclarativeSlotPool,声明式资源池,真正处理资源,用声明式SlotPool实现SlotPool,为了简化描述,描述不区分DeclarativeSlotPoolBridge和DeclarativeSlotPool
-
**++调度器++**调用PhysicalSlotProvider的allocatePhysicalSlot分配资源
-
allocatePhysicalSlot首先tryAllocateFromAvailable,从当前可用资源分配;若当前可用资源不够9.3 请求新资源
-
tryAllocateFromAvailable调用DeclarativeSlotPoolBridge的
getAvailableSlotsInformation获取资源池的可用资源,其实际最终调用AllocatedSlotPool的getFreeSlotsInformation并组装为SlotInfoAndResources,该类组合了SlotInfo,分配信息;ResourceProfile,资源信息
-
SlotSelectionStrategy选择策略在可用资源选择一个最合适的,目前基于位置策略
-
选出最合适的资源后,PhysicalSlotProvider调用DeclarativeSlotPoolBridge的allocateAvailableSlot分配资源
-
DeclarativeSlotPoolBridge的allocateAvailableSlot分配资源,该方法调用DeclarativeSlotPool的
increaseResourceRequirementsBy增加资源请求(声明),该方法触发异步处理资源请求,9.2.21深入分析
-
最后保留资源,真正的分配在处理资源请求,保留资源AllocatedSlotPool的reserveFreeSlot登记未已分配资源AllocatedSlot
-
最后调整资源,保留不一定是最终分配,最终分配后调整实际资源情况
9.2.1.1 notifyNewResourceRequirements
最后分析一下
notifyNewResourceRequirements
notifyNewResourceRequirements类型Consumer,函数方法
图1
上图是
notifyNewResourceRequirements设置和调用的方法,函数是怎么设置?
图2
图1是图2的 connect调用,设置Service
设置方法是哪里调起?
ResourceManagerLeaderListener监听**++资源管理器++**选主,获取新主节点的地址
ResourceManagerLeaderListener通知JobMaster,调用JobMaster的
notifyOfNewResourceManagerLeader方法
notifyOfNewResourceManagerLeader启动rpc(重新)连接
- 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,触发**++任务管理器++**部署,任务管理器启动后报告新的资源。
-
**++检查资源声明++**是9.2请求新资源的延申,判断需要增加资源时调用requestNewWorker
-
requestNewWorker调用ResourceManagerDriver的requestResource方法,k8s环境下,ResourceManagerDriver的实现
KubernetesResourceManagerDriver,requestResource使用kubeclient向k8s集群管理发起《构建和启动任务管理器》,任务管理器启动后,9.5 注册任务管理器/报告资源
9.5 注册任务管理器/报告资源
++任务管理器++ 启动后注册到**++资源管理器++**,报告自身资源,资源通过这个方式新增的
9.5.1 服务分析
- ++任务管理器++ 启动,同时启动高可用组件,触发
ResourceManagerLeaderListener监听机制,注意,ResourceManagerLeaderListener有两个,一个是**++作业管理器++** ,一个是**++任务管理器++**,这里毫无疑问用任务管理器相关的那个
ResourceManagerLeaderListener调用TaskExecutor的notifyOfNewResourceManagerLeader方法
notifyOfNewResourceManagerLeader方法使用RegisteredRpcConnection连接到**++资源管理器++**
-
RegisteredRpcConnection连接完成后,触发事件onRegistrationSuccess,onRegistrationSuccess调用**++资源管理器++**的sendSlotReport(rpc)方法报告资源
-
ResourceManager的sendSlotReport方法,调用SlotManager注册**++任务管理器++**和登记资源
-
最后采用延时异步方式执行《检查资源请求》,登记新资源,触发处理资源请求
9.6 请求使用资源(request slots)/提供资源(offer slots)
++调度器++ 申请和分配资源,匹配了合适的空闲资源,++资源管理器++ 请求资源所属的**++任务管理器++** 使用资源,**++任务管理器++**确认提供资源
资源请求使用和提供两步操作,++资源管理器++ 不直接使用资源,主要让资源使用情况放在**++任务管理器++** ,++资源管理器++ 下线, 选出新**++资源管理器++** master,**++任务管理器++**重新注册,恢复资源使用情况
9.6.1 服务分析
-
++调度器++ 分配资源完成,向资源所在的**++任务管理器++**TaskExecutor发出使用请求requestSlot
-
TaskExecutor调用allocateSlotForJob,登记资源使用jobId, slotId, allocationId, resourceProfile, targetAddress
-
TaskExecutor rpc-offerSlots通知JobMaster,确认提供资源
-
JobMaster转交SlotPool的offerSlots处理,同样,最终处理是DeclarativeSlotPool
-
DeclarativeSlotPool的
matchOfferWithOutstandingRequirements匹配offerSlot与未完成的资源请求,构建AllocatedSlot
- 最后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
10 flink kubeclient
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等
-
KubernetesStepDecorator装饰器,装饰器列表实现责任链模式,装饰用模板构建的FlinkPod,包括主容器和其他容器,增加其特性,用户使用此机制定制pod,后面几章分析几个典型的装饰器
-
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要点
-
模板构建初始的FlinkPod,拥有初始的完整的特性和属性
-
可配置的/可扩展的装饰器增加FlinkPod的特性和属性,以及相应的资源,ConfigMap,Service等
-
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