1、GCS URI 规则与常用场景
在 Flink 中访问 GCS 的路径格式:
gs://<your-bucket>/<endpoint>
其中 <endpoint> 可以是单个文件,也可以是目录前缀。
适用场景
- 批/流读取:FileSource 从 GCS 读文件/目录
- 结果落盘:FileSink 写入 GCS
- Checkpoint/Savepoint:把状态持久化到 GCS
- 其他:HA 存储、RocksDB 远端状态文件等(只要该处接受 FileSystem URI)
2、代码示例:读、写、Checkpoint 上 GCS
2.1 从 GCS 读取(FileSource)
java
FileSource<String> fileSource = FileSource.forRecordStreamFormat(
new TextLineInputFormat(),
new Path("gs://<bucket>/<endpoint>")
).build();
env.fromSource(
fileSource,
WatermarkStrategy.noWatermarks(),
"gcs-input"
);
2.2 写入 GCS(FileSink)
java
stream.sinkTo(
FileSink.forRowFormat(
new Path("gs://<bucket>/<endpoint>"),
new SimpleStringEncoder<String>()
).build()
);
2.3 使用 GCS 作为 Checkpoint 存储
java
Configuration config = new Configuration();
config.set(CheckpointingOptions.CHECKPOINT_STORAGE, "filesystem");
config.set(CheckpointingOptions.CHECKPOINTS_DIRECTORY, "gs://<bucket>/<endpoint>");
env.configure(config);
建议:生产把 checkpoint 放对象存储时,要把"认证 + RecoverableWriter 写入语义 + 超时/重试"一起配好,否则最常见的问题就是 checkpoint 慢、失败、恢复失败。
3、GCS 文件系统插件:flink-gs-fs-hadoop
Flink 提供 flink-gs-fs-hadoop 插件来访问 GCS:
-
scheme:
gs:// -
依赖:自包含(无需把 Hadoop 整套依赖加入 classpath)
-
底层实现:
- 使用 Google 的
gcs-connector(Hadoop library)访问 GCS - 同时使用
google-cloud-storage提供 RecoverableWriter 支持(这对 exactly-once/可恢复写很关键)
- 使用 Google 的
-
可用于 FileSystem connector
3.1 安装插件
启动 Flink 前把 JAR 从 opt 拷贝到 plugins:
bash
mkdir ./plugins/gs-fs-hadoop
cp ./opt/flink-gs-fs-hadoop-2.2.0.jar ./plugins/gs-fs-hadoop/
4、配置体系:Flink 配置键 ↔ gcs-connector Hadoop 配置键
flink-gs-fs-hadoop 支持直接用 gcs-connector 的 Hadoop 配置键,但你写到 flink-conf.yaml 时要用 Flink 的前缀形式,Flink 会自动翻译回 Hadoop key。
例子:gcs-connector 的 Hadoop key 是 fs.gs.http.connect-timeout
你在 Flink 配置文件里写:
yaml
gs.http.connect-timeout: xyz
Flink 内部会翻译成 fs.gs.http.connect-timeout
4.1 也可以走 core-site.xml
你也可以把 gcs-connector 选项写在 Hadoop 的 core-site.xml 里,但要确保 Flink 能找到 Hadoop 配置目录:
- 配
env.hadoop.conf.dir(Flink option) - 或设置环境变量
HADOOP_CONF_DIR
这适合平台统一管理 Hadoop 配置的场景。
5、flink-gs-fs-hadoop 的关键增强配置(生产强相关)
下面这些是插件额外支持的 Flink 配置项,最常用、也最容易影响稳定性与成本。
5.1 RecoverableWriter 临时 bucket:强烈建议单独桶 + TTL
yaml
gs.writer.temporary.bucket.name: <temp-bucket>
作用:选择一个 bucket 存放"进行中的写入"临时对象(前缀 .inprogress/)。
为什么建议单独 bucket?
- 恢复/失败重启时可能产生孤儿临时对象(orphaned blobs)
- 单独 bucket 方便设置 TTL 自动清理,省成本、减少垃圾对象堆积
重要风险提示:
如果你给临时 bucket 设置了 TTL,且 TTL 到期把临时对象清掉了,那么在 TTL 之后尝试从旧的 check/savepoint 恢复,可能会失败(因为恢复需要的临时对象已被删)。
实战建议:
- temp bucket 单独建,并设置合理 TTL(比如 7 天/14 天,按你们最长回滚窗口定)
- 运维层明确"可回滚窗口",避免 TTL 比回滚窗口还短
5.2 写入分块大小(chunk size)
yaml
gs.writer.chunk.size: <bytes>
用于 RecoverableWriter 写入的 chunk size。不配则用 Google 默认值。
调参经验:
- 大文件写入吞吐不足,可考虑增大 chunk
- 小文件居多时,chunk 不必太大,避免内存占用与无效缓冲
5.3 FileSink 熵注入:缓解 GCS 热点(hotspotting)
yaml
gs.filesink.entropy.enabled: true
启用后,会在"临时对象"的 gcs path 开头注入熵(例如临时 object id),以提升并发性能、降低前缀热点问题。最终对象路径保持不变。
适用场景:
- 高并发写入同一前缀目录
- 观察到 GCS 前缀热点导致写入抖动或限速
5.4 HTTP 超时与重试(稳定性关键)
yaml
gs.http.connect-timeout: <ms>
gs.http.read-timeout: <ms>
gs.retry.max-attempt: <n>
gs.retry.init-rpc-timeout: <ms>
gs.retry.rpc-timeout-multiplier: <float>
gs.retry.max-rpc-timeout: <ms>
gs.retry.total-timeout: <ms>
建议思路:
- 先把 connect/read timeout 设成"可接受的最大等待",避免无穷卡死
- retry.total-timeout 控制"总体重试窗口",配合 checkpoint 超时一起考虑
- multiplier + max-rpc-timeout 控制指数退避上限,避免越退越慢拖垮恢复时间
6、认证:两种方式与一个非常重要的坑
GCS 大部分操作都需要认证。推荐方式如下。
6.1 推荐:GOOGLE_APPLICATION_CREDENTIALS(环境变量)
在 JobManager 与 TaskManager 运行的机器/容器上设置:
GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa.json
这是推荐方法,通常也最省事。
6.2 另一种:core-site.xml 指定 keyfile
在 core-site.xml 里配置:
xml
<configuration>
<property>
<name>google.cloud.auth.service.account.json.keyfile</name>
<value>PATH TO GOOGLE AUTHENTICATION JSON FILE</value>
</property>
</configuration>
并确保 Flink 知道 Hadoop 配置目录(env.hadoop.conf.dir 或 HADOOP_CONF_DIR)。
6.3 必须确保启用 Service Account(默认启用,但可能被关)
如果 core-site.xml 里把它关了,会导致服务账号认证不可用:
xml
<configuration>
<property>
<name>google.cloud.auth.service.account.enable</name>
<value>false</value>
</property>
</configuration>
生产上一般不要关。
6.4 重要坑:不要用"其它 gcs-connector 认证选项"
gcs-connector 还有别的认证方式,但如果你用那些方式,凭证可能不会被 google-cloud-storage library 识别,而 RecoverableWriter 正是依赖它。结果就是:
- RecoverableWriter 的可恢复写入预期失败
- 作业从 checkpoint 恢复、或 exactly-once 写入链路出现问题
因此,除 google.cloud.auth.service.account.json.keyfile / GOOGLE_APPLICATION_CREDENTIALS 这两条主线外,不建议走其它认证配置。
7、一份可直接套用的生产配置清单(示例)
yaml
# 插件已安装:flink-gs-fs-hadoop-2.2.0.jar
# checkpoint 放 GCS(示例,实际在代码或 flink-conf / SQL 配置里指定)
# state.checkpoints.dir: gs://<bucket>/checkpoints/<job>/
# RecoverableWriter 临时桶(建议单独桶并配 TTL)
gs.writer.temporary.bucket.name: <temp-bucket>
# 写入性能(按需)
# gs.writer.chunk.size: 8388608 # 8MB 示例
# Filesink 热点优化(按需)
gs.filesink.entropy.enabled: true
# 超时与重试(按需)
gs.http.connect-timeout: 20000
gs.http.read-timeout: 60000
gs.retry.max-attempt: 5
gs.retry.total-timeout: 300000