跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaAIjava

Flink 外部资源框架:作业原生申请 GPU/FPGA 资源

Flink 外部资源框架实现作业对 GPU、FPGA 等硬件资源的原生申请与分配。框架负责向底层资源管理系统(如 Kubernetes、YARN)请求容器资源,并向算子提供可用资源信息。支持 GPU 推理、特征工程及 FPGA 加速场景。配置需包含插件加载、资源声明及驱动工厂设置。在 Standalone 模式下需注意多 TaskManager 间的资源协调,避免冲突。生产环境推荐结合 K8s 或 YARN 使用,并遵循设备亲和策略进行算子绑定。

忘忧发布于 2026/3/23更新于 2026/6/1129 浏览

1. 外部资源框架到底做了什么

整体就两件事:

1)改写资源请求(Resource Request)

  • 你在 Flink 配置里声明要什么资源、要多少
  • Flink 会把这些外部资源需求映射进底层资源管理系统(Kubernetes/YARN)的容器或 Pod 资源请求中
  • 最终确保 TaskManager 所在的容器/Pod 真的带着你要的外部资源启动

2)把'可用资源信息'提供给算子(Operator)

  • TaskManager 启动后,由'外部资源驱动(driver)'生成 ExternalResourceInfo(资源信息集合)
  • 算子通过 RuntimeContext.getExternalResourceInfos(resourceName) 拿到资源的关键属性(比如 GPU index),然后就可以在算子里绑定对应设备去用

一句话:框架负责'申请 + 告知',至于'怎么用'取决于具体插件。

2. 适用场景与边界

适合的典型场景

  • GPU 推理(TensorRT / ONNX Runtime / PyTorch inference)作为 RichFunction/AsyncFunction 的一部分
  • GPU 加速特征工程或向量计算
  • 需要 FPGA、专用加速卡的自定义计算
  • 同一套作业在 Kubernetes/YARN 上希望'按需申请资源'

当前边界(很关键)

  • 外部资源是'机器级/进程级共享'的:同一 TaskManager 上运行的所有算子拿到的 ExternalResourceInfos 目前是同一份集合
  • 也就是说:没有 operator 级别的资源隔离(同 TM 内算子理论上能看到同一批 GPU)

如果你希望'每个算子/每个 subtask 独占一张卡',需要你在算子内部做更严格的绑定策略,或用脚本协调模式避免同机多 TM 抢同一 GPU(后面讲)。

3. 启用流程:三步走

3.1 准备外部资源插件(plugins/)

外部资源通过 Flink 插件机制加载,你需要把对应 jar 放到 Flink 的 plugins/ 目录下的某个子目录中,例如:

  • GPU 插件:放到 plugins/external-resource-gpu/(或你自定义目录,但要保证 jar 能被加载)
  • 自定义资源插件:创建一个目录,比如 plugins/fpga/,把你打出来的 jar 放进去

插件隔离非常重要:每个 plugin 目录是独立 classloader,避免依赖冲突;同时 SPI(ServiceLoader)文件必须保留(META-INF/services)。

3.2 配置 external-resources 与每个资源的参数

核心配置有两层:

A)先声明启用哪些资源(白名单)

external-resources: gpu;fpga

只有这里列出来的 <resource_name> 才会生效。

B)为每个资源配置 amount、k8s/yarn 映射、driver、driver 参数 常见配置项含义:

  • external-resource.<name>.amount:每个 TaskManager 需要的资源数量
  • external-resource.<name>.yarn.config-key:YARN 容器资源 profile 的映射 key(可选)
  • external-resource.<name>.kubernetes.config-key:K8s 容器 resources.requests/limits 的 key(可选)
  • external-resource.<name>.driver-factory.class:驱动工厂(可选但强烈建议)
    • 不配置也能'申请到资源',但算子拿不到 ExternalResourceInfo(RuntimeContext 里会没有信息)
  • :传给驱动工厂的自定义参数(插件自定义解释)
external-resource.<name>.param.<param>

一个包含 GPU+FPGA 的示例:

external-resources: gpu;fpga
external-resource.gpu.driver-factory.class: org.apache.flink.externalresource.gpu.GPUDriverFactory
external-resource.gpu.amount: 2
external-resource.gpu.param.discovery-script.args: --enable-coordination-mode
external-resource.fpga.driver-factory.class: org.apache.flink.externalresource.fpga.FPGADriverFactory
external-resource.fpga.amount: 1
external-resource.fpga.yarn.config-key: yarn.io/fpga
3.3 在算子里使用 RuntimeContext 获取资源信息

算子侧用法非常直接:

public class ExternalResourceMapFunction extends RichMapFunction<String, String> {
    private static final String RESOURCE_NAME = "gpu";

