news 2026/10/14 3:06:54

Flink SlotManager 分配 Slot 源码深度剖析:从请求接收到状态转换的完整链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flink SlotManager 分配 Slot 源码深度剖析:从请求接收到状态转换的完整链路

前面讲了 SlotManager 的启动流程和 SlotPool 申请资源的源码实现,这篇聚焦 SlotManager 分配 Slot 的源码实现。SlotManager 运行在 ResourceManager 内部,负责管理所有已注册的 TaskManager 和 Slot,接收 SlotPool 的 requestSlot 请求,查找空闲 Slot,标记分配状态,通知 TaskManager 分配,确认分配完成。你有没有想过,SlotManager 收到请求后是如何查找 FREE Slot 的?Slot 状态 FREE → PENDING → ALLOCATED 是如何转换的?无空闲 Slot 时是如何处理的?Slot 选择策略有哪些?这篇从源码级别跟踪 SlotManager 分配 Slot 的完整链路。


一、SlotManager 分配 Slot 整体架构

下面这张图是 SlotManager 分配 Slot 整体架构,包括 ResourceManager、SlotManager 内部组件、TaskManager 和分配流程。

SlotManager 运行在 ResourceManager 内部,与 TaskManagerManager、ResourceManagerDriver、taskManagerConnections 协作。SlotManager 内部维护三个核心组件:

  • taskManagerSlots:所有 Slot 映射,key 为 SlotID,value 为 TaskManagerSlot,记录所有已注册的 Slot 及其状态。
  • pendingSlotRequests:等待中请求映射,key 为 AllocationID,value 为 PendingSlotRequest,记录正在等待 Slot 可用的请求。
  • slotStatusSyncer:Slot 状态同步器,Slot 状态变化时同步到 ResourceManager 和 SlotPool。

SlotManager 通过 TaskExecutorGateway 与 TaskManager 通信,发送 requestSlot RPC 请求。TaskExecutor 收到请求后在本地 SlotTable 中分配 Slot,返回 Acknowledge 确认。分配成功后,SlotManager 标记 Slot 为 ALLOCATED,通知 ResourceManager,RM 向 SlotPool 发送 SlotRequestSuccess 通知。


二、SlotManager 分配 Slot 完整流程

下面这张图是 SlotManager 分配 Slot 完整流程,包括6步分配流程、方法调用链、核心类和常见问题。

SlotManager 分配 Slot 分为6步:

第1步:接收 Slot 请求。ResourceManager 收到 SlotPool 的 requestSlot RPC 请求后,调用 slotManager.requestSlot(jobId, allocationId, resourceProfile) 方法,将请求转发给 SlotManager。SlotManager 验证请求参数,检查是否已存在相同 allocationId 的请求,避免重复分配。如果已存在相同请求,直接返回,不重复处理。

第2步:查找 FREE Slot。SlotManager 调用 findFreeSlot(resourceProfile) 方法,遍历所有已注册的 TaskManagerSlot,查找状态为 FREE 且满足资源需求(CPU、内存、网络)的 Slot。查找策略:优先选择资源匹配度最高的 Slot,其次按 TaskManager 注册顺序轮询,支持 Slot 亲和性调度(优先选择与输入源同节点的 Slot)。

第3步:标记 PENDING 状态。找到合适的 FREE Slot 后,调用 taskManagerSlot.assignPendingAllocation(allocationId, jobId) 方法,将 Slot 状态从 FREE 改为 PENDING。该方法有严格的前置条件检查(Preconditions.checkState(state == FREE)),防止非法状态转换。同时创建 PendingSlotRequest,记录请求信息和对应的 Slot,加入 pendingSlotRequests 映射。

第4步:通知 TaskManager 分配。SlotManager 通过 taskManagerConnections 获取 TaskExecutorGateway,调用 taskExecutorGateway.requestSlot(slotId, jobId, allocationId, targetAddress, timeout) 方法,向 TaskManager 发送 Slot 分配请求。TaskExecutor 收到请求后,在本地 SlotTable 中分配 Slot,返回 Acknowledge 确认。如果 TaskManager 无响应或分配失败,SlotManager 会取消 PENDING 状态,重新查找其他 Slot。

