Flink 系列第10篇:Flink 分布式缓存详解

一、分布式缓存概述

Flink 提供的分布式缓存,核心作用是让用户在并行函数中便捷读取本地或远程文件,并将文件同步至所有 TaskManager 节点的本地文件系统,避免 Task 重复拉取文件,提升作业执行效率,降低网络开销。

二、分布式缓存工作机制

Flink 分布式缓存的工作流程可分为以下4个步骤,确保文件高效同步且仅执行一次:

  1. 用户注册文件/目录:可注册本地文件,或远程文件系统(如 HDFS、S3)中的文件/目录;

  2. 通过执行环境注册:借助 ExecutionEnvironment 注册缓存文件,并为其指定一个唯一名称(后续用于查找文件);

  3. 自动同步至 TaskManager:程序执行时,Flink 会自动将注册的文件/目录复制到所有 TaskManager 节点的本地文件系统,该同步操作仅执行一次;

  4. 本地访问文件:用户在并行函数中,通过注册时指定的名称查找文件/目录,从 TaskManager 本地文件系统直接访问,无需重复拉取。

三、代码示例

3.1 注册缓存文件

通过 ExecutionEnvironment 注册缓存文件,支持本地文件或远程文件(如 HDFS),示例如下:

java 复制代码
// 1. 获取Flink批处理运行环境(分布式缓存主要用于批处理,流处理需结合特定场景)
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();

// 2. 注册缓存文件:第一个参数为文件路径(本地路径/远程路径),第二个参数为缓存名称(唯一标识)
// 示例:注册本地文件,缓存名称为"a.txt"
env.registerCachedFile("/Users/wangzhiwu/WorkSpace/quickstart/text", "a.txt");

3.2 在并行函数中访问缓存文件

需通过继承 RichFunction(如 RichMapFunction),借助 RuntimeContext 读取缓存文件。原因是 RichFunction 提供了 RuntimeContext 实例,可用于获取分布式缓存资源。

java 复制代码
// 3. 在RichMapFunction中访问缓存文件
DataSet<String> result = data.map(new RichMapFunction<String, String>() {
    // 用于存储缓存文件中的数据,供后续业务逻辑使用
    private ArrayList<String> dataList = new ArrayList<String>();

    // open方法:在Task启动时执行一次,适合初始化操作(如读取缓存)
    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        // 4. 通过缓存名称"a.txt"获取本地文件
        File myFile = getRuntimeContext().getDistributedCache().getFile("a.txt");
        // 5. 读取文件内容(需导入org.apache.commons.io.FileUtils)
        List<String> lines = FileUtils.readLines(myFile);
        // 6. 将文件内容存入dataList,供map方法使用
        for (String line : lines) {
            this.dataList.add(line);
            System.err.println("分布式缓存内容:" + line);
        }
    }

    // map方法:并行处理每条数据,可直接使用缓存中的dataList
    @Override
    public String map(String value) throws Exception {
        // 打印缓存数据和当前处理的value,便于调试
        System.err.println("使用缓存数据:" + dataList + "------------" + value);
        // 业务逻辑:将缓存数据与当前value拼接返回
        return dataList + ":" + value;
    }
});

// 打印结果(printToErr()用于区分标准输出和错误输出,便于查看缓存相关日志)
result.printToErr();

3.3 完整代码(含注释)

以下为完整可运行代码,包含环境初始化、缓存注册、缓存访问及结果输出,注释详细可直接复用:

java 复制代码
import org.apache.flink.api.common.functions.RichMapFunction;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.DataSource;
import org.apache.flink.configuration.Configuration;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class DisCacheTest {

    public static void main(String[] args) throws Exception{
        // 1. 获取Flink批处理运行环境
        ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();

        // 2. 注册缓存文件:本地文件路径(可替换为HDFS路径,如hdfs://xxx/text)
        // 备注:缓存文件text中包含4个单词:hello flink hello FLINK
        env.registerCachedFile("/Users/wangzhiwu/WorkSpace/quickstart/text", "a.txt");

        // 3. 构造测试数据源(4条数据:a、b、c、d)
        DataSource<String> data = env.fromElements("a", "b", "c", "d");

        // 4. 利用RichMapFunction访问缓存并处理数据
        DataSet<String> result = data.map(new RichMapFunction<String, String>() {
            // 存储缓存文件内容的集合
            private ArrayList<String> dataList = new ArrayList<String>();

            // Task启动时执行,仅执行一次,用于读取缓存文件
            @Override
            public void open(Configuration parameters) throws Exception {
                super.open(parameters);
                // 通过缓存名称"a.txt"获取TaskManager本地的缓存文件
                File myFile = getRuntimeContext().getDistributedCache().getFile("a.txt");
                // 读取文件所有行(依赖commons-io包,需引入相关依赖)
                List<String> lines = FileUtils.readLines(myFile);
                // 将文件内容存入dataList
                for (String line : lines) {
                    this.dataList.add(line);
                    System.err.println("分布式缓存内容:" + line);
                }
            }

            // 并行处理每条输入数据,可直接使用缓存中的dataList
            @Override
            public String map(String value) throws Exception {
                // 打印缓存数据和当前处理的value,用于调试
                System.err.println("使用缓存数据:" + dataList + "------------" + value);
                // 业务逻辑:将缓存数据与当前value拼接,作为结果返回
                return dataList + ":" + value;
            }
        });

        // 5. 输出结果(使用printToErr(),避免与缓存日志混淆)
        result.printToErr();
    }
}

四、输出结果

运行上述代码后,输出结果如下(包含缓存读取日志和最终处理结果):

plain 复制代码
分布式缓存内容:hello
分布式缓存内容:flink
分布式缓存内容:hello
分布式缓存内容:FLINK
使用缓存数据:[hello, flink, hello, FLINK]------------a
[hello, flink, hello, FLINK]:a
使用缓存数据:[hello, flink, hello, FLINK]------------b
[hello, flink, hello, FLINK]:b
使用缓存数据:[hello, flink, hello, FLINK]------------c
[hello, flink, hello, FLINK]:c
使用缓存数据:[hello, flink, hello, FLINK]------------d
[hello, flink, hello, FLINK]:d
相关推荐
SPC的存折2 小时前
自用LNMP-Redis-NFS-Discuz5.0部署指南-脚本版
linux·运维·服务器·数据库·redis·mysql·缓存
杰克尼3 小时前
redis(day05-分布式缓存)
数据库·redis·缓存
gihigo19983 小时前
分布式发电的配电网有功-无功综合优化 MATLAB 实现
开发语言·分布式·matlab
脑子加油站4 小时前
OpenEuler24.03 分布式配置redis 集群
数据库·redis·分布式·php·nginx代理
李昊哲小课4 小时前
安装 npm/pnpm/yarn 换国内镜像 统一目录管理全局包+缓存
前端·缓存·npm·pnpm·yarn
蒸汽求职5 小时前
告别静态文档:利用 Notion 搭建“交互式”简历的降维展示策略
开发语言·缓存·面试·职场和发展·金融·notion
武子康5 小时前
大数据-269 实时数仓-Flink+HBase+DIM层数据处理实战:构建地区维度数据仓库
大数据·后端·flink
想你依然心痛5 小时前
HarmonyOS 5.0工业物联网开发实战:构建分布式智能制造监控与数字孪生预测维护系统
分布式·物联网·harmonyos·数字孪生
zhixingheyi_tian5 小时前
Hadoop 之 native 库
大数据·linux·hadoop·分布式