    @Override
    public String map(String value) throws Exception {
        Set<ExternalResourceInfo> infos = getRuntimeContext().getExternalResourceInfos(RESOURCE_NAME);
        List<String> indices = new ArrayList<>();
        for (ExternalResourceInfo info : infos) {
            info.getProperty("index").ifPresent(indices::add); // GPU 插件常用属性 key:index
        }
        // 这里用 indices 做设备绑定,比如选择一张卡 set CUDA_VISIBLE_DEVICES 或初始化推理引擎
        return value;
    }
}

每个 ExternalResourceInfo 里有哪些 key,取决于插件实现。你可以用 ExternalResourceInfo#getKeys() 获取完整键集合。

4. Kubernetes / YARN / Standalone:三种环境的差异

4.1 Kubernetes
  • K8s 原生通过 Device Plugin 机制提供 GPU/FPGA 等资源(Kubernetes v1.10+ 支持)
  • Flink 会把你配置的 kubernetes.config-key 写入 TaskManager 主容器的:
    • resources.requests.<config-key>
    • resources.limits.<config-key>

GPU 的常见 key:

  • NVIDIA:nvidia.com/gpu
  • AMD:amd.com/gpu(但 Flink 默认 discovery 脚本是 NVIDIA 的,AMD 需要你自己写脚本)
4.2 YARN
  • YARN 2.10+ / 3.1+ 开始支持 GPU/FPGA 资源
  • Flink 通过 external-resource.<name>.yarn.config-key 把 amount 写进 container resource profile

GPU(YARN)常见 key:

  • yarn.io/gpu(注意:YARN 当前通常仅支持 NVIDIA GPU 的调度)
4.3 Standalone
  • Standalone 模式没有底层 RM 帮你'保证资源',你需要管理员在节点上确保外部资源可用(驱动安装、权限、设备可见性等)
  • 如果同一台机器上跑多个 TaskManager,GPU 可见性很容易冲突,需要配合 discovery script 的协调模式

5. GPU 插件:最常用也最值得踩坑的一块

Flink 目前官方提供的一方外部资源插件就是 GPU 插件。

5.1 必要配置(GPU)
external-resources: gpu
external-resource.gpu.driver-factory.class: org.apache.flink.externalresource.gpu.GPUDriverFactory
external-resource.gpu.amount: 2
# Kubernetes
external-resource.gpu.kubernetes.config-key: nvidia.com/gpu
# YARN
external-resource.gpu.yarn.config-key: yarn.io/gpu
5.2 discovery script(GPU 发现脚本)

GPUDriver 会调用 discovery script 来发现可用 GPU,并生成 ExternalResourceInfo,其中关键属性是:

  • key = index(GPU 设备 index)

默认脚本路径(NVIDIA):

external-resource.gpu.param.discovery-script.path: plugins/external-resource-gpu/nvidia-gpu-discovery.sh

自定义脚本路径(例如 AMD)也可以配置同一个 key。

脚本参数:

external-resource.gpu.param.discovery-script.args: --enable-coordination-mode
5.3 脚本契约(你写自定义脚本时必须遵守)
  • Flink 先把 amount 作为第一个参数传给脚本
  • 你配置的 discovery-script.args 会拼在后面
  • 脚本输出:用逗号分隔的 GPU index 列表,例如 0,1
  • 输出里纯空白 index 会被忽略
  • 如果发现失败或数量不足:脚本返回非 0 exit code,Flink 将不会向算子提供 gpu 信息(RuntimeContext 拿不到)
5.4 协调模式:解决'同机多 TM 抢同一 GPU'

Standalone 下经常同机部署多个 TaskManager,此时所有 TM 默认都能看到同一批 GPU(nvidia-smi 可见),很容易'多进程抢同一张卡'。

默认脚本提供 coordination mode:

  • --enable-coordination-mode:启用协调
  • --coordination-file <path>:协调文件路径(默认 /var/tmp/flink-gpu-coordination)

它能保证:同一个 Flink 集群内,同机多个 TaskManager 不会分到同一张 GPU。

但要注意两点:

  • 只在'同一协调文件范围内'有效:另一个 Flink 集群如果用不同 coordination file,仍可能抢同一 GPU
  • 非 Flink 应用也可能用同一 GPU,这个模式无法防住

6. 自定义资源插件:你要支持 FPGA/自研加速卡怎么做

你需要实现三件套:

1)ExternalResourceDriver

  • retrieveResourceInfo(long amount):返回 ExternalResourceInfo 集合(你定义的资源维度)

2)ExternalResourceDriverFactory

  • createExternalResourceDriver(Configuration config):从配置创建 driver

3)SPI 服务声明(非常关键)

  • 在 jar 内创建文件:
    • META-INF/services/org.apache.flink.api.common.externalresource.ExternalResourceDriverFactory
  • 文件内容写你的 factory 全类名,例如:
    • your.domain.FPGADriverFactory