第5步:确认 ALLOCATED 状态。TaskExecutor 分配成功后返回 Acknowledge,SlotManager 收到确认后调用 taskManagerSlot.markAllocated() 方法,将 Slot 状态从 PENDING 改为 ALLOCATED。该方法同样有前置条件检查(state == PENDING)。状态变化时通知 SlotStatusListener,触发 SlotStatusSyncer 同步状态。从 pendingSlotRequests 中移除对应的请求,标记分配完成。

第6步:通知 ResourceManager 成功。SlotManager 分配完成后,ResourceManager 向 SlotPool 发送 SlotRequestSuccess(allocationId, slotId) 通知。SlotPool 收到通知后创建 AllocatedSlot,加入 allocatedSlots,通知等待的 Execution。SchedulerNG 获得 Slot 后,通过 TaskExecutorGateway 发送 submitTask 请求,TaskExecutor 创建 Task 实例,分配到 Slot 上启动执行。


三、核心类源码剖析

3.1 SlotManagerImpl 核心实现

publicclassSlotManagerImplimplementsSlotManager{privatefinalMap<SlotID,TaskManagerSlot>taskManagerSlots;privatefinalMap<AllocationID,PendingSlotRequest>pendingSlotRequests;privatefinalSlotStatusSyncerslotStatusSyncer;privatefinalMap<ResourceID,TaskExecutorGateway>taskManagerConnections;@OverridepublicvoidrequestSlot(JobIDjobId,AllocationIDallocationId,ResourceProfileresourceProfile,StringtargetAddress){// 1. 检查是否已存在相同请求if(pendingSlotRequests.containsKey(allocationId)){return;// 避免重复分配}// 2. 查找 FREE SlotTaskManagerSlotfreeSlot=findFreeSlot(resourceProfile,targetAddress);if(freeSlot!=null){// 3. 标记 PENDING 状态freeSlot.assignPendingAllocation(allocationId,jobId);// 4. 创建 PendingSlotRequestPendingSlotRequestpendingRequest=newPendingSlotRequest(allocationId,jobId,resourceProfile,freeSlot.getSlotId());pendingSlotRequests.put(allocationId,pendingRequest);// 5. 通知 TaskManager 分配TaskExecutorGatewaytaskExecutorGateway=taskManagerConnections.get(freeSlot.getTaskManagerId());taskExecutorGateway.requestSlot(freeSlot.getSlotId(),jobId,allocationId,targetAddress,timeout);}else{// 6. 无 FREE Slot,创建 PendingSlotRequest 等待PendingSlotRequestpendingRequest=newPendingSlotRequest(allocationId,jobId,resourceProfile,null);pendingSlotRequests.put(allocationId,pendingRequest);}}privateTaskManagerSlotfindFreeSlot(ResourceProfileresourceProfile,StringtargetAddress){// 1. 优先亲和性:查找与 targetAddress 同节点的 FREE Slotif(targetAddress!=null){for(TaskManagerSlotslot:taskManagerSlots.values()){if(slot.getState()==SlotState.FREE&&slot.getTaskManagerLocation().getHostname().equals(targetAddress)&&slot.getResourceProfile().isMatching(resourceProfile)){returnslot;}}}// 2. 资源匹配:查找满足资源需求的 FREE Slotfor(TaskManagerSlotslot:taskManagerSlots.values()){if(slot.getState()==SlotState.FREE&&slot.getResourceProfile().isMatching(resourceProfile)){returnslot;}}returnnull;// 无可用 Slot}@OverridepublicvoidnotifyAllocationComplete(AllocationIDallocationId,SlotIDslotId){// 1. 查找对应的 PendingSlotRequestPendingSlotRequestpendingRequest=pendingSlotRequests.remove(allocationId);if(pendingRequest==null){return;}// 2. 查找对应的 TaskManagerSlotTaskManagerSlotslot=taskManagerSlots.get(slotId);if(slot==null){return;}// 3. 标记 ALLOCATED 状态slot.markAllocated();// 4. 通知状态同步器slotStatusSyncer.notifySlotStatusChange(slotId,SlotState.ALLOCATED);}}

SlotManagerImpl 是 SlotManager 的核心实现。requestSlot 方法首先检查是否已存在相同请求,避免重复分配;然后调用 findFreeSlot() 查找 FREE Slot,有空闲则标记 PENDING 并通知 TM 分配;无空闲则创建 PendingSlotRequest 等待。findFreeSlot 方法优先亲和性调度(与 targetAddress 同节点),其次资源匹配。notifyAllocationComplete 方法接收 TM 的分配确认,标记 ALLOCATED 状态,通知状态同步器。

3.2 TaskManagerSlot 状态管理

publicclassTaskManagerSlot{privatefinalSlotIDslotId;privatefinalResourceIDtaskManagerId;privatefinalTaskManagerLocationtaskManagerLocation;privatefinalResourceProfileresourceProfile;privateSlotStatestate;privateAllocationIDallocationId;privateJobIDjobId;publicTaskManagerSlot(SlotIDslotId,ResourceIDtaskManagerId,TaskManagerLocationtaskManagerLocation,ResourceProfileresourceProfile){this.slotId=slotId;this.taskManagerId=taskManagerId;this.taskManagerLocation=taskManagerLocation;this.resourceProfile=resourceProfile;this.state=SlotState.FREE;}publicvoidassignPendingAllocation(AllocationIDallocationId,JobIDjobId){// 前置条件检查:当前状态必须是 FREEPreconditions.checkState(state==SlotState.FREE,"Cannot assign pending allocation to slot in state %s",state);this.state=SlotState.PENDING;this.allocationId=allocationId;this.jobId=jobId;}publicvoidmarkAllocated(){// 前置条件检查:当前状态必须是 PENDINGPreconditions.checkState(state==SlotState.PENDING,"Cannot mark slot as allocated in state %s",state);this.state=SlotState.ALLOCATED;}publicvoidfreeSlot(){// 释放 Slot,回到 FREE 状态this.state=SlotState.FREE;this.allocationId=null;this.jobId=null;}publicSlotStategetState(){returnstate;}publicSlotIDgetSlotId(){returnslotId;}publicResourceIDgetTaskManagerId(){returntaskManagerId;}publicTaskManagerLocationgetTaskManagerLocation(){returntaskManagerLocation;}publicResourceProfilegetResourceProfile(){returnresourceProfile;}}publicenumSlotState{FREE,// 空闲,可分配PENDING,// 分配中,等待 TM 确认ALLOCATED// 已分配,执行 Task}

TaskManagerSlot 表示一个 Slot 实例,管理 Slot 的状态转换。Slot 有三种状态:FREE(空闲,可分配)、PENDING(分配中,等待 TM 确认)、ALLOCATED(已分配,执行 Task)。assignPendingAllocation 方法将状态从 FREE 改为 PENDING,有严格的前置条件检查。markAllocated 方法将状态从 PENDING 改为 ALLOCATED,同样有前置条件检查。freeSlot 方法释放 Slot,回到 FREE 状态。

3.3 PendingSlotRequest 等待请求

publicclassPendingSlotRequest{privatefinalAllocationIDallocationId;privatefinalJobIDjobId;privatefinalResourceProfileresourceProfile;privatefinalSlotIDassignedSlot;privatefinallongcreationTime;publicPendingSlotRequest(AllocationIDallocationId,JobIDjobId,ResourceProfileresourceProfile,SlotIDassignedSlot){this.allocationId=allocationId;this.jobId=jobId;this.resourceProfile=resourceProfile;this.assignedSlot=assignedSlot;this.creationTime=System.currentTimeMillis();}publicbooleanisTimeout(longtimeout){returnSystem.currentTimeMillis()-creationTime>timeout;}publicAllocationIDgetAllocationId(){returnallocationId;}publicJobIDgetJobId(){returnjobId;}publicResourceProfilegetResourceProfile(){returnresourceProfile;}publicSlotIDgetAssignedSlot(){returnassignedSlot;}}

PendingSlotRequest 封装了等待中的 Slot 请求,包含 allocationId、jobId、resourceProfile、assignedSlot(已分配的 Slot,无空闲时为 null)等请求信息。creationTime 记录请求创建时间,用于超时检测。isTimeout 方法判断请求是否超时,超过 request-timeout(默认5分钟)未分配则取消请求。

3.4 SlotStatusSyncer 状态同步

publicclassSlotStatusSyncer{privatefinalResourceManagerGatewayresourceManagerGateway;privatefinalMap<SlotID,SlotState>slotStatusCache;publicvoidnotifySlotStatusChange(SlotIDslotId,SlotStatenewState){// 1. 更新状态缓存SlotStateoldState=slotStatusCache.put(slotId,newState);// 2. 状态变化时通知 ResourceManagerif(oldState!=newState){resourceManagerGateway.notifySlotStatus(slotId,newState,System.currentTimeMillis());}}publicvoidsyncAllSlotStatus(){// 全量同步所有 Slot 状态for(Map.Entry<SlotID,SlotState>entry:slotStatusCache.entrySet()){resourceManagerGateway.notifySlotStatus(entry.getKey(),entry.getValue(),System.currentTimeMillis());}}}

SlotStatusSyncer 是 Slot 状态同步器,负责将 Slot 状态变化同步到 ResourceManager。notifySlotStatusChange 方法更新状态缓存,状态变化时通过 ResourceManagerGateway 通知 RM。syncAllSlotStatus 方法全量同步所有 Slot 状态,用于 RM 重新连接后的状态恢复。


四、Slot 选择策略与无空闲处理

下面这张图是 Slot 选择策略与无空闲处理,包括三种选择策略、无空闲处理流程、超时检查、配置和最佳实践。

Slot 选择策略

SlotManager 分配 Slot 时有三种选择策略:

  1. 资源匹配优先:优先选择资源需求匹配度最高的 Slot。比较 Slot 的 ResourceProfile 与请求的 resourceProfile,选择 CPU、内存、网络等资源最匹配的 Slot,避免资源浪费和资源不足。
  2. 轮询分配:按 TaskManager 注册顺序轮询分配 Slot,保证 Slot 在不同 TaskManager 间均匀分布,避免单个 TaskManager 负载过高。适用于资源需求相同的 Slot 请求。
  3. Slot 亲和性:优先选择与输入源同一节点的 Slot,提高数据本地性,减少网络传输开销。Locality 分为 LOCAL(同节点)、HOST_SLOT(同主机)、UNKNOWN(无法判断)三个级别。

无空闲 Slot 处理

无 FREE Slot 时,SlotManager 创建 PendingSlotRequest 等待,同时通知 ResourceManager 通过 ResourceManagerDriver 申请新容器。新 TaskManager 注册后,新 Slot 可用,SlotManager 分配给等待的 PendingSlotRequest。超过 request-timeout(默认5分钟)未分配则取消请求,通知 SlotPool 分配失败。

无空闲处理流程:

  1. 无 FREE Slot:findFreeSlot() 返回 null
  2. 创建 PendingRequest:加入 pendingSlotRequests 等待
  3. 通知 RM 申请资源:ResourceManagerDriver 申请新容器
  4. 新 TM 注册:新 Slot 可用,分配等待请求
  5. 超时取消:超过 request-timeout 则取消

超时检查机制

超时检查通过三个关键参数控制:

  • request-timeout(默认5分钟):Slot 请求超时,超过该时间未分配则取消 PendingSlotRequest
  • taskmanager-timeout(默认30秒):TaskManager 超时,超过该时间无心跳则剔除 TM
  • check-interval(默认10秒):超时检查间隔,定期遍历 pendingSlotRequests

五、关键配置参数

# Slot 请求超时slotmanager.request-timeout:5min# TaskManager 超时slotmanager.taskmanager-timeout:30s# 每个 TaskManager 的 Slot 数taskmanager.numberOfTaskSlots:1# 调度器类型jobmanager.scheduler:adaptive# 最大 Slot 数slotmanager.max-number-of-slots:2147483647# 故障恢复策略jobmanager.execution.failover-strategy:region# 重启策略类型restart-strategy.type:fixed-delay# 固定延迟重启次数restart-strategy.fixed-delay.attempts:3# 固定延迟重启间隔restart-strategy.fixed-delay.delay:10s

关键配置说明:

  • slotmanager.request-timeout:Slot 请求超时,默认5分钟,大作业可调大到10-15分钟。
  • slotmanager.taskmanager-timeout:TaskManager 超时,默认30秒,网络不稳定环境可调大。
  • taskmanager.numberOfTaskSlots:每个 TM 的 Slot 数,根据 CPU 核数配置,通常1-4个。
  • jobmanager.scheduler:调度器类型,adaptive 支持动态调整并行度。
  • slotmanager.max-number-of-slots:最大 Slot 数,限制集群可分配的 Slot 总数。
  • jobmanager.execution.failover-strategy:故障恢复策略,region 只重启受影响的 Task 区域。

六、常见问题与最佳实践

常见问题

  1. 无 FREE Slot 可分配

    • 原因:所有 Slot 已分配或资源不足。
    • 解决:增加 TM 数量,调整并行度,等待 Slot 释放,检查资源配置。
  2. PENDING 状态卡住

    • 原因:TM 无响应或网络异常,分配请求未收到确认。
    • 解决:检查 TM 心跳,确认网络连通,调大超时时间,查看 TM 日志。
  3. 状态转换异常

    • 原因:非法状态转换或并发问题,Preconditions.checkState 抛出异常。
    • 解决:检查日志,重启 JM,查看 SlotManager 状态,确认是否有并发分配。
  4. 分配超时

    • 原因:资源不足或 TM 启动慢,新容器启动时间长。
    • 解决:调大 request-timeout,增加资源,预启动 TM,检查 Driver 配置。
  5. Slot 亲和性失效

    • 原因:targetAddress 配置错误或 Slot 不足无法满足本地性要求。
    • 解决:检查输入源位置配置,确保足够 Slot,监控 Locality 级别,接受 UNKNOWN 降级。

最佳实践

  1. 合理配置 Slot 数:根据 CPU 核数配置 numberOfTaskSlots,通常1-4个。Slot 数过多会导致每个 Slot 分配的内存和 CPU 减少,影响 Task 执行性能;过少则资源利用率低。

  2. 配置合适超时时间:大作业可调大 request-timeout 到10-15分钟,避免资源申请频繁超时导致作业失败。但不要过大,否则资源不足时作业长时间挂起,影响集群稳定性。

  3. 监控 PendingRequest:关注等待中的 Slot 请求数量和等待时间,及时发现资源不足问题。pendingSlotRequests 持续增长说明资源不足,需要增加 TM 或调整并行度。

  4. 使用亲和性调度:配置 targetAddress 提高数据本地性,减少网络传输,提升作业性能。优先选择 LOCAL 级别的 Slot,无法满足时接受 HOST_SLOT 或 UNKNOWN 降级。

  5. 预启动 TaskManager:资源波动大的环境可预启动 TM,避免新容器启动慢导致 Slot 分配超时。预启动的 TM 注册后 Slot 立即可用,减少等待时间。

  6. 配置重启策略:生产环境配置 fixed-delay 或 failure-rate 重启策略,Slot 分配失败时自动重试,提高作业稳定性。

  7. 使用 adaptive 调度器:adaptive 调度器支持动态调整并行度,根据可用 Slot 数自动调整,提高资源利用率和作业稳定性。


七、总结

Flink SlotManager 分配 Slot 是一个6步流程:接收 Slot 请求 → 查找 FREE Slot → 标记 PENDING 状态 → 通知 TaskManager 分配 → 确认 ALLOCATED 状态 → 通知 ResourceManager 成功。核心类包括 SlotManagerImpl(Slot 管理器,接收请求,查找和分配 Slot)、TaskManagerSlot(Slot 实例,管理 FREE/PENDING/ALLOCATED 状态转换)、PendingSlotRequest(待处理请求,记录请求信息和超时)、SlotStatusSyncer(Slot 状态同步器,状态变化时同步到 RM)。

Slot 选择策略有三种:资源匹配优先(选择 ResourceProfile 匹配度最高的 Slot)、轮询分配(按 TM 注册顺序轮询,保证负载均衡)、Slot 亲和性(优先选择与输入源同节点的 Slot,提高数据本地性)。无 FREE Slot 时,创建 PendingSlotRequest 等待,通知 RM 申请新容器,新 TM 注册后分配等待请求,超过 request-timeout(默认5分钟)未分配则取消。

理解 SlotManager 分配 Slot 的源码实现,有助于排查无 FREE Slot、PENDING 状态卡住、状态转换异常、分配超时、亲和性失效等常见问题,为 Flink 作业的稳定运行提供保障。合理配置 Slot 数、超时时间、监控 PendingRequest、使用亲和性调度和预启动 TM,可以显著提高 Slot 分配效率和作业稳定性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 3:06:42

SpringBoot+Vue构建智能冷链物流系统实战

1. 冷链物流系统概述&#xff1a;当技术遇上生鲜供应链去年夏天帮朋友调试他们生鲜电商的仓储系统时&#xff0c;亲眼目睹了因为温控数据延迟上报导致的一车精品牛排报废——这个价值12万的教训让我深刻意识到&#xff0c;一套可靠的冷链管理系统对现代物流意味着什么。今天我们…

作者头像 李华
网站建设 2026/10/14 3:06:38

SM3算法的各种密码分析方法全面盘点

SM3算法的各种密码分析方法全面盘点对SM3算法的密码分析&#xff0c;目前主要分为针对算法数学结构的分析和针对具体实现的物理攻击两大类。虽然SM3在设计上增强了安全性&#xff0c;但对其实施缩减轮数攻击和侧信道攻击的研究一直在持续。以下是当前主要的密码分析方法盘点&am…

作者头像 李华
网站建设 2026/10/14 3:06:30

C++对象存储SDK集成实战:从编译到分片上传的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 3:06:18

国自然申请中个人贡献描述的核心要点与技巧

1. 国自然申请中的个人贡献描述为何如此重要国家自然科学基金&#xff08;简称"国自然"&#xff09;作为我国基础研究领域最重要的资助渠道之一&#xff0c;其申请书中的"个人贡献描述"部分往往是评审专家重点关注的环节。这个看似简单的段落&#xff0c;实…

作者头像 李华
网站建设 2026/10/14 3:05:54

漫剧角色资产命名规范的六段式编码体系与七类资产字段定义

漫剧角色资产命名规范的核心是一套六段式主模板——项目代号_角色ID_资产类型_细分标签_版本.后缀&#xff0c;搭配ref、turn、face、pose、cost、hair、part、rig、tex、bone十类资产类型缩写&#xff0c;确保角色资产在AI生图与视频合成链路中可被精确调用。截至2026年&#…

作者头像 李华
网站建设 2026/10/14 3:05:30

MySQL索引优化:从B+树原理到慢查询实战

做后端开发这几年&#xff0c;最常被拉到群里去救火的场景&#xff0c;十有八九是数据库慢查询。系统跑得好好的&#xff0c;突然某天接口变慢、CPU飙高&#xff0c;一看日志全是SELECT走了全表扫描&#xff0c;几百万行的表一次查询几秒钟才回来。这种时候&#xff0c;十次里有…

作者头像 李华