示例骨架:

public class FPGAInfo implements ExternalResourceInfo {
    @Override
    public Optional<String> getProperty(String key) {
        // 根据 key 返回属性,比如 "device", "pci", "address" 等
        return Optional.empty();
    }

    @Override
    public Collection<String> getKeys() {
        return List.of("device", "pci", "address");
    }
}

public class FPGADriver implements ExternalResourceDriver {
    @Override
    public Set<ExternalResourceInfo> retrieveResourceInfo(long amount) {
        // 发现并返回 FPGA 信息集合
        return Set.of(/* ... */);
    }
}

public class FPGADriverFactory implements ExternalResourceDriverFactory {
    @Override
    public ExternalResourceDriver createExternalResourceDriver(Configuration config) {
        return new FPGADriver();
    }
}

打包成 jar 丢到 plugins/fpga/,然后在 flink-conf.yaml 里按 <resource_name> 配置启用即可。

7. 排障清单:最常见的 6 个'为什么拿不到 GPU'

1)external-resources 没写 gpu(或资源名拼错) 2)插件 jar 没放到 plugins/ 下正确目录(或目录里缺依赖) 3)没配置 driver-factory.class,导致算子侧拿不到 ExternalResourceInfo 4)K8s 没装 NVIDIA device plugin(Pod 根本拿不到 GPU) 5)discovery script 不可执行 / 路径不对 / 返回非 0 6)Standalone 同机多 TM 没开协调模式,导致资源冲突看似'有卡但不可用'

8. 最佳实践建议

  • 先明确'资源申请'和'资源绑定'是两步:申请解决'容器是否带卡',绑定解决'算子用哪张卡'
  • GPU 推理算子里要做设备亲和:基于 index 决定 CUDA_VISIBLE_DEVICES 或引擎初始化参数
  • Standalone 同机多 TM 建议默认开 coordination mode
  • 生产上尽量用 Kubernetes/YARN 去做资源保证,Standalone 只适合可控环境
  • 由于没有 operator 级隔离,最好避免在同一 TM 内多个算子'各自随便挑卡',要统一策略(例如只由一个算子管理 GPU worker)

目录

  1. 1. 外部资源框架到底做了什么
  2. 2. 适用场景与边界
  3. 3. 启用流程:三步走
  4. 3.1 准备外部资源插件(plugins/)
  5. 3.2 配置 external-resources 与每个资源的参数
  6. 3.3 在算子里使用 RuntimeContext 获取资源信息
  7. 4. Kubernetes / YARN / Standalone:三种环境的差异
  8. 4.1 Kubernetes
  9. 4.2 YARN
  10. 4.3 Standalone
  11. 5. GPU 插件:最常用也最值得踩坑的一块
  12. 5.1 必要配置(GPU)
  13. Kubernetes
  14. YARN
  15. 5.2 discovery script(GPU 发现脚本)
  16. 5.3 脚本契约(你写自定义脚本时必须遵守)
  17. 5.4 协调模式:解决“同机多 TM 抢同一 GPU”
  18. 6. 自定义资源插件:你要支持 FPGA/自研加速卡怎么做
  19. 7. 排障清单:最常见的 6 个“为什么拿不到 GPU”
  20. 8. 最佳实践建议
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 PotPlayer、Alist 与 WebDAV 搭建个人云影院方案
  • 本地代码上传到 Gitee 仓库教程(IDEA 和 VSCode 通用)
  • TypeScript 前端高频面试题精选与实战解析
  • KaiwuDB 3.1.0 在 Ubuntu 22.04 单机部署实战:TLS 配置与性能基线
  • 基于 AR 眼镜的亲戚称呼助手开发实战
  • 三维组合导航算法:INS与GNSS融合及卡尔曼滤波MATLAB实现
  • Docker 沙盒运行 OpenClaw:保护 API 密钥与本地 AI 代理安全
  • 归并排序时间复杂度 O(nlogn) 解析:LeetCode 148 排序链表
  • Flutter 三方库 arcade 的鸿蒙化适配指南
  • 多模态 Agent 图像识别 Skills 开发:JavaScript+Python 全栈方案
  • 2026 年高校论文 AI 率新规解读:多校明确 AIGC 检测要求
  • C++中文字符乱码问题解决方案
  • HarmonyOS 6.0 应用预加载机制详解
  • AR.js Web 增强现实应用开发指南
  • 基于C#的OPC转Web API服务器框架源码,集成IoT与Modbus及PLC协议
  • 不改一行代码定位线上 Java 性能问题
  • 国内主流AI大模型企业及产品布局解析
  • Vue 前端文件导出实战:file-saver 插件用法详解
  • 使用文心一言为智能体设计稳定调用工作流的提示词
  • GitHub Copilot 超级定制化 AI 编程助手工具集

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online