注:次文档参考 Flink v1.11 官方文档
Deployment & Operations
部分进行编写。
由于精力有限,部分内容并未整理,详见官网。
此文档仅用作个人学习,请勿用于商业获利。
以上模式的区别在于:
Session Mode
这种模式会预先在 yarn 或者或者 k8s 上启动一个 flink 集群,然后将任务提交到这个集群上,这种模式,集群中的任务使用相同的资源,如果某一个任务出现了问题导致整个集群挂掉,那就得重启集群中的所有任务,这样就会给集群造成很大的负面影响。
Per-Job Mode
考虑到集群的资源隔离情况,一般生产上的任务都会选择 Per-Job 模式,也就是每个任务启动一个 flink 集群,各个集群之间独立运行,互不影响,且每个集群可以设置独立的配置。
目前,对于 Per-Job 模式,jar 包的解析、生成 JobGraph 是在客户端上执行的,然后将生成的 jobgraph 提交到集群。很多公司都会有自己的实时计算平台,用户可以使用这些平台提交 flink 任务,如果任务特别多的话,那么这些生成 JobGraph、提交到集群的操作都会在实时平台所在的机器上执行,那么将会给服务器造成很大的压力。
Application Mode
详见 1.1.3 Application Mode
作为现代企业的重要工具,流处理和实时分析这类工具逐渐兴起,越来越多的企业以 Apache Flink 为核心构建平台,并将其作为服务在内部提供。在最新举办的 Flink Forward 会议中, Uber、 Netflix 和阿里巴巴等公司的许多相关主题演讲进一步说明了这一趋势。
众多平台旨在通过减轻最终用户的所有运营负担来简化内部的 Application (应用)提交。为了提交 Flink 应用程序,这些平台通常只公开一个集中式或低并行度端点(例如 Web 前端)用于应用提交,我们将其称为 Deployer(部署器)。
平台开发人员和维护人员经常提到的障碍之一是,Deployer 可能是一个很难配置的大量资源消耗者。如果按照平均负载进行配置,可能会导致 Deployer 服务被部署请求淹没(在最坏的情况下,短时间内对所有生产应用程序都是如此),而按照最高负载进行规划的话,又会带来不必要的成本。根据这一观察结果,Flink 1.11 引入了 Application 模式(应用模式)作为部署选项,它允许一个轻量级、更可伸缩性的应用提交过程,从而使应用程序部署负载更均匀地分布在集群的各个节点上。
为了理解这个问题以及了解 Application 模式如何解决该问题,我们首先简要概述 Flink 中应用程序执行的当前状态,然后再阐述部署模式引入的架构变化以及如何利用它们。
Flink 中的应用程序执行
在 Flink 中执行应用程序主要涉及三个实体:
更多细节请参考 Flink 架构 文档。
当前部署模式
在 1.11 版本中引入 Application 模式之前,Flink 允许用户在 Session(会话)或 Per-Job 集群上执行应用程序。两者之间的差异与集群生命周期和它们提供的资源隔离保证有关。
Session 模式(会话模式)假定集群已经运行,并使用该集群的资源来执行任何提交的应用程序。在同一(Session)集群中执行的应用程序使用相同的资源,并因此相互竞争。
这样做的好处是,你无需为每个提交的作业分配整个集群的资源开销。
但是,如果其中一个作业行为不正常或者关闭了 TaskManager,那么在该 TaskManager 上运行的所有作业都将受到故障的影响。
除了对导致故障的作业产生负面影响之外,这还意味着潜在的大规模恢复过程,即所有重新启动的作业同时访问文件系统,并使其不可用于其他服务。
此外,单个集群运行多个作业意味着 JobManager 的负载更大,它负责集群中所有作业的 bookkeeping。
这种模式非常适合启动短作业,例如交互式查询。
在 Per-Job 模式中,可用的集群管理器框架(如 YARN 或 Kubernetes)用于为每个提交的作业启动 Flink 集群,该集群仅对该作业可用。当作业完成后,集群将关闭,并清理所有延迟的资源(例如文件)。
这种模式提供了更好的资源隔离,因为行为不正常的作业不会影响任何其他作业。
另外,由于每个应用程序都有自己的 JobManager,因此它将 bookkeeping 负载分散到多个实体。
考虑到前面提到的 Session 模式中的资源隔离问题,对于长时间运行的作业,用户经常选择 Per-Job 模式,因为这些作业愿意接受一定程度的启动延迟的增加,以支持弹性。
总之,在 Session 模式中,集群生命周期独立于集群中运行的任何作业,并且集群中运行的所有作业共享其资源。
Per-Job 模式选择为每个提交的作业分配一个集群,已提供更好的资源隔离保证,因为资源不会在作业之间共享。在这种情况下,集群的 生命周期 与 作业的生命周期相关。
Application 提交
Flink 应用程序的执行包括两个阶段:
main() 方法使用 Flink 的 API(DataStream API、Table API、DataSet API)之一构造用户程序。当 main() 方法调用 env.execute() 时,用户定义的管道将被转换成 Job Graph(作业图),并将其传递给集群。
Session 模式和 Per-Job 模式 都会在 Client 执行应用程序的 main() 方法,即 pre-flight 阶段。
对于已经在本地具有其作业的所有依赖关系,然后通过在其机器上运行的 Client 提交其应用程序的单个用户来说,这通常不是问题。但是,对于通过远程实体(如 Deployer)提交的情况下,这个过程包括:
1. 本地下载应用程序的依赖项;
2. 执行 main() 方法提取 Job Graph;
3. 将 Job Graph 及其依赖项发送到集群以便执行;
4. 等待结果。
这使得 Client 消耗了大量的资源,因为它可能需要大量的网络带宽来下载依赖项或将二进制文件发送到集群,并且需要 CPU 周期来执行 main() 方法。随着越来越多的用户共享同一个 Client,这个问题甚至会变得更加突出。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hjooKavC-1600137656682)(https://flink.apache.org/img/blog/2020-07-14-application-mode/session-per-job.png)]
上图展示了使用三种应用程序( 红 \color{Red}红 红、 蓝 \color{blue}蓝 蓝、 绿 \color{green}绿 绿)的两种部署模式。每个并行度为3。
黑色矩形代表不同的进程:TaskManager、JobManager 和 Deployer。
我们假设在所有情况下都只有一个 Deployer 流程。彩色三角形表示提交进程的负载,而彩色矩形表示 TaskManager 和 JobManager 进程的负载。
如图所示,Per-Job 模式和 Session 模式下的 Deployer 共享相同的负载。它们的不同之处在于任务的分配和 JobManager 负载。
在 Session 模式下,集群中的所有作业共享一个 JobManager。而在 Per-Job 模式下,每个作业都有一个 JobManager。此外,Session 模式下的任务会随机分配给 TaskManager,而在 Per-Job 模式下,每个 TaskManager 只能有单个作业任务。
Application 模式
Application 模式建立在上述观察结果的基础上,并尝试将 Per-Job 模式的资源隔离 与 轻量级且可伸缩的应用提交过程 结合起来。为实现这一点,它为每个提交的应用程序创建一个集群,但是这一次,应用程序的 main() 方法在 JobManager 上执行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TfQB7g1R-1600137656685)(https://flink.apache.org/img/blog/2020-07-14-application-mode/application.png)]
为每个应用程序创建一个集群可以看作是创建一个只在特定应用程序的作业之间共享的 Session 集群,并在应用程序结束时关闭。使用这种架构,Application 模式提供与 Per-Job 模式相同的资源隔离和负载平衡保证,但在整个应用程序的粒度上。这是有道理的,因为属于同一应用程序的工作应该相互关联,并被视为一个单元。
在 JobManager 上执行 main() 方法, 不仅可以节省提取 Job Graph 所需的 CPU 周期,也可以节省 Client 本地下载依赖项并将 Job Graph 及其依赖项发送到集群所需的带宽。
此外,由于每个应用程序只有一个 JobManager,因此,它可以更均匀地分散网络负载。
上图对此进行了说明,其中我们具有与 “Session 和 Per-Job 部署模式” 部分中相同的场景,但是这一次 Client 负载已经转移到了每个应用程序的 JobManager。
注:在 Application 模式下, main() 方法是在集群上执行的,而不是像在其他模式中那样在 Client 上执行。这可能对代码产生影响,例如,使用 regsiterCachedFile() 在环境中注册的任何路径都必须由应用程序的 JobManager 进行访问。
与 Per-Job 模式相比,Application 模式允许提交由多个作业组成的应用程序。作业执行的顺序不受部署模式的影响,而是受用于启动作业的调用的影响。使用阻塞 execute() 方法建立一个顺序,并将导致 “next” 作业的执行被延迟到 “this” 作业完成为止。相反,一旦提交了当前作业,非阻塞 executeAsync() 方法将立即继续提交 “next” 作业。
降低网络需求
如上所述,通过在 JobManager 上执行应用程序的 main() 方法,Application 模式可以节省以前在提交作业时所需的大量资源。但仍有改进的余地。
重点关注 YARN,YARN 已经支持此处提到的所有优化,即使 Application 模式已经就绪,Client 仍然需要发送用户 Jar 到 JobManager。此外,对于每个应用程序,Client 必须将 “flink-dist” 目录发送到集群,该目录包含框架本身的二进制文件,包括 flink-dist.jar 、 lib/ 和 plugin/ 目录。这两者可能会在 Client 占用大量带宽。此外,在每次提交时发送相同的 flink-dist 二进制文件既是对带宽的浪费,也是对存储空间的浪费。只需允许应用程序共享相同的二进制文件即可减少存储空间的浪费。
在 Flink 1.11 中,我们引入了允许用户执行以下操作的选项:
指定一个目录的远程路径,在该目录中,YARN 可以找到 Flink 分发二进制文件。
指定一个远程路径,YARN 可以在其中找到用户 Jar。
对于第一步,我们利用了 YARN 的分布式缓存,并允许应用程序共享这些二进制文件。因此,如果一个应用程序碰巧在它的 TaskManager 的本地存储中找到了 Flink 的副本,由于之前的一个应用程序在同一个 TaskManager 上执行,它甚至都不需要在内部下载它。
注:这两种优化都可以用于 YARN 上的所有部署模式,而不仅仅是 Application 模式。
示例:YARN 上的 Application 模式
有关完整说明,请参阅 Flink 的官方文档,更具体地说,请参阅引用集群管理框架的页面,例如 YARN 或 Kubernetes。接下来我将给出一些关于 YARN 的例子,其中上述所有功能都是可用的。
要以 Application 模式启动用用程序,可以使用:
./bin/flink run-application -t yarn-application ./MyApplication.jar
使用这条命令,所有的配置参数,例如用于引导应用程序状态的保存点的路径,或者所需的 JobManager/TaskManager 内存大小,都可以通过它们的配置选项(以 -d 作为前缀)来指定。有关可用配置选项的目录,请参阅 配置参数。
例如,指定 JobManager 和 TaskManager 内存大小的命令如下所示:
./bin/flink run-application -t yarn-application \
-Djobmanager.memory.process.size=2048m \
-Dtaskmanager.memory.process.size=4096m \
./MyApplication.jar
如前所述,以上内容将确保您的应用程序的 main() 方法将在 JobManager 上执行。
为了进一步节省将Flink发行版运送到群集的带宽,请考虑将 Flink 发行版预上传到 YARN 可以访问的位置,并使用 yarn.provided.lib.dirs 配置选项,如下所示:
./bin/flink run-application -t yarn-application \
-Djobmanager.memory.process.size=2048m \
-Dtaskmanager.memory.process.size=4096m \
-yD yarn.provided.lib.dirs="hdfs://myhdfs/remote-flink-dist-dir" \
./MyApplication.jar
最后,为了进一步节省提交应用程序 Jar 所需的带宽,可以预先将其上传到 HDFS,并指定指向 ./MyApplication.jar 的远程路径,如下所示:
./bin/flink run-application -t yarn-application \
-Djobmanager.memory.process.size=2048m \
-Dtaskmanager.memory.process.size=4096m \
-yD yarn.provided.lib.dirs="hdfs://myhdfs/remote-flink-dist-dir" \
hdfs://myhdfs/jars/MyApplication.jar
这将使作业提交变得更加轻量级,因为所需的 Flink jar 和应用程序 Jar 将从指定的远程位置提取,而不是由 Client 发送到集群。Client 将唯一提供给集群的是应用程序的配置,其中包括上述提到的所有路径。
原文链接: Application Deployment in Flink: Current State and the new Application Mode
下载启动
检查 Java 版本
java -version
从 下载页面 下载二进制文件。您可以选择任何您喜欢的 Scala 版本。对于某些功能,您可能还需要下载一个预先捆绑的 Hadoop jar 并将其放入 $FLINK_HOME/lib 目录中。
# 创建用户
userdel -r flink && useradd flink && echo flink | passwd --stdin flink
# 下载
su - flink
wget https://mirrors.tuna.tsinghua.edu.cn/apache/flink/flink-1.11.1/flink-1.11.1-bin-scala_2.11.tgz
# 解压
tar -zxvf flink-1.11.1-bin-scala_2.11.tgz
# 创建软链
ln -s flink-1.11.1 flink
# 配置环境变量
vim ~/.bashrc
export FLINK_HOME=/home/software/flink/flink-1.11.0
export PATH=$PATH:$FLINK_HOME/bin:
source ~/.bashrc
启动
/home/flink/flink-1.11.1/bin/start-cluster.sh
# UI
http://localhost:8081
停止
/home/flink/flink-1.11.1/bin/stop-cluster.sh
Apache Flink® 1.11.1 是当前最新的稳定版本。
如果你计划将 Apache Flink 与 Apache Hadoop 一起使用(在 YARN 上运行 Flink ,连接到 HDFS ,连接到 HBase ,或使用一些基于 Hadoop 文件系统的 connector ),请查看 Hadoop 集成文档。
Release Notes - Flink 1.11
原文链接:https://ci.apache.org/projects/flink/flink-docs-release-1.11/zh/release-notes/flink-1.11.html
Maven 依赖
你只要将以下依赖项添加到 pom.xml 中,就能在项目中引入 Apache Flink 。这些依赖项包含了本地执行环境,因此支持本地测试。
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-javaartifactId>
<version>1.11.1version>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-streaming-java_2.11artifactId>
<version>1.11.1version>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-clients_2.11artifactId>
<version>1.11.1version>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-scala_2.11artifactId>
<version>1.11.1version>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-streaming-scala_2.11artifactId>
<version>1.11.1version>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-clients_2.11artifactId>
<version>1.11.1version>
dependency>
从源码构建 Flink
前提:
注意:Maven 3.3.x 可以构建 Flink,但是不能正确地遮盖某些依赖项。Maven 3.2.5会正确创建库。
要构建单元测试,请使用 Java 8u51 或更高版本,以防止使用 PowerMock 运行器的单元测试失败。
下载源码
wget http://archive.apache.org/dist/flink/flink-1.11.1/flink-1.11.1-src.tgz
构建 Flink 的最简单方法:
mvn clean install -DskipTests
这指示 Maven(mvn)首先删除所有现有的内部版本(clean),然后创建一个新的 Flink 二进制文件(install)。
为了加快构建速度,您可以跳过测试,QA 插件 和 JavaDocs:
mvn clean install -DskipTests -Dfast
# Scala version 2.11 (default)
# mvn clean install -DskipTests -Dscala-2.12
编译好的文件
flink-1.11.1/flink-dist/target/flink-1.11.1-bin/
tar -zcvf flink-1.11.1.tgz flink-1.11.1
为了使用 Hadoop 功能(例如YARN,HDFS),必须为 Flink 提供所需的 Hadoop 类,因为默认情况下未捆绑这些类。
推荐的方法是通过 HADOOP_CLASSPATH 环境变量将 Hadoop 类路径添加到 Flink 。
Flink 将使用环境变量 HADOOP_CLASSPATH 来扩展启动 Flink 组件(例如 Client,JobManager 或 TaskManager)时使用的类路径。默认情况下,大多数 Hadoop 发行版和云环境不会设置此变量,因此,如果 Flink 选择 Hadoop 类路径,则必须在运行 Flink 组件的所有计算机上导出环境变量。
在 YARN 上运行时,这通常不是问题,因为在 YARN 中运行的组件将使用 Hadoop 类路径启动,但是在将作业提交给 YARN 时,可能会发生 Hadoop 依赖项必须在类路径中的情况。为此,在 shell 中使用 export HADOOP_CLASSPATH=
hadoop classpath` 通常足以运行。
export HADOOP_CLASSPATH=`hadoop classpath`
export HADOOP_CONF_DIR=/etc/hadoop/conf
export FLINK_HOME=~/flink
export PATH=$PATH:$FLINK_HOME/bin:$HADOOP_CLASSPATH:$HADOOP_CONF_DIR:
在本地执行工作
要使用小型集群将作业作为一个 JVM 进程在本地运行,必须将必需的 hadoop 依赖项显式添加到已启动的 JVM 进程的类路径中。
要使用 Maven 运行应用程序,可以将所需的 Hadoop 依赖项添加到 pom.xml 中,例如:
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-clientartifactId>
<version>2.8.3version>
<scope>providedscope>
dependency>
使用 flink-shaded-hadoop-2-uberjar 解决依赖冲突(旧版)
警告:从 Flink 1.11 开始,flink-shaded-hadoop-2-uberFlink 项目不再正式支持使用发行版。建议用户通过提供 Hadoop 依赖关系 HADOOP_CLASSPATH(请参见上文)。
Flink 1.10 以及之前的 Hadoop 发行版,可以将版本对应的 Pre-bundled Hadoop v* jar 包放入 Flink 的 /lib 目录中就足够了。
如果没有对应的版本,那么可以针对该版本构建 flink 阴影的版本。运行以下命令以 flink-shaded 针对所需的 Hadoop 版本(例如 version 2.6.5-custom )进行构建和安装:
mvn clean install -Dhadoop.version=2.6.5-custom
完成此步骤后,将 flink-shaded-hadoop-2-uber
jar 放入 /lib 分发目录中。
群集由 一个主节点 和 一个或多个工作节点 组成。在开始设置系统之前,请确保在每个节点上都安装了以下软件:
集群规划:
ip/host | jobmanager | taskmanager |
---|---|---|
10.0.0.1 | √ | |
10.0.0.2 | √ | |
10.0.0.3 | √ |
修改配置
转到下载页面并获取准备运行的软件包。确保选择与您的 Hadoop 版本匹配的 Flink 软件包。如果您不打算使用 Hadoop,请选择任何版本。
# 主节点配置
jobmanager.rpc.address: 10.0.0.1
# 定义允许 Flink 在每个节点上分配的最大主内存量(单位 MB)
# 工作节点也可根据自身内存大小自定义这两个数值
jobmanager.memory.process.size: 2048m
taskmanager.memory.process.size: 4096m
# 定义每台服务器的最大 Slot 数
taskmanager.numberOfTaskSlots: 4
10.0.0.2
10.0.0.3
略
Flink 目录必须在同一路径下的每个工作线程上都可用。您可以使用共享的 NFS 目录,也可以将整个 Flink 目录复制到每个工作节点。
请参阅 配置参数 以获取详细信息和其他配置选项。
特别是以下几个非常重要的配置值:
启动 Flink
start-cluster.sh
# 将 JobManager/TaskManager 实例添加到集群
jobmanager.sh ((start|start-foreground) [host] [webui-port])|stop|stop-all
taskmanager.sh start|start-foreground|stop|stop-all
使用 ./bin/flink
将 程序提交到 Flink 群集:
Action "run" compiles and runs a program.
Syntax: run [OPTIONS] <jar-file> <arguments>
"run" action arguments:
-c,--class <classname> Class with the program entry point ("main"
method or "getPlan()" method. Only needed
if the JAR file does not specify the class
in its manifest.
-m,--jobmanager <host:port> Address of the JobManager to
which to connect. Use this flag to connect
to a different JobManager than the one
specified in the configuration.
-p,--parallelism <parallelism> The parallelism with which to run the
program. Optional flag to override the
default value specified in the
configuration
Example :
wget -O LICENSE-2.0.txt http://www.apache.org/licenses/LICENSE-2.0.txt
hadoop fs -copyFromLocal LICENSE-2.0.txt hdfs:///tmp
flink run ~/flink/examples/batch/WordCount.jar --input hdfs:///tmp/LICENSE-2.0.txt --output hdfs:///tmp/wordcount-result-dir
Start a long-running Flink cluster on YARN
# If HADOOP_CLASSPATH is not set:
# export HADOOP_CLASSPATH=`hadoop classpath`
./bin/yarn-session.sh -jm 1024m -tm 4096m
Run a single Flink job on YARN
# If HADOOP_CLASSPATH is not set:
# export HADOOP_CLASSPATH=`hadoop classpath`
flink run -m yarn-cluster -p 4 -yjm 1024m -ytm 4096m ~/flink/examples/batch/WordCount.jar --input hdfs:///tmp/test.txt --output hdfs:///tmp/wordcount-result-dir
以上运行的任务可以在 Yarn ResourceManager 管理页上查看。
使用 yarn-session.sh -h
查看具体指令
Usage:
Optional
-at,--applicationType <arg> Set a custom application type for the application on YARN
-D <property=value> use value for given property
-d,--detached If present, runs the job in detached mode
-h,--help Help for the Yarn session CLI.
-id,--applicationId <arg> Attach to running YARN session
-j,--jar <arg> Path to Flink jar file
-jm,--jobManagerMemory <arg> Memory for JobManager Container with optional unit (default: MB)
-m,--jobmanager <arg> Address of the JobManager to which to connect. Use this flag to connect to a different JobManager than the one specified in the configuration.
-nl,--nodeLabel <arg> Specify YARN node label for the YARN application
-nm,--name <arg> Set a custom name for the application on YARN
-q,--query Display available YARN resources (memory, cores)
-qu,--queue <arg> Specify YARN queue.
-s,--slots <arg> Number of slots per TaskManager
-t,--ship <arg> Ship files in the specified directory (t for transfer)
-tm,--taskManagerMemory <arg> Memory per TaskManager Container with optional unit (default: MB)
-yd,--yarndetached If present, runs the job in detached mode (deprecated; use non-YARN specific option instead)
-z,--zookeeperNamespace <arg> Namespace to create the Zookeeper sub-paths for high availability mode
请注意,客户端要求将 YARN_CONF_DIR
或 HADOOP_CONF_DIR
环境变量设置为读取 YARN 和 HDFS 配置。
示例:发出以下命令以启动Yarn会话集群,在该集群中,每个任务管理器均以 8 GB 内存和 32 个处理插槽启动:
./bin/yarn-session.sh -tm 8192 -s 32
# 使用 Ctrl + C 关闭 Flink 集群
系统将使用中的配置 conf/flink-conf.yaml。如果要更改某些内容,请遵循我们的 配置参数。
YARN 上的 Flink 将覆盖以下配置参数 jobmanager.rpc.address
(因为 JobManager 始终分配在不同的机器上),io.tmp.dirs
(我们使用的是 YARN 提供的 tmp 目录)以及 parallelism.default
是否指定了插槽数。
如果您不想更改配置文件来设置配置参数,则可以选择通过 -D
标志传递动态属性。因此,您可以通过以下方式传递参数: -Dfs.overwrite-files=true -Dtaskmanager.memory.network.min=536346624
。
示例调用为运行作业管理器的 ApplicationMaster 启动了一个容器。当作业提交到集群时,会话集群将自动分配运行任务管理器的其他容器。
将 Flink 部署到 YARN 群集中后,它将向您显示作业管理器的连接详细信息。
仅当群集上的 ApplicationMaster 有足够的资源可用时,YARN 上的 Flink 才会启动。大多数 YARN 调度程序都考虑了容器的请求内存,有些还考虑了 vcore 的数量。默认情况下,vcore 的数量等于处理插槽(-s)参数。在 yarn.containers.vcores 允许覆盖 vcores 的数量与自定义值。为了使此参数起作用,您应该在集群中启用 CPU 调度。
在 YARN 上启动一个长期运行的 Flink 集群
如果您不想一直保持 Flink YARN 客户端运行,也可以启动一个分离的 YARN 会话。该参数称为 -d
或 --detached
。在这种情况下,Flink YARN 客户端只会将 Flink 提交到群集,然后自行关闭。
# If HADOOP_CLASSPATH is not set:
# export HADOOP_CLASSPATH=`hadoop classpath`
# 开启一个有 8个 slots,每个 jobManager 内存为 1G,每个 TaskManager 内存为 1G 的 Yarn Session
yarn-session.sh -s 8 -jm 1024 -tm 1024 -nm YarnSessionDemo -d
# 可使用以下两种方式关闭 Flink 集群
echo "stop" | yarn-session.sh -id <appId>
yarn application -kill applicationId // 但是请注意,杀死 Flink 可能不会清除所有作业工件和临时文件。
附加到现有会话
yarn application -list
yarn-session.sh -id applicationId/yarnAppId
提交任务
在 Web UI 上提交运行 Jar 包并执行
OR
flink run -yid application_12345678 ~/flink/examples/batch/WordCount.jar --input hdfs:///tmp/test.txt --output hdfs:///tmp/wordcount-result.txt
上面的文档描述了如何在 Hadoop YARN 环境中启动 Flink 集群。也可以仅在执行单个作业时在 YARN 中启动 Flink。
例:
./bin/flink run -m yarn-cluster ./examples/batch/WordCount.jar
该 ./bin/flink 工具还提供 YARN 会话的命令行选项。它们以 y 或 yarn 为前缀(用于长参数选项)。
注意:通过设置环境变量,可以为每个作业使用不同的配置目录 FLINK_CONF_DIR
。要使用此副本,请从 Flink 分发版复制 conf 目录并进行修改。
User jars & Classpath
用户依赖管理还是有一定的注意事项的,默认情况下当单个 job 在运行的时候 flink 会将用户 jar 包含进 系统 chasspath
内部。该行为也可以通过 yarn.per-job-cluster.include-user-jar
参数进行控制。
当将该参数设置为 DISABLED,Flink 会将 jar 放入到 用户 classpath
里面(这里要强调一下,前面说的是 系统 classpath,而这里是 用户 classpath)。
用户 jar 的在 classpath 的位置顺序是由该参数的下面几个值决定的:
要以 应用程序模式
启动应用程序,您可以输入:
./bin/flink run-application -t yarn-application ./examples/batch/WordCount.jar
注意:除了 -t 以外,所有其他配置参数(例如,用于引导应用程序状态的保存点的路径,应用程序并行性或所需的作业管理器/任务管理器内存大小)可以通过其配置选项(带前缀)来指定由 -D。
更多配置选项,参考 配置参数
例如,用于指定 JM 和 TM 的内存大小的命令如下所示:
flink run-application -t yarn-application -Djobmanager.memory.process.size=2048m -Dtaskmanager.memory.process.size=4096m ~/flink/examples/batch/WordCount.jar --input hdfs:///tmp/LICENSE-2.0.txt --output hdfs:///tmp/wordcount-result2.txt
要释放应用程序模式的全部潜力,请考虑将其与 yarn.provided.lib.dirs 配置选项一起使用,并将您的应用程序 jar 预上传到群集中所有节点均可访问的位置。在这种情况下,命令如下所示:
flink run-application -t yarn-application \
-yD yarn.provided.lib.dirs="hdfs://myhdfs/my-remote-flink-dist-dir" \
hdfs://myhdfs/jars/my-application.jar
上面的方法可以使作业提交更加轻巧,因为所需的 Flink jar 和应用 jar 将由指定的远程位置拾取,而不是由客户端运送到集群。
使用 yarn.application-attempts
控制容器发生故障时的行为方式。可以从 conf/flink-conf.yaml 或在启动 YARN 会话时使用 -D 参数进行设置。
yarn.application-attempts
: ApplicationMaster(及其 TaskManager 容器)的尝试次数。如果将此值设置为 1(默认值),则当 ApplicationMaster 失败时,整个 YARN 会话将失败。
yarn.application.priority
:一个非负整数,表示提交 Flink YARN 申请的优先级。仅在启用 YARN 优先级调度设置后才会生效。整数越大,优先级越高。如果优先级为负或设置为 -1(默认值),则 Flink 将取消 Yarn 优先级设置,并使用群集默认优先级。
Flink YARN session 部署失败的原因有很多。
错误配置的 Hadoop 设置(HDFS 权限,YARN 配置),版本不兼容(运行 Flink 以及 Cloudera Hadoop 上的原始 Hadoop 依赖项)或其他错误。
Log Files
如果 Flink YARNsession 在部署本身期间失败,则用户必须依赖 Hadoop YARN 的日志记录功能。
最有用的功能是 YARN 日志聚合。要启用它,需要设置 yarn.log-aggregation-enable 属性设置为 true。
启用后,用户可以使用以下命令来检索(失败的) YARN session 的所有日志文件。
yarn logs -applicationId <application ID>
YARN 客户端控制台和 Web 界面 - YARN Client console & Web interfaces
如果在运行期间发生错误(例如,如果 TaskManager 在一段时间后停止工作),则 Flink YARN session 还会在终端中显示错误消息。
除此之外,还有 YARN Resource Manager Web 界面(默认情况下在端口 8088 上)。资源管理器 Web 界面的端口由 yarn.resourcemanager.webapp.address
配置值确定。
它允许访问运行 YARN 应用程序的日志文件,并显示失败应用程序的诊断信息。
使用 Hortonworks,Cloudera 或 MapR 等公司的 Hadoop发行版的用户可能必须针对其特定版本的 Hadoop(HDFS) 和 YARN 构建 Flink。请阅读构建说明以了解更多详细信息。
某些 YARN 群集使用防火墙来控制群集与网络其余部分之间的网络流量。在这些设置中,只能将 Flink 作业从群集网络内(在防火墙之后)提交到 YARN 会话。如果这对于生产用途不可行,则 Flink 允许为其 REST 端点配置端口范围,该端口范围用于客户端群集通信。配置了此范围后,用户还可以将作业提交给穿越防火墙的 Flink。
用于指定 REST 端点端口的配置参数如下:
rest.bind-port
: 此配置选项接受单个端口(例如:“50010”),范围(“50000-50025”)或两者的组合(“50010,50011,50020-50025,50050-50075”)。请确保 rest.port 未指定配置选项,因为它优先于 rest.bind-port 并且不接受范围。
(Hadoop 使用了类似的机制,其中的配置参数称为 yarn.app.mapreduce.am.job.client.port-range
。)
本节简要介绍了 Flink 和 YARN 的交互方式。
YARN 客户端需要访问 Hadoop 配置以连接到 YARN 资源管理器和 HDFS。它使用以下策略确定 Hadoop 配置:
YARN_CONF_DIR
, HADOOP_CONF_DIR
或 HADOOP_CONF_PATH
设置(按顺序)。如果设置了这些变量之一,则将其用于读取配置。$HADOOP_HOME/etc/hadoop
(Hadoop 2) 和 $HADOOP_HOME/conf
(Hadoop 1)。在启动新的 Flink YARN session 时,客户端首先检查所请求的资源(ApplicationMaster 的内存和 vcore)是否可用。之后,它将包含 Flink 和配置的 jar 上传到 HDFS(步骤1)。
客户端的下一步是请求(步骤2)YARN 容器来启动 ApplicationMaster(步骤3)。
由于客户端将配置和 jar 文件注册为容器的资源,因此在指定的 NodeManager 将负责准备容器(例如,下载文件)。完成后,将启动 ApplicationMaster(AM)。
JobManager 和 AM 在同一容器中运行。一旦成功启动,AM 就会知道 JobManager(其自己的主机)的地址。AM 会为 TaskManager 生成一个新的 Flink 配置文件,以便它们可以连接到 JobManager。该文件还上传到 HDFS。此外,AM 容器还提供 Flink 的 Web 界面。YARN 代码分配的所有端口都是临时端口。这使用户可以并行执行多个 Flink YARN 会话。
之后,AM 开始为 Flink 的 TaskManager 分配容器,这将从 HDFS 下载 jar 文件和修改后的配置。
完成这些步骤后,Fink 就完全启动并等待接收提交的 Jobs。
以下为更具体的步骤和各组件的用途。
ResourceManager
NodeManager
ApplicationMaster
Flink on yarn 集群启动步骤 :
国内不常用,此处略。
详见官网: https://ci.apache.org/projects/flink/flink-docs-release-1.11/ops/deployment/mesos.html
详见官网:https://ci.apache.org/projects/flink/flink-docs-release-1.11/ops/deployment/docker.html
详见官网:https://ci.apache.org/projects/flink/flink-docs-release-1.11/ops/deployment/kubernetes.html
详见官网:https://ci.apache.org/projects/flink/flink-docs-release-1.11/ops/deployment/native_kubernetes.html
JobManager 协调每个 Flink 部署。它既负责 调度 又负责 资源管理。
默认情况下,每个 Flink 集群只有一个 JobManager 实例。这将创建一个单点故障(SPOF):如果 JobManager 崩溃,则无法提交任何新程序,并且正在运行的程序也会失败。
使用 JobManager 高可用性,您可以从 JobManager 故障中恢复并消除 SPOF。您可以为独立群集和 YARN 群集配置高可用性。
在 Flink Wiki 中的 JobManager High Availability 中查看更多 HA 实现细节。
独立集群的 JobManager HA 的总体思想是,随时都有一个 leading JobManager,并且有多个备用 JobManager 可以在领导者失败的情况下接管领导。这样可以保证不会出现单点故障,并且只要待机 JobManager 处于领导地位,程序就可以取得进展。备用 JobManager 实例和主 JobManager 实例之间没有明显区别。每个 JobManager 都可以充当主角色或备用角色。
作为示例,请考虑以下三个 JobManager 实例的设置:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rI0NeNhi-1600137656689)(https://ci.apache.org/projects/flink/flink-docs-release-1.11/fig/jobmanager_ha_overview.png)]
配置
要启用 JobManager HA,需要使用 zookeeper,配置 ZooKeeper quorum 并在 masters 配置文件中设置 JobManager hosts 及其 Web UI 端口。
需要修改以下配置:
jobManagerAddress1:webUIPort1
[...]
jobManagerAddressX:webUIPortX
默认情况下,jobmanager 将选择一个随机端口进行进程间通信。您可以通过 high-availability.jobmanager.port
更改它。此键接受单个端口 (例如50010),范围 (50000-50025) 或两者的组合 (50010,50011,50020-50025,50050-50075)。
# high-availability mode (required)
high-availability: zookeeper
# ZooKeeper quorum (required)
high-availability.zookeeper.quorum: address1:2181[,...],addressX:2181
# ZooKeeper root (recommended)
high-availability.zookeeper.path.root: /flink
# ZooKeeper cluster-id (recommended): cluster-id ZooKeeper 节点,在该节点下放置了群集的所有必需协调数据
high-availability.cluster-id: /flink_cluster # important: 每个集群自定义
# 注: 在运行 YARN cluster, a per-job YARN session, 或者其他的 cluster manager 时,不应手动设置此值。在这些情况下,将根据应用程序 ID 自动生成 cluster-id。手动设置 cluster-id 会覆盖 YARN 中的这个配置。使用 -z CLI 选项指定集群id,则会覆盖手动配置。如果您在裸机上运行多个 Flink HA 群集,则必须为每个群集手动配置单独的群集 ID。
# 此处参数使用默认值就好,强烈建议不要设置使用此参数。
# Storage directory (required): JobManager 元数据保留在文件系统 storageDir 中,并且仅将指向此状态的指针存储在 ZooKeeper 中
high-availability.storageDir: hdfs:///flink/ha
Example
flink-conf.yaml
high-availability: zookeeper
high-availability.zookeeper.quorum: 10.0.0.1:2181,10.0.0.2:2181,10.0.0.3:2181
high-availability.zookeeper.path.root: /flink
high-availability.cluster-id: /flink_cluster # important: customize per cluster
high-availability.storageDir: hdfs:///flink/ha
masters
# 同一台机器可以有多个 jobmanager
10.0.0.1:8081
10.0.0.1:8082
10.0.0.2:8081
workers
10.0.0.1
10.0.0.2
10.0.0.3
下发配置文件
scp ~/flink/conf/* 10.0.0.2:~/flink/conf/
scp ~/flink/conf/* 10.0.0.3:~/flink/conf/
启动集群
start-cluster.sh
停止集群
stop-cluster.sh
在运行高可用性的 YARN 群集时,我们不会运行多个 JobManager(ApplicationMaster) 实例,而只会运行一个实例,当实例发生故障时,它将由 YARN 重新启动。确切的行为取决于您使用的特定 YARN 版本。
配置
yarn-site.xml - 配置 application master 的最大尝试次数
<property>
<name>yarn.resourcemanager.am.max-attemptsname>
<value>10value>
<description>
The maximum number of application master execution attempts.
description>
property>
当前 YARN 版本的默认值为 2(表示可以容忍单个 JobManager 故障)。
flink-conf.yaml - 配置最大尝试次数
yarn.application-attempts: 10
这意味着在 YARN 使应用程序失败之前,可以为失败的尝试将应用程序重新启动 9 次(9 次重试 +1 次初始尝试)。
如果 YARN 操作需要(清空、节点硬件故障 或 重新引导 或 NodeManager 重新同步),YARN 可以重新启动,这些重新启动不计入 yarn.application-attempts,请参阅 Jian Fang的博客文章。
重要的是要注意,这 yarn.resourcemanager.am.max-attempts 是应用程序重新启动的上限。因此,在 Flink 中设置的 应用程序尝试次数(yarn.application-attempts) 不能超过 YARN cluster 的设置。
容器关闭行为
注意:Hadoop YARN 2.4.0 有一个主要错误(在 2.5.0 中修复),阻止重新启动的 Application Master/Job Manager 容器重启容器。有关详细信息,请参阅 FLINK-4142。我们建议至少在 YARN 上使用 Hadoop 2.5.0 进行高可用性设置。
Example:YarnSession HA
flink-conf.yaml
high-availability: zookeeper
high-availability.zookeeper.quorum: 10.0.0.1:2181,10.0.0.2:2181,10.0.0.3:2181
high-availability.storageDir: hdfs:///flink/ha
high-availability.zookeeper.path.root: /flink
yarn.application-attempts: 10
启动 YarnSession
yarn-session.sh
如果 ZooKeeper 使用 Kerberos 以安全模式运行,则可以 flink-conf.yaml 根据需要覆盖以下配置:
zookeeper.sasl.service-name: zookeeper # default is "zookeeper". If the ZooKeeper quorum is configured
# with a different service name then it can be supplied here.
zookeeper.sasl.login-context-name: Client # default is "Client". The value needs to match one of the values
# configured in "security.kerberos.login.contexts".
Flink 附带了用于 3.4 和 3.5 的单独 Zookeeper 客户端,其中 3.4 位于 lib 发行目录中,因此默认使用,而 3.5 放置在 opt 目录中。
3.5 客户端允许您通过 SSL 保护 Zookeeper 连接,但可能不适用于 3.4-Zookeeper 安装。
您可以通过将任一 jar 放在 lib 目录中来控制 Flink 使用哪个版本。
如果没有正在运行的 ZooKeeper,可以使用 Flink 附带的帮助程序脚本。
中有一个 ZooKeeper 配置模板 conf/zoo.cfg。您可以配置主机并在其上运行 ZooKeeper。
该脚本 bin/start-zookeeper-quorum.sh 将在每个配置的主机上启动 ZooKeeper 服务器。启动的进程通过 Flink 包装器启动 ZooKeeper 服务器,该包装器从中读取配置 conf/zoo.cfg 并确保设置一些必需的配置值以方便使用。在生产设置中,建议管理您自己的 ZooKeeper 安装。
Checkpoint 使 Flink 的状态具有良好的容错性,通过 checkpoint 机制,Flink 可以对 作业的状态
和 计算位置
进行恢复。
参考 Checkpointing 查看如何在 Flink 程序中开启和配置 checkpoint。
Checkpoint 在默认的情况下仅用于 恢复失败的作业,并不保留,当程序取消时 checkpoint 就会被删除。 当然,你可以通过配置来保留 checkpoint,这些被保留的 checkpoint 在作业失败或取消时不会被清除。这样,你就可以使用该 checkpoint 来恢复失败的作业。
CheckpointConfig config = env.getCheckpointConfig();
config.enableExternalizedCheckpoints(ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
ExternalizedCheckpointCleanup 配置项定义了当作业取消时,对作业 checkpoint 的操作:
ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION
:当作业取消时,保留作业的 checkpoint。注意,这种情况下,需要手动清除该作业保留的 checkpoint。ExternalizedCheckpointCleanup.DELETE_ON_CANCELLATION
:当作业取消时,删除作业的 checkpoint。仅当作业失败时,作业的 checkpoint 才会被保留。目录结构
与 savepoints 相似,checkpoint 由元数据文件、数据文件(与 state backend 相关)组成。可通过配置文件 flink-conf.yaml 中 state.checkpoints.dir
配置项来指定元数据文件和数据文件的存储路径,另外也可以在代码中针对单个作业特别指定该配置项。
当前的 checkpoint 目录结构(由 FLINK-8531 引入)如下所示:
/user-defined-checkpoint-dir
/{job-id}
|
+ --shared/
+ --taskowned/
+ --chk-1/
+ --chk-2/
+ --chk-3/
...
其中 SHARED 目录保存了可能被多个 checkpoint 引用的文件,TASKOWNED 保存了不会被 JobManager 删除的文件,EXCLUSIVE 则保存那些仅被单个 checkpoint 引用的文件。
注意: Checkpoint 目录不是公共 API 的一部分,因此可能在未来的 Release 中进行改变。
通过 flink-conf.yaml 全局配置
state.checkpoints.dir: hdfs:///flink/checkpoints/default
创建 state backend 对单个作业进行配置
env.setStateBackend(new RocksDBStateBackend("hdfs:///flink/checkpoints/"));
Checkpoint 与 Savepoint 的区别
Checkpoint 与 savepoints 有一些区别,体现在 checkpoint :
从保留的 checkpoint 中恢复状态
与 savepoint 一样,作业可以从 checkpoint 的元数据文件恢复运行。注意,如果元数据文件中信息不充分,那么 jobmanager 就需要使用相关的数据文件来恢复作业(参考目录结构)。
./bin/flink run -s <savepointPath> :runArgs
./bin/flink run -s <savepointPath> -n :runArgs
Savepoint 是依据 Flink checkpointing 机制 所创建的流作业执行状态的一致镜像。 你可以使用 Savepoint 进行 Flink 作业的停止与重启、fork 或者更新。
Savepoint 由两部分组成:
Savepoint 的元数据文件以(绝对路径)的形式包含(主要)指向作为 Savepoint 一部分的稳定存储上的所有文件的指针。
注意: 为了允许程序和 Flink 版本之间的升级,请务必查看以下有关 分配算子 ID 的部分 。
从概念上讲, Flink 的 Savepoint 与 Checkpoint 的不同之处类似于传统数据库中的备份与恢复日志之间的差异。
Checkpoint 的主要目的是为意外失败的作业提供恢复机制。 Checkpoint 的生命周期由 Flink 管理,即 Flink 创建,管理和删除 Checkpoint - 无需用户交互。 作为一种恢复和定期触发的方法,Checkpoint 实现有两个设计目标:i)轻量级创建和 ii)尽可能快地恢复。 可能会利用某些特定的属性来达到这个,例如, 工作代码在执行尝试之间不会改变。 在用户终止作业后,通常会删除 Checkpoint(除非明确配置为保留的 Checkpoint)。
与此相反,Savepoint 由用户创建,拥有和删除。 他们的用例是计划的,手动备份和恢复。 例如,升级 Flink 版本,调整用户逻辑,改变并行度,以及进行红蓝部署等。 当然,Savepoint 必须在作业停止后继续存在。 从概念上讲,Savepoint 的生成,恢复成本可能更高一些,Savepoint 更多地关注可移植性和对前面提到的作业更改的支持。
除去这些概念上的差异,Checkpoint 和 Savepoint 的当前实现基本上使用相同的代码并生成相同的格式。然而,目前有一个例外,我们可能会在未来引入更多的差异。例外情况是使用 RocksDB 状态后端的增量 Checkpoint。他们使用了一些 RocksDB 内部格式,而不是 Flink 的本机 Savepoint 格式。这使他们成为了与 Savepoint 相比,更轻量级的 Checkpoint 机制的第一个实例。
强烈建议你按照本节所述调整你的程序,以便将来能够升级你的程序。主要通过 uid(String) 方法手动指定算子 ID 。这些 ID 将用于恢复每个算子的状态。
DataStream<String> stream = env.
// Stateful source (e.g. Kafka) with ID
.addSource(new StatefulSource())
.uid("source-id") // ID for the source operator
.shuffle()
// Stateful mapper with ID
.map(new StatefulMapper())
.uid("mapper-id") // ID for the mapper
// Stateless printing sink
.print(); // Auto-generated ID
如果不手动指定 ID ,则会自动生成 ID 。只要这些 ID 不变,就可以从 Savepoint 自动恢复。生成的 ID 取决于程序的结构,并且对程序更改很敏感。因此,强烈建议手动分配这些 ID 。
Savepoint 状态
你可以将 Savepoint 想象为每个有状态的算子保存一个映射 “算子 ID ->状态”:
Operator ID | State
------------+------------------------
source-id | State of StatefulSource
mapper-id | State of StatefulMapper
在上面的示例中,print sink 是无状态的,因此不是 Savepoint 状态的一部分。默认情况下,我们尝试将 Savepoint 的每个条目映射回新程序。
触发 Savepoint
当触发 Savepoint 时,将创建一个新的 Savepoint 目录,其中存储数据和元数据。可以通过 配置默认目标目录 或 使用触发器命令 指定自定义目标目录参数 来控制该目录的位置。
注意: 目标目录必须是 JobManager(s) 和 TaskManager(s) 都可以访问的位置,例如分布式文件系统上的位置。
以 FsStateBackend 或 RocksDBStateBackend 为例:
# Savepoint 目标目录
/savepoint/
# Savepoint 目录
/savepoint/savepoint-:shortjobid-:savepointid/
# Savepoint 文件包含 Checkpoint元数据
/savepoint/savepoint-:shortjobid-:savepointid/_metadata
# Savepoint 状态
/savepoint/savepoint-:shortjobid-:savepointid/...
注意: 虽然看起来好像可以移动 Savepoint ,但由于 _metadata 中保存的是绝对路径,因此暂时不支持。 请按照 FLINK-5778 了解取消此限制的进度。
如果使用 MemoryStateBackend,则元数据和 Savepoint 状态将存储在 _metadata
文件中。 由于它是自包含的,你可以移动文件并从任何位置恢复。
注意: 不建议移动或删除正在运行作业的最后一个 Savepoint ,因为这可能会干扰故障恢复。
因此,Savepoint 对精确一次的接收器有副作用,为了确保精确一次的语义,如果在最后一个 Savepoint 之后没有 Checkpoint ,那么将使用 Savepoint 进行恢复。
触发 Savepoint
$ bin/flink savepoint :jobId [:targetDirectory]
使用 YARN 触发 Savepoint
$ bin/flink savepoint :jobId [:targetDirectory] -yid :yarnAppId
使用 Savepoint 取消作业
$ bin/flink cancel -s [:targetDirectory] :jobId
从 Savepoint 恢复
这将提交作业并指定要从中恢复的 Savepoint 。 你可以给出 Savepoint 目录或 _metadata 文件的路径。
$ bin/flink run -s :savepointPath :runArgs
跳过无法映射的状态恢复
# 默认情况下,resume 操作将尝试将 Savepoint 的所有状态映射回你要还原的程序。
# 如果删除了程序的部分算子,则可以通过 --allowNonRestoredState(short:-n)选项跳过无法映射到新程序的状态:
$ bin/flink run -s :savepointPath -n :runArgs
处理 Savepoint
# 处理存储在 :savepointPath 中的 Savepoint
$ bin/flink savepoint -d :savepointPath
请注意,还可以通过常规文件系统操作手动删除 Savepoint ,而不会影响其他 Savepoint 或 Checkpoint(请记住,每个 Savepoint 都是自包含的)。 在 Flink 1.2 之前,使用上面的 Savepoint 命令执行是一个更乏味的任务。
配置
你可以通过修改 flink-conf.yaml 的 state.savepoint.dir
,配置 savepoint 的默认目录。 触发 savepoint 时,将使用此目录来存储 savepoint。 你可以通过使用触发器命令指定自定义目标目录来覆盖缺省值
# 默认 Savepoint 目标目录
state.savepoints.dir: hdfs:///flink/savepoints/default
如果既未配置缺省值也未指定自定义目标目录,则触发 Savepoint 将失败。
注意:目标目录必须是 JobManager(s) 和 TaskManager(s) 可访问的位置,例如,分布式文件系统上的位置。
我应该为我作业中的所有算子分配 ID 吗?
根据经验,是的。 严格来说,仅通过 uid 方法给有状态算子分配 ID 就足够了。Savepoint 仅包含这些有状态算子的状态,无状态算子不是 Savepoint 的一部分。
在实践中,建议给所有算子分配 ID,因为 Flink 的一些内置算子(如 Window 算子)也是有状态的,而内置算子是否有状态并不很明显。 如果你完全确定算子是无状态的,则可以跳过 uid 方法。
如果我在作业中添加一个需要状态的新算子,会发生什么?
当你向作业添加新算子时,它将在没有任何状态的情况下进行初始化。 Savepoint 包含每个有状态算子的状态。 无状态算子根本不是 Savepoint 的一部分。 新算子的行为类似于无状态算子。
如果从作业中删除有状态的算子会发生什么?
默认情况下,从 Savepoint 恢复时将尝试将所有状态分配给新作业。如果有状态算子被删除,则无法从 Savepoint 恢复。
你可以通过使用 run 命令设置 --allowNonRestoredState (简称:-n ) 来允许删除有状态算子:
$ bin/flink run -s :savepointPath -n :runArgs
如果我在作业中重新排序有状态算子,会发生什么?
如果给这些算子分配了 ID,它们将像往常一样恢复。
如果没有分配 ID ,则有状态操作符自动生成的 ID 很可能在重新排序后发生更改。这将导致你无法从以前的 Savepoint 恢复。
如果我添加、删除或重新排序作业中没有状态的算子,会发生什么?
如果将 ID 分配给有状态操作符,则无状态操作符不会影响 Savepoint 恢复。
如果没有分配 ID ,则有状态操作符自动生成的 ID 很可能在重新排序后发生更改。这将导致你无法从以前的Savepoint 恢复。
当我在恢复时改变程序的并行度时会发生什么?
如果 Savepoint 是用 Flink >= 1.2.0 触发的,并且没有使用像 Checkpointed 这样的不推荐的状态API,那么你可以简单地从 Savepoint 恢复程序并指定新的并行度。
如果你正在从 Flink < 1.2.0 触发的 Savepoint 恢复,或者使用现在已经废弃的 api,那么你首先必须将作业和 Savepoint 迁移到 Flink >= 1.2.0,然后才能更改并行度。参见升级作业和Flink版本指南。
我可以将 savepoint 文件移动到稳定存储上吗?
这个问题的快速答案目前是“否”,因为元数据文件由于技术原因将稳定存储上的文件作为绝对路径引用。 更长的答案是:如果你因某种原因必须移动文件,那么有两个潜在的方法作为解决方法。 首先,更简单但可能更危险,你可以使用编辑器在元数据文件中查找旧路径并将其替换为新路径。 其次,你可以使用这个类 SavepointV2Serializer 作为以新路径以编程方式读取,操作和重写元数据文件的起点。
Checkpoints 主要是 Flink 自行管理,在默认的情况下仅用于恢复失败的作业,并不保留,当程序取消时就会被删除。
可以在代码中设置不删除,这样就可以在程序取消后使用指令从取消点继续运行。
# 代码部分设置程序退出不删除状态文件
val environment: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
val config: CheckpointConfig = environment.getCheckpointConfig
config.enableExternalizedCheckpoints(ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION)
environment.setStateBackend(new FsStateBackend("hdfs:///flink/checkpoints/ns_test", false))
# flink shell 指定任务的 metadata 路径,继续运行任务。
# 注:此处会生成一个新的 checkpoint Path,旧路径仍存在,需要手动删除
flink run -s :checkpointMetaDataPath :runArgs
Savepoint 由用户创建,拥有和删除。他们的用例是计划的,手动备份和恢复。例如,备份状态数据,升级 Flink 版本,调整用户逻辑,改变并行度,以及进行红蓝部署等。
# 触发 Savepoint
flink savepoint :jobId [:targetDirectory]
# 使用 YARN 触发 Savepoint
flink savepoint :jobId [:targetDirectory] -yid :yarnAppId
# 使用 Savepoint 取消作业
flink cancel -s [:targetDirectory] :jobId
# 从 Savepoint 恢复
flink run -s :savepointPath :runArgs
# 跳过无法映射的状态恢复
flink run -s :savepointPath -n :runArgs
用 Data Stream API 编写的程序通常以各种形式保存状态:
另请参阅 Streaming API 指南中的 状态部分 。
在启动 CheckPoint 机制时,状态会随着 CheckPoint 而持久化,以防止数据丢失、保障恢复时的一致性。 状态内部的存储格式、状态在 CheckPoint 时 如何持久化 以及 持久化在哪里 均取决于选择的 State Backend。
Flink 内置了以下这些开箱即用的 state backends :
在 MemoryStateBackend 内部,数据以 Java 对象的形式存储在堆中。 Key/value 形式的状态和窗口算子持有存储着状态值、触发器的 hash table。
在 CheckPoint 时,State Backend 对状态进行快照,并将快照信息作为 CheckPoint 应答消息的一部分发送给 JobManager(master),同时 JobManager 也将快照信息存储在堆内存中。
MemoryStateBackend 能配置异步快照。强烈建议使用异步快照来防止数据流阻塞,注意,异步快照默认是开启的。 用户可以在实例化 MemoryStateBackend 的时候,将相应布尔类型的构造参数设置为 false 来关闭异步快照(仅在 debug 的时候使用),例如:
new MemoryStateBackend(MAX_MEM_STATE_SIZE, false);
MemoryStateBackend 的限制:
akka.framesize
大小(看 配置参数)。MemoryStateBackend 适用场景:
建议同时将 managed memory 设为 0,以保证将最大限度的内存分配给 JVM 上的用户代码。
taskmanager.memory.managed.size: 0b
taskmanager.memory.managed.fraction: 0
FsStateBackend 需要配置一个文件系统的 URL(类型、地址、路径),例如:hdfs://namenode:40010/flink/checkpoints
或 file:///data/flink/checkpoints
。
FsStateBackend 将正在运行中的状态数据保存在 TaskManager 的内存中。CheckPoint 时,将状态快照写入到配置的文件系统目录中。 少量的元数据信息存储到 JobManager 的内存中(高可用模式下,将其写入到 CheckPoint 的元数据文件中)。
FsStateBackend 默认使用异步快照来防止 CheckPoint 写状态时对数据处理造成阻塞。 用户可以在实例化 FsStateBackend 的时候,将相应布尔类型的构造参数设置为 false 来关闭异步快照,例如:
# 关闭异步快照,默认开启
new FsStateBackend(path, false);
FsStateBackend 适用场景:
建议同时将 managed memory 设为0,以保证将最大限度的内存分配给 JVM 上的用户代码。
RocksDBStateBackend 需要配置一个文件系统的 URL (类型、地址、路径),例如:hdfs://namenode:40010/flink/checkpoints
或 file:///data/flink/checkpoints
。
RocksDBStateBackend 将正在运行中的状态数据保存在 RocksDB 数据库中,RocksDB 数据库默认将数据存储在 TaskManager 的数据目录。 CheckPoint 时,整个 RocksDB 数据库被 checkpoint 到配置的文件系统目录中。 少量的元数据信息存储到 JobManager 的内存中(高可用模式下,将其存储到 CheckPoint 的元数据文件中)。
RocksDBStateBackend 只支持异步快照。
RocksDBStateBackend 的限制:
RocksDBStateBackend 的适用场景:
注意,你可以保留的状态大小仅受磁盘空间的限制。与状态存储在内存中的 FsStateBackend 相比,RocksDBStateBackend 允许存储非常大的状态。 然而,这也意味着使用 RocksDBStateBackend 将会使应用程序的最大吞吐量降低。 所有的读写都必须序列化、反序列化操作,这个比基于堆内存的 state backend 的效率要低很多。
请同时参考 Task Executor 内存配置 中关于 RocksDBStateBackend 的建议。
RocksDBStateBackend 是目前唯一支持增量 CheckPoint 的 State Backend (见 3.4 大状态与 Checkpoint 调优)。
可以使用一些 RocksDB 的本地指标(metrics),但默认是关闭的。你能在 配置参数 找到关于 RocksDB 本地指标的文档。
The total memory amount of RocksDB instance(s) per slot can also be bounded, please refer to documentation here for details.
如果没有明确指定,将使用 jobmanager 做为默认的 state backend。你能在 flink-conf.yaml
中为所有 Job 设置其他默认的 State Backend。 每一个 Job 的 state backend 配置会覆盖默认的 state backend 配置,如下所示:
设置每个 Job 的 State Backend
StreamExecutionEnvironment 可以对每个 Job 的 State Backend 进行设置,如下所示:
// Java
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStateBackend(new FsStateBackend("hdfs://namenode:40010/flink/checkpoints"));
// Scala
val env = StreamExecutionEnvironment.getExecutionEnvironment()
env.setStateBackend(new FsStateBackend("hdfs://namenode:40010/flink/checkpoints"))
如果你想在 IDE 中使用 RocksDBStateBackend,或者需要在作业中通过编程方式动态配置 RocksDBStateBackend,必须添加以下依赖到 Flink 项目中。
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-statebackend-rocksdb_2.11artifactId>
<version>1.11.0version>
<scope>providedscope>
dependency>
注意: 由于 RocksDB 是 Flink 默认分发包的一部分,所以如果你没在代码中使用 RocksDB,则不需要添加此依赖。而且可以在 flink-conf.yaml
文件中通过 state.backend
配置 State Backend,以及更多的 checkpointing 和 RocksDB State Backend 参数。
设置默认的(全局的) State Backend
在 flink-conf.yaml
可以通过键 state.backend
设置默认的 State Backend。
可选值包括 jobmanager (MemoryStateBackend)、filesystem (FsStateBackend)、rocksdb (RocksDBStateBackend), 或使用实现了 state backend 工厂 StateBackendFactory 的类的全限定类名, 例如: RocksDBStateBackend 对应为 org.apache.flink.contrib.streaming.state.RocksDBStateBackendFactory
。
state.checkpoints.dir
选项指定了所有 State Backend 写 CheckPoint 数据和写元数据文件的目录。 你能在 3.1.2 保留 checkpoint 找到关于 CheckPoint 目录结构的详细信息。
配置文件的部分示例如下所示:
# 用于存储 operator state 快照的 State Backend
state.backend: filesystem
# 存储快照的目录
state.checkpoints.dir: hdfs://namenode:40010/flink/checkpoints
该小节描述 RocksDBStateBackend 的更多细节
RocksDBStateBackend 支持增量快照。不同于产生一个包含所有数据的全量备份,增量快照中只包含自上一次快照完成之后被修改的记录,因此可以显著减少快照完成的耗时。
一个增量快照是基于 (通常多个)前序快照 构建的。由于 RocksDB 内部存在 compaction 机制对 sst 文件进行合并,Flink 的增量快照也会定期重新设立起点(rebase),因此增量链条不会一直增长,旧快照包含的文件也会逐渐过期并被自动清理。
和基于全量快照的恢复时间相比,如果网络带宽是瓶颈,那么基于增量快照恢复可能会消耗更多时间,因为增量快照包含的 sst 文件之间可能存在数据重叠导致需要下载的数据量变大;而当 CPU 或者 IO 是瓶颈的时候,基于增量快照恢复会更快,因为从增量快照恢复不需要解析 Flink 的统一快照格式来重建本地的 RocksDB 数据表,而是可以直接基于 sst 文件加载。
虽然状态数据量很大时我们推荐使用增量快照,但这并不是默认的快照机制,可以通过下述配置手动开启该功能:
flink-conf.yaml
中设置:state.backend.incremental: true
RocksDBStateBackend backend = new RocksDBStateBackend(filebackend, true);
需要注意的是,一旦启用了增量快照,网页上展示的 Checkpointed Data Size 只代表增量上传的数据量,而不是一次快照的完整数据量。
Flink 致力于控制整个进程的内存消耗,以确保 Flink 任务管理器(TaskManager)有良好的内存使用,从而既不会在容器(Docker/Kubernetes, Yarn等)环境中由于内存超用被杀掉,也不会因为内存利用率过低导致不必要的数据落盘或是缓存命中率下降,致使性能下降。
为了达到上述目标,Flink 默认将 RocksDB 的可用内存配置为任务管理器的单槽(per-slot)托管内存量。这将为大多数应用程序提供良好的开箱即用体验,即大多数应用程序不需要调整 RocksDB 配置,简单的增加 Flink 的托管内存即可改善内存相关性能问题。
当然,您也可以选择不使用 Flink 自带的内存管理,而是手动为 RocksDB 的每个列族(ColumnFamily)分配内存(每个算子的每个 state 都对应一个列族)。这为专业用户提供了对 RocksDB 进行更细粒度控制的途径,但同时也意味着用户需要自行保证总内存消耗不会超过(尤其是容器)环境的限制。请参阅 3.4.4.3 Tuning RocksDB Memory 了解有关大状态数据性能调优的一些指导原则。
RocksDB 使用托管内存
这个功能默认打开,并且可以通过 state.backend.rocksdb.memory.managed
配置项控制。
Flink 并不直接控制 RocksDB 的 native 内存分配,而是通过配置 RocksDB 来确保其使用的内存正好与 Flink 的托管内存预算相同。这是在任务槽(per-slot)级别上完成的(托管内存以任务槽为粒度计算)。
为了设置 RocksDB 实例的总内存使用量,Flink 对同一个任务槽上的所有 RocksDB 实例使用共享的 cache 以及 write buffer manager。 共享 cache 将对 RocksDB 中内存消耗的三个主要来源(块缓存、索引 和 bloom 过滤器、MemTables)设置上限。
Flink 还提供了两个参数来控制 写路径(MemTable) 和 读路径(索引及过滤器,读缓存) 之间的内存分配。当您看到 RocksDB 由于缺少写缓冲内存(频繁刷新)或读缓存未命中而性能不佳时,可以使用这些参数调整读写间的内存分配。
state.backend.rocksdb.memory.write-buffer-ratio
,默认值 0.5,即 50% 的给定内存会分配给写缓冲区使用。state.backend.rocksdb.memory.high-prio-pool-ratio
,默认值 0.1,即 10% 的 block cache 内存会优先分配给索引及过滤器。 我们强烈建议不要将此值设置为零,以防止索引和过滤器被频繁踢出缓存而导致性能问题。此外,我们默认将 L0 级的过滤器和索引将被固定到缓存中以提高性能,更多详细信息请参阅 RocksDB 文档。注 意 \color{blue}注意 注意 上述机制开启时将覆盖用户在 PredefinedOptions 和 RocksDBOptionsFactory 中对 block cache 和 write buffer 进行的配置。
注 意 \color{blue}注意 注意 仅面向专业用户:若要手动控制内存,可以将 state.backend.rocksdb.memory.managed 设置为 false,并通过 ColumnFamilyOptions 配置 RocksDB。 或者可以复用上述 cache/write-buffer-manager 机制,但将内存大小设置为与 Flink 的托管内存大小无关的固定大小(通过 state.backend.rocksdb.memory.fixed-per-slot 选项)。 注意在这两种情况下,用户都需要确保在 JVM 之外有足够的内存可供 RocksDB 使用。
计时器(Timer)用于安排稍后的操作(基于事件时间或处理时间),例如触发窗口或回调 ProcessFunction。
当选择 RocksDBStateBackend 时,默认情况下计时器也存储在 RocksDB 中。这是一种健壮且可扩展的方式,允许应用程序使用很多个计时器。另一方面,在 RocksDB 中维护计时器会有一定的成本,因此 Flink 也提供了将计时器存储在 JVM 堆上而使用 RocksDB 存储其他状态的选项。当计时器数量较少时,基于堆的计时器可以有更好的性能。
您可以通过将 state.backend.rocksdb.timer-service.factory
配置项设置为 heap(而不是默认的 rocksdb)来将计时器存储在堆上。
注 意 \color{blue}注意 注意 在 RocksDBStateBackend 中使用基于堆的计时器的组合当前不支持计时器状态的异步快照。其他状态(如 keyed state)可以被异步快照。
您可以选择使用 Flink 的监控指标系统来汇报 RocksDB 的原生指标,并且可以选择性的指定特定指标进行汇报。 请参阅 configuration docs 了解更多详情。
注 意 \color{blue}注意 注意 启用 RocksDB 的原生监控指标可能会对应用程序的性能产生负面影响。
注 意 \color{blue}注意 注意 在引入 RocksDB 使用托管内存 功能后,此机制应限于在 专家调优(expert tuning) 或 故障处理(trouble shooting) 中使用。
使用预定义选项,用户可以在每个 RocksDB 列族上应用一些预定义的配置,例如配置内存使用、线程、Compaction 设置等。目前每个算子的每个状态都在 RocksDB 中有专门的一个列族存储。
有两种方法可以选择要应用的预定义选项:
state.backend.rocksdb.predefined-options
配置项将选项名称设置进 flink-conf.yaml 。RocksDBStateBackend.setPredefinedOptions(PredefinedOptions.SPINNING_DISK_OPTIMIZED_HIGH_MEM) 。
该选项的默认值是 DEFAULT ,对应 PredefinedOptions.DEFAULT
。
注 意 \color{blue}注意 注意 在引入 RocksDB 使用托管内存 功能后,此机制应限于在专家调优或故障处理中使用。
您也可以通过配置一个 RocksDBOptionsFactory 来手动控制 RocksDB 的选项。此机制使您可以对列族的设置进行细粒度控制,例如内存使用、线程、Compaction 设置等。目前每个算子的每个状态都在 RocksDB 中有专门的一个列族存储。
有两种方法可以将 RocksDBOptionsFactory 传递给 RocksDBStateBackend:
state.backend.rocksdb.options-factory
选项将工厂实现类的名称设置到 flink-conf.yaml
。注 意 \color{blue}注意 注意 通过程序设置的 RocksDBOptionsFactory 将覆盖 flink-conf.yaml 配置文件的设置,且 RocksDBOptionsFactory 设置的优先级高于预定义选项(PredefinedOptions)。
注 意 \color{blue}注意 注意 RocksDB 是一个本地库,它直接从进程分配内存, 而不是从 JVM 分配内存。分配给 RocksDB 的任何内存都必须被考虑在内,通常需要将这部分内存从任务管理器(TaskManager)的 JVM 堆中减去。 不这样做可能会导致 JVM 进程由于分配的内存超过申请值而被 YARN/Mesos 等资源管理框架终止。
从 flink-conf.yaml 中读取列族选项
一个实现了 ConfigurableRocksDBOptionsFactory
接口的 RocksDBOptionsFactory
可以直接从配置文件(flink-conf.yaml)中读取设定。
state.backend.rocksdb.options-factory
的默认配置是 org.apache.flink.contrib.streaming.state.DefaultConfigurableOptionsFactory
,它默认会将 这里定义 的所有配置项全部加载。 因此您可以简单的通过关闭 RocksDB 使用托管内存的功能并将需要的设置选项加入配置文件来配置底层的列族选项。
下面是自定义 ConfigurableRocksDBOptionsFactory 的一个示例 (开发完成后,请将您的实现类全名设置到 state.backend.rocksdb.options-factory).
public class MyOptionsFactory implements ConfigurableRocksDBOptionsFactory {
private static final long DEFAULT_SIZE = 256 * 1024 * 1024; // 256 MB
private long blockCacheSize = DEFAULT_SIZE;
@Override
public DBOptions createDBOptions(DBOptions currentOptions, Collection handlesToClose) {
return currentOptions.setIncreaseParallelism(4)
.setUseFsync(false);
}
@Override
public ColumnFamilyOptions createColumnOptions(
ColumnFamilyOptions currentOptions, Collection handlesToClose) {
return currentOptions.setTableFormatConfig(
new BlockBasedTableConfig()
.setBlockCacheSize(blockCacheSize)
.setBlockSize(128 * 1024)); // 128 KB
}
@Override
public RocksDBOptionsFactory configure(Configuration configuration) {
this.blockCacheSize =
configuration.getLong("my.custom.rocksdb.block.cache.size", DEFAULT_SIZE);
return this;
}
}
此处提供了有关如何配置和调整使用大状态的应用程序的指南。
为了使 Flink 应用程序能够大规模可靠地运行,必须满足两个条件:
第一部分讨论了如何获得性能良好的检查点。最后一部分介绍了有关计划使用多少资源的一些最佳做法。
监视检查点行为的最简单方法是通过UI的检查点部分。检查点监视 的文档显示了如何访问可用的检查点指标。
扩大检查点时特别感兴趣的两个数字是:
算子启动检查点的时间:此时间目前尚未直接公开,但对应于:
checkpoint_start_delay = end_to_end_duration - synchronous_duration - asynchronous_duration
当触发检查点的时间一直非常高时,这意味着检查点障碍需要很长时间才能从源头移动到算子。这通常表明系统在恒定的背压下运行。
在对齐期间缓冲的数据量。对于一次性语义,Flink 在接收多个输入流的 算子处对齐流,为该对齐缓冲一些数据。理想情况下缓冲的数据量较低。较高的数量意味着在在不同的时间从不同的输入流接收检查点障碍。
请注意,在存在瞬时背压,数据偏斜或网络问题的情况下,此处指示的数字有时可能很高。但是,如果数字一直很高,则意味着 Flink 将许多资源投入检查点。
检查点会定期触发,应用程序可以对其进行配置。如果检查点完成所需的时间长于检查点间隔,则在进行中的检查点完成之前不会触发下一个检查点。 默认情况下,正在进行的检查点完成后,下一个检查点将立即触发。
当检查点结束时经常花费比基本间隔更长的时间(例如,因为状态变得比计划的大,或者存储检查点的存储暂时变慢),系统会不断获取检查点(一旦完成检查,则立即启动新的检查点)。这可能意味着在检查点上经常捆绑太多资源,而且算子的进展太少。此行为对使用异步检查点状态的流应用程序的影响较小,但可能仍会对整体应用程序性能产生影响。
为了避免这种情况,应用程序可以定义检查点之间的最小持续时间:
StreamExecutionEnvironment.getCheckpointConfig().setMinPauseBetweenCheckpoints(milliseconds)
此持续时间是在最新检查点结束和下一个检查点开始之间必须经过的最小时间间隔。下图说明了这对检查点的影响。
注 意 \color{blue}注意 注意:可以通过 CheckpointConfig 配置应用程序以允许多个检查点同时进行。对于 Flink 中具有大状态的应用程序,这通常会将太多资源绑定到检查点。当手动触发保存点时,它可能正在与正在进行的检查点同时进行。
RocksDB 状态后端是许多大型 Flink 流应用程序的状态存储主力。后端的扩展范围远远超出了主内存,并且可以可靠地存储较大的 键控状态。
RocksDB 的性能可能会因配置而异,本节概述了一些优化的最佳做法,这些最佳做法是针对使用 RocksDB 状态后端的作业进行调优的。
在减少检查点花费的时间时,激活增量检查点应该是首要考虑因素之一。与完全检查点相比,增量检查点可以大大减少检查点的时间,因为增量检查点仅记录与先前完成的检查点相比的更改,而不是生成状态后端的完整的独立备份。
有关更多背景信息,请参见 3.3.2.1 RocksDB 中的增量检查点。
默认情况下,计时器存储在RocksDB中,这是更可靠和可扩展的选择。
当仅具有少量计时器的性能优化作业(无窗口,不使用ProcessFunction中的计时器)时,将这些计时器放在堆上可以提高性能。请谨慎使用此功能,因为基于堆的计时器可能会增加检查点时间,并且自然无法扩展到内存之外。
有关如何配置基于堆的计时器的详细信息,请参见 3.3.6.3 计时器(内存 vs. RocksDB)。
RocksDB 状态后端的性能在很大程度上取决于其可用的内存量。为了提高性能,添加内存可以提供很多帮助,或者调整内存的功能。
默认情况下,RocksDB 状态后端将 Flink 的托管内存预算用于 RocksDB 的缓冲区和缓存(state.backend.rocksdb.memory.managed: true
)。
有关该机制如何工作的背景,请参考 RocksDB 内存管理。
要调整与内存相关的性能问题,以下步骤可能会有所帮助:
尝试提高性能的第一步应该是增加托管内存量。这通常可以大大改善这种情况,而无需增加调整底层RocksDB选项的复杂性。
特别是对于大型容器/进程,除非应用程序逻辑本身需要大量JVM堆,否则总的内存通常可以分配给RocksDB。默认托管内存分数(0.4)是保守的,在使用具有GB进程大小的TaskManager时通常可以增加。
RocksDB中的写缓冲区数取决于应用程序中的状态数(管道中所有算子的状态)。每个状态对应一个ColumnFamily,它需要自己的写缓冲区。因此,具有许多状态的应用程序通常需要更多内存才能实现相同的性能。
您可以通过设置来尝试比较具有托管内存的RocksDB与具有每个列系列内存的RocksDB的性能state.backend.rocksdb.memory.managed: false。尤其是要针对基线进行测试(假设容器内存限制为无限制)或与Flink的早期版本相比进行回归测试时,这可能会很有用。
与托管内存设置(恒定内存池)相比,不使用托管内存意味着RocksDB分配的内存与应用程序中状态的数量成正比(内存占用量随应用程序的更改而变化)。根据经验,非托管模式(除非应用了ColumnFamily选项)的上限大约为“ 140MB *跨所有任务的num-states * num-slots”。计时器也算为状态!
如果您的应用程序有许多状态,并且看到频繁的MemTable刷新(写侧瓶颈),但是您不能提供更多的内存,则可以增加写入写缓冲区的内存比例(state.backend.rocksdb.memory.write-buffer-ratio)。有关详细信息,请参见RocksDB内存管理。
一种高级选项(专家模式),它可以通过以下几种方法来减少具有许多状态的设置中MemTable刷新的次数:调整RocksDB的ColumnFamily选项(区域块大小,最大背景刷新线程等)RocksDBOptionsFactory:
public class MyOptionsFactory implements ConfigurableRocksDBOptionsFactory {
@Override
public DBOptions createDBOptions(DBOptions currentOptions, Collection handlesToClose) {
// increase the max background flush threads when we have many states in one operator,
// which means we would have many column families in one DB instance.
return currentOptions.setMaxBackgroundFlushes(4);
}
@Override
public ColumnFamilyOptions createColumnOptions(
ColumnFamilyOptions currentOptions, Collection handlesToClose) {
// decrease the arena block size from default 8MB to 1MB.
return currentOptions.setArenaBlockSize(1024 * 1024);
}
@Override
public OptionsFactory configure(Configuration configuration) {
return this;
}
}
本节讨论如何确定应使用多少资源才能使 Flink 作业可靠地运行。容量规划的基本经验法则是:
正常运行应具有足够的容量,以使其在恒定的背压下无法运行。有关如何检查应用程序是否在背压下运行的详细信息,请参见 背压监视
在无故障时间内无需背压即可运行程序所需的资源之上提供一些额外资源。需要这些资源来 “赶上” 在应用程序恢复期间累积的输入数据。这应该取决于恢复 算子操作通常需要多长时间(这取决于故障转移时需要加载到新 TaskManagers 中的状态的大小)以及该方案需要多快才能恢复。
重要说明:应该在激活检查点的情况下建立基线,因为检查点会占用一些资源(例如网络带宽)。
暂时的背压通常是可以的,并且在负载峰值,追赶阶段或外部系统(写入接收器中)表现出暂时的减速期间,是执行流控制的重要部分。
某些操作(如大窗口)会给下游算子带来不菲的负担:就 Windows 而言,在构建窗口时,下游算子可能无事可做,而在发射窗口时,这些操作将负有重担。下游并行性的计划需要考虑到窗口发射多少以及这种尖峰需要处理多快。
注 意 \color{blue}注意 注意:为了允许以后添加资源,请确保将数据流程序的最大并行度设置为合理的数量。最大并行度定义了在重新缩放程序时(通过保存点)可以将程序并行度设置为多高。
Flink 的内部副本记录以 max-parallelism-many key groups
的粒度跟踪并行状态。即使执行低并行度的程序,Flink 的设计也力求使其具有非常高的最大并行度值。
Flink 为所有检查点和保存点提供了可选的压缩功能(默认值:关闭)。当前,压缩始终使用灵活的 压缩算法(版本1.1.4),但我们计划在将来支持自定义压缩算法。压缩对处于 键控状态 的键组的粒度起作用,即,每个键组可以分别解压缩,这对于重新缩放很重要。
压缩可以通过以下方式激活 ExecutionConfig:
ExecutionConfig executionConfig = new ExecutionConfig();
executionConfig.setUseSnapshotCompression(true);
注 意 \color{blue}注意 注意 压缩选项对增量快照没有影响,因为它们使用的是 RocksDB 的内部格式,该格式始终使用开箱即用的快速压缩。
在 Flink 的检查点中,每个任务都会生成其状态的快照,然后将其写入分布式存储。每个任务通过发送描述分布式存储中状态位置的句柄来确认成功将状态写入 JobManager。反过来,JobManager 从所有任务中收集句柄并将它们捆绑到检查点对象中。
在恢复的情况下,JobManager 打开最新的检查点对象并将句柄发送回相应的任务,然后可以从分布式存储中恢复其状态。使用分布式存储来存储状态有两个重要的优点。首先,存储是容错的,其次,分布式存储中的所有状态都可以被所有节点访问,并且可以容易地重新分配(例如,用于重新缩放)。
但是,使用远程分布式存储也有一个很大的缺点:所有任务必须通过网络从远程位置读取其状态。在许多情况下,恢复可以将失败的任务重新安排到与上一次运行相同的 TaskManager(当然,机器故障等例外),但我们仍然必须读取远程状态。即使单台机器上只有很小的故障,这也可能导致大型状态的恢复时间过长。
任务本地状态恢复正是针对此恢复时间长的问题,其主要思想如下:对于每个检查点,每个任务不仅将任务状态写到分布式存储中,而且还将状态快照的辅助副本保存在磁盘中。任务本地的存储(例如在本地磁盘或内存中)。请注意,快照的主要存储区仍必须是分布式存储区,因为本地存储区不能确保在节点故障下的持久性,并且也不能为其他节点提供重新分发状态的访问权限,因此此功能仍需要主要副本。
但是,对于可以重新安排到先前位置进行恢复的每个任务,我们可以从辅助本地副本还原状态,从而避免了远程读取状态的开销。鉴于许多故障不是节点故障,并且节点故障通常一次仅影响一个或很少几个节点,因此很有可能大多数任务可以在恢复中返回其先前位置并发现其完整状态。这就是使本地恢复有效减少恢复时间的原因。
请注意,这取决于创建和存储辅助本地状态副本的每个检查点的一些额外费用,具体取决于所选的状态后端和检查点策略。例如,在大多数情况下,实现将简单地将对分布式存储的写入复制到本地文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sVHItY2p-1600137656692)(https://ci.apache.org/projects/flink/flink-docs-release-1.11/fig/local_recovery.png)]
任务本地状态始终被视为辅助副本,检查点状态的基础是分布式存储中的主要副本。这对检查点和恢复期间的本地状态问题具有影响:
对于检查点,主副本必须成功,并且生成辅助本地副本的失败不会使检查点失败。如果无法创建主副本,则检查点将失败,即使已成功创建辅助副本也是如此。
只有主副本由 JobManager 确认和管理,辅助副本由 TaskManager 拥有,其生命周期可以独立于其主副本。例如,可以将 3 个最新检查点的历史记录保存为主副本,并仅保存最新检查点的任务本地状态。
对于恢复,如果匹配的辅助副本可用,Flink 将始终首先尝试从任务本地状态恢复。如果从辅助副本恢复期间出现任何问题,Flink 将透明地重试从主副本恢复任务。如果主要和(可选)辅助副本失败,则恢复仅失败。在这种情况下,根据配置,Flink 仍然可以回退到较旧的检查点。
任务本地副本可能仅包含完整任务状态的一部分(例如,写入一个本地文件时发生异常)。在这种情况下,Flink 将首先尝试在本地恢复本地部分,从主副本还原非本地状态。主状态必须始终是完整的,并且是任务本地状态的超集。
任务本地状态可以具有与主状态不同的格式,不需要字节相同。例如,任务本地状态甚至可能是由堆对象组成的内存中状态,而不是存储在任何文件中。
如果 TaskManager 丢失,则其所有任务的本地状态将丢失。
默认情况下,任务本地恢复是禁用的,并且可以通过 Flink 的配置(使用 state.backend.local-recovery
中指定的 Keys)来激活 CheckpointingOptions.LOCAL_RECOVERY
。此设置的值可以为 true 以启用,也可以为 false(默认) 以禁用本地恢复。
局 限 性 \color{blue}局限性 局限性:当前,任务本地恢复仅涵盖 键控状态 后端。到目前为止,键控状态 通常是该状态的最大部分。在不久的将来,我们还将介绍算子的状态和计时器。
以下状态后端可以支持任务本地恢复:
FsStateBackend:键控状态 支持任务本地恢复。该实现会将状态复制到本地文件。这会导致额外的写入成本并占用本地磁盘空间。将来,我们可能还会提供将任务本地状态保存在内存中的实现。
RocksDBStateBackend:键控状态 支持任务本地恢复。对于完整的检查点,状态被复制到本地文件。这会导致额外的写入成本并占用本地磁盘空间。对于增量快照,本地状态基于 RocksDB 的本机检查点机制。此机制还用作创建主副本的第一步,这意味着在这种情况下,创建第二副本不会引入额外的成本。我们只是保留本地检查点目录,而不是在上载到分布式存储后将其删除。此本地副本可以与 RocksDB 的工作目录共享活动文件(通过硬链接),因此对于活动文件,使用增量快照进行任务本地恢复也不会占用额外的磁盘空间。使用硬链接还意味着 RocksDB 目录必须与所有可用于存储本地状态的配置本地恢复目录位于同一物理设备上,否则建立硬链接可能会失败(请参阅 FLINK-10954)。目前,
任务本地恢复假定发生故障时保留分配的任务调度,其工作方式如下。
每个任务都会记住其先前的分配,并请求完全相同的插槽以重新启动以进行恢复。如果此插槽不可用,则任务将向资源管理器请求一个新的新插槽。
这样,如果 TaskManager 不再可用,那么无法返回到其先前位置的任务将不会将其他正在恢复的任务从先前的插槽中移出。我们的理由是,当 TaskManager 不再可用时,前一个插槽只能消失,在这种情况下是一些任务必须要求新的插槽。通过我们的调度策略,我们可以为最大数量的任务提供从本地状态恢复的机会,并避免任务窃取其先前插槽之间的级联效应。
由于配置参数一章中含有较多内存配置相关的参数,故此处将内存配置这一章节放在前面,方便下一节众多内存参数的理解。
Set up Flink’s Process Memory
Apache Flink 基于 JVM 的高效处理能力,依赖于其对各组件内存用量的细致掌控。 考虑到用户在 Flink 上运行的应用的多样性,尽管社区已经努力为所有配置项提供合理的默认值,仍无法满足所有情况下的需求。 为了给用户生产提供最大化的价值, Flink 允许用户在 整体上 以及 细粒度上 对集群的内存分配进行调整。
本文接下来介绍的内存配置方法适用于 1.10 及以上版本的 TaskManager 进程和 1.11 及以上版本的 JobManager 进程。 Flink 在 1.10 和 1.11 版本中对内存配置部分进行了较大幅度的改动,从早期版本升级的用户请参考 升级指南。
Flink JVM 进程(Flink JVM process) 的 进程总内存(Total Process Memory) 包含了由 Flink application 使用的内存(Flink 总内存) 以及由 运行 Flink 的 JVM 使用的内存。
其中,Flink 总内存(Total Flink Memory) 包括 JVM 堆内存(JVM Heap Memory) 和 堆外内存(Off-Heap Memory) 。 其中 堆外内存 包括 直接内存(Direct Memory) 和 本地内存(Native Memory) 。
Flink JVM process
- Total Process Memory
- Total Flink Memory
- JVM Heap Memory
- Off-heap Memory
- Direct Memory
- Native Memory
- JVM specific memory(JVM to run the Flink process)
- JVM Metaspace
- JVM Overhead
配置 Flink 进程内存最简单的方法是指定以下两个配置项中的任意一个:
配置项 | TaskManager 配置参数 | JobManager 配置参数 |
---|---|---|
Flink 总内存 - Total Flink memory | taskmanager.memory.flink.size | jobmanager.memory.flink.size |
进程总内存 - Total process memory | taskmanager.memory.process.size | jobmanager.memory.process.size |
提 示 \color{blue}提示 提示 关于本地执行,请分别参考 TaskManager 和 JobManager 的相关文档。
Flink 会根据默认值或其他配置参数自动调整剩余内存部分的大小。 关于各内存部分的更多细节,请分别参考 TaskManager 和 JobManager 的相关文档。
对于 独立部署模式(Standalone Deployment),如果你希望指定由 Flink 应用本身使用的内存大小,最好选择配置 Flink 总内存(Total Flink memory) 。 Flink 总内存会进一步划分为 JVM 堆内存和堆外内存。 更多详情请参考 4.4.1 独立部署模式(Standalone Deployment)下的内存配置
通过配置 进程总内存(Total process memory) 可以指定由 Flink JVM 进程 使用的总内存大小。 对于容器化部署模式(Containerized Deployment),这相当于申请的容器(Container)大小,详情请参考 4.4.2 容器(Container)的内存配置(Kubernetes、Yarn 或 Mesos)。
此外,还可以通过设置 Flink 总内存的特定内部组成部分的方式来进行内存配置。 不同进程需要设置的内存组成部分是不一样的。 详情请分别参考 TaskManager - 配置堆内存和托管内存 和 JobManager - 配置 JVM 堆内存 的相关文档。
提 示 \color{blue}提示 提示 以上三种方式中,用户需要至少选择其中一种进行配置(本地运行除外),否则 Flink 将无法启动。 这意味着,用户需要从以下无默认值的配置参数(或参数组合)中选择一个给出明确的配置:
Option | for TaskManager | for JobManager |
---|---|---|
Option 1 | taskmanager.memory.flink.size | jobmanager.memory.flink.size |
Option 2 | taskmanager.memory.process.size | jobmanager.memory.process.size |
Option 3 | taskmanager.memory.task.heap.size taskmanager.memory.managed.size | jobmanager.memory.heap.size |
提 示 \color{blue}提示 提示 不建议同时设置 进程总内存(Total process memory) 和 Flink 总内存(Total Flink memory) , 这可能会造成内存配置冲突,从而导致部署失败。 额外配置其他内存部分时,同样需要注意可能产生的配置冲突。
Flink 进程启动时,会根据配置的和自动推导出的各内存部分大小,显式地设置以下 JVM 参数:
JVM Arguments | Value for TaskManager | Value for JobManager |
---|---|---|
-Xmx 和 -Xms | Framework + Task Heap Memory (框架和任务的堆内存) | JVM Heap Memory |
-XX:MaxDirectMemorySize (TaskManager 始终设置,JobManager 见注释) | Framework + Task Off-heap (*) + Network Memory | Off-heap Memory (*),(**) |
-XX:MaxMetaspaceSize | JVM Metaspace | JVM Metaspace |
(*) 请注意,堆外内存 也包括了用户代码使用的本地内存(非直接内存)。
(**) 只有在 jobmanager.memory.enable-jvm-direct-memory-limit
设置为 true 时,JobManager 才会设置 JVM 直接内存
限制。
相关内存部分的配置方法,请同时参考 TaskManager - 内存模型详解 和 JobManager - 详细配置 的详细内存模型。
本节介绍下列内存部分的配置方法,它们都可以通过指定在总内存中所占比例的方式进行配置,同时受限于相应的的最大/最小值范围。
相关内存部分的配置方法,请同时参考 TaskManager - 内存模型详解 和 JobManager - 详细配置 的详细内存模型。
设置 JVM Overhead 和 Network memory 的内存,可以使用 min-max 范围,以及 占比(fraction) 三个参数限定。若根据此比例算出的内存量比最小值小或比最大值大,就会限制到最小值或者最大值。具体可以分为以下四种情况:
total Process memory = 1000Mb,
JVM Overhead min = 64Mb,
JVM Overhead max = 128Mb,
JVM Overhead fraction = 0.1
那么 JVM 开销的实际大小将会是 1000Mb x 0.1 = 100Mb,在 64-128Mb 的范围内。total Process memory = 1000Mb,
JVM Overhead min = 128Mb,
JVM Overhead max = 256Mb,
JVM Overhead fraction = 0.1
那么 JVM 开销的实际大小将会是 128Mb,因为根据总内存和占比计算得到的内存大小 100Mb 小于最小值。total Process memory = 1000Mb,
task heap = 100Mb, (或 JobManager 的 JVM 堆内存)
JVM Overhead min = 64Mb,
JVM Overhead max = 256Mb,
JVM Overhead fraction = 0.1
进程总内存中所有其他内存部分均有默认大小,包括 TaskManager 的托管内存默认占比或 JobManager 的默认堆外内存。 因此,JVM 开销的实际大小不是根据占比算出的大小(1000Mb x 0.1 = 100Mb),而是进程总内存中剩余的部分。 这个剩余部分的大小必须在 64-256Mb 的范围内,否则将会启动失败。Flink 的 TaskManager 负责执行用户代码。 根据实际需求为 TaskManager 配置内存将有助于减少 Flink 的资源占用,增强作业运行的稳定性。
本文接下来介绍的内存配置方法适用于 1.10 及以上版本。 Flink 在 1.10 版本中对内存配置部分进行了较大幅度的改动,从早期版本升级的用户请参考 升级指南。
提 示 \color{blue}提示 提示 本篇内存配置文档仅针对 TaskManager。与 JobManager 相比,TaskManager 具有相似但更加复杂的内存模型。
Flink JVM 进程(Flink JVM process) 的 进程总内存(Total Process Memory) 包含了由 Flink application 使用的内存(Flink 总内存) 以及由 运行 Flink 的 JVM 使用的内存。
其中,Flink 总内存(Total Flink Memory) 包括 JVM 堆内存(JVM Heap Memory) 、托管内存(Managed Memory) 以及 直接内存(Direct Memory) 或 本地内存(Native Memory) 。
Flink JVM process for TaskManager
- Total Process Memory
- Total Flink Memory
- JVM Heap Memory
- Off-heap Memory
- Managed Memory
- Direct Memory/Native Memory
- JVM specific memory(JVM to run the Flink process)
- JVM Metaspace
- JVM Overhead
如果你是在本地运行 Flink(例如在 IDE 中)而非创建一个集群,那么本文介绍的配置并非所有都是适用的,详情请参考 本节的本地执行。
其他情况下,配置 Flink 内存最简单的方法就是 4.1.1 配置总内存 。 此外,Flink 也支持 更细粒度的内存配置方式 。
Flink 会根据默认值或其他配置参数自动调整剩余内存部分的大小。 接下来的章节将介绍关于各内存部分的更多细节。
如 4.1.1 配置总内存 中所述,另一种配置 Flink 内存的方式是同时设置 任务堆内存 和 托管内存(managed memory) 。 通过这种方式,用户可以更好地掌控用于 Flink 任务的 JVM 堆内存 及 Flink 的托管内存 大小。
Flink 会根据默认值或其他配置参数自动调整剩余内存部分的大小。 关于各内存部分的更多细节,请参考 4.2.4 内存模型详解。
提 示 \color{blue}提示 提示 如果已经明确设置了 任务堆内存(taskmanager.memory.task.heap.size )
和 托管内存(taskmanager.memory.managed.size)
,建议不要再设置 进程总内存(taskmanager.memory.process.size)
或 Flink 总内存(taskmanager.memory.flink.size)
,否则可能会造成内存配置冲突。
如果希望确保指定大小的 JVM 堆内存给用户代码使用,可以明确指定任务堆内存(taskmanager.memory.task.heap.size
)。
指定的内存将被包含在总的 JVM 堆空间中,专门用于 Flink 算子及用户代码的执行。
托管内存(Managed memory)
是由 Flink 负责分配和管理的 本地(堆外)内存(native off-heap memory)
。 以下场景需要使用托管内存:
可以通过以下两种范式指定托管内存的大小:
taskmanager.memory.managed.size
明确指定其大小。taskmanager.memory.managed.fraction
指定在 Flink 总内存中的占比。当同时指定二者时,会优先采用指定的大小(Size)。 若二者均未指定,会根据默认占比进行计算。
请同时参考 4.4.3 State Backend 的内存配置 以及 4.4.4 批处理作业的内存配置。
用户代码中分配的堆外内存被归为 任务堆外内存(Task Off-heap Memory)
,可以通过 taskmanager.memory.task.off-heap.size
指定。
提 示 \color{blue}提示 提示 你也可以调整 框架内存中的 框架堆外内存(Framework Off-heap Memory)。 这是一个进阶配置,建议仅在确定 Flink 框架需要更多的内存时调整该配置。
Flink 将 框架堆外内存
和 任务堆外内存
都计算在 JVM 的直接内存
限制中,请参考 JVM 参数。
提 示 \color{blue}提示 提示 本地内存(非直接内存)
也可以被归在 框架堆外内存
或 任务堆外内存
中,在这种情况下 JVM 的直接内存 限制可能会高于实际需求。
提 示 \color{blue}提示 提示 网络内存(Network Memory)
同样被计算在 JVM 直接内存
中。 Flink 会负责管理网络内存,保证其实际用量不会超过配置大小。 因此,调整网络内存的大小不会对其他堆外内存有实质上的影响。
Flink JVM process for TaskManager
- Total Process Memory
- Total Flink Memory
- JVM Heap Memory
- Framework Heap
- Task Heap
- Off-heap Memory
- Managed Memory
- Direct Memory/Native Memory
- Framework Off-heap
- Task Off-heap
- Network Memory
- JVM specific memory(JVM to run the Flink process)
- JVM Metaspace
- JVM Overhead
如上图所示,下表中列出了 Flink TaskManager 内存模型的所有组成部分,以及影响其大小的相关配置参数。
Component/组成部分 | Configuration options/配置参数 | Default | Description/描述 |
---|---|---|---|
框架堆内存 - Framework Heap Memory | taskmanager.memory.framework.heap.size | 128mb | 用于 Flink 框架的 JVM 堆内存(进阶配置) |
框架堆外内存 - Framework Off-heap Memory | taskmanager.memory.framework.off-heap.size | 128mb | 用于 Flink 框架的堆外内存(直接内存或本地内存)(进阶配置) |
任务堆内存 - Task Heap Memory | taskmanager.memory.task.heap.size | (none) | 用于 Flink 应用的算子及用户代码的 JVM 堆内存 |
任务堆外内存 - Task Off-heap Memory | taskmanager.memory.task.off-heap.size | 0bytes | 用于 Flink 应用的算子及用户代码的堆外内存(直接内存或本地内存) |
托管内存 - Managed memory | taskmanager.memory.managed.size taskmanager.memory.managed.fraction | (none) 0.4 | 由 Flink 管理的用于排序、哈希表、缓存中间结果及 RocksDB State Backend 的本地内存 |
网络内存 - Network Memory | taskmanager.memory.network.min taskmanager.memory.network.max taskmanager.memory.network.fraction | 64mb 1gb 0.1 | 用于任务之间数据传输的直接内存,例如网络传输缓冲。该内存部分为基于 Flink 总内存的受限的等比内存部分 |
JVM Metaspace | taskmanager.memory.jvm-metaspace.size | 256mb | Flink JVM 进程的 Metaspace |
JVM 开销 | taskmanager.memory.jvm-overhead.min taskmanager.memory.jvm-overhead.max taskmanager.memory.jvm-overhead.fraction | 192mb 1gb 0.1 | 用于其他 JVM 开销的本地内存,例如栈空间、垃圾回收空间等。 该内存部分为基于 配置总内存 的 受限的等比内存部分 |
通常情况下,不建议对 框架堆内存 和 框架堆外内存 进行调整。 除非你非常肯定 Flink 的内部数据结构及操作需要更多的内存。 这可能与具体的部署环境及作业结构有关,例如非常高的并发度。 此外,Flink 的部分依赖(例如 Hadoop)在某些特定的情况下也可能会需要更多的 直接内存 或 本地内存。
提 示 \color{blue}提示 提示 不管是 堆内存 还是 堆外内存,Flink 中的 框架内存 和 任务内存 之间目前是没有隔离的。 对框架和任务内存的区分,主要是为了在后续版本中做进一步优化。
如果你是将 Flink 作为一个单独的 Java 程序运行在你的电脑本地而非创建一个集群(例如在 IDE 中),那么只有下列配置会生效,其他配置参数则不会起到任何效果:
组成部分 | 配置参数 | 本地执行时的默认值 |
---|---|---|
任务堆内存 | taskmanager.memory.task.heap.size | 无穷大 |
任务堆外内存 | taskmanager.memory.task.off-heap.size | 无穷大 |
托管内存 | taskmanager.memory.managed.size | 128Mb |
网络内存 | taskmanager.memory.network.min taskmanager.memory.network.max | 64Mb |
本地执行模式下,上面列出的所有内存部分均可以但不是必须进行配置。 如果未配置,则会采用默认值。 其中,任务堆内存和任务堆外内存的默认值无穷大(Long.MAX_VALUE 字节),以及托管内存的默认值 128Mb 均只针对本地执行模式。
提 示 \color{blue}提示 提示 这种情况下,任务堆内存的大小与实际的堆空间大小无关。 该配置参数可能与后续版本中的进一步优化相关。 本地执行模式下,JVM 堆空间的实际大小不受 Flink 掌控,而是取决于本地执行进程是如何启动的。 如果希望控制 JVM 的堆空间大小,可以在启动进程时明确地指定相关的 JVM 参数,即 -Xmx 和 -Xms(framework.heap + task.heap)。
原文链接:https://blog.csdn.net/nazeniwaresakini/article/details/105678146
Flink 社区在 FLIP-49 提出了新版统一的 TaskManager 内存模型及配置,这也是 Flink 1.10 版本最主要的改进与优化点之一。根据社区的说法,该 proposal 致力于解决 1.9 版本及之前的 TaskManager 内存配置的三个缺点:
由于内存模型发生了变化,所以 Flink 1.10 作业的内存配置参数也与 1.9 版本之前有比较大的区别,本文就来具体看一看,防止生产环境中踩坑。
TaskManager 进程总内存(Total Process Memory)
taskmanager.memory.process.size
:无默认值,需要用户指定。Flink 总内存(Total Flink Memory)
JVM 元空间
和 其他额外开销
)。具体包含4大块:Flink 框架内存(堆内、堆外)、任务内存(堆内、堆外)、托管内存(仅堆外)、网络缓存(仅堆外)。taskmanager.memory.flink.size
:无默认值,需要用户指定。Flink 框架(Framework)内存
taskmanager.memory.framework.heap.size
:堆内部分(Framework Heap),默认值 128MB;taskmanager.memory.framework.off-heap.size
:堆外部分(Framework Off-Heap),以直接内存形式分配,默认值 128MB。任务(Task)内存
taskmanager.memory.task.heap.size
:堆内部分(Task Heap),无默认值,一般不建议设置,会自动用 Flink 总内存减去框架、托管、网络三部分的内存推算得出。taskmanager.memory.task.off-heap.size
:堆外部分(Task Off-Heap),以直接内存形式分配,默认值为 0,即不使用。托管(Managed)内存
taskmanager.memory.managed.fraction
:托管内存占 Flink 总内存(taskmanager.memory.flink.size
)的比例,默认值 0.4;taskmanager.memory.managed.size
:托管内存的大小,无默认值,一般也不指定,而是依照上述比例来推定,更加灵活。网络(Network)缓存
taskmanager.memory.network.min
:网络缓存的最小值,默认 64MB;taskmanager.memory.network.max
:网络缓存的最大值,默认 1GB;taskmanager.memory.network.fraction
:网络缓存占 Flink 总内存(taskmanager.memory.flink.size
)的比例,默认值 0.1。若根据此比例算出的内存量比最小值小或比最大值大,就会限制到最小值或者最大值。JVM 元空间(Metaspace)
taskmanager.memory.jvm-metaspace.size
:默认值 256MB。JVM 额外开销(Overhead)
containerized.heap-cutoff-ratio
与 containerized.heap-cutoff-min
参数对 TaskManager 就不再生效了。taskmanager.memory.jvm-overhead.min
:JVM 额外开销的最小值,默认 192MBtaskmanager.memory.jvm-overhead.max
:JVM 额外开销的最大值,默认 1GB;taskmanager.memory.jvm-overhead.fraction
:JVM 额外开销占 TaskManager 进程总内存 taskmanager.memory.process.size
的比例,默认值 0.1。若根据此比例算出的内存量比最小值小或比最大值大,就会限制到最小值或者最大值。Flink 内存参数 与 JVM 参数的关系
上述内存参数会直接影响启动 TaskManager 时使用的 JVM 参数,使用相关工具可以观察到。
到底该如何配置
一大堆参数看得人眼花缭乱,但实际用起来并不需要管那么多。简而言之:
taskmanager.memory.flink.size
taskmanager.memory.process.size
其他部分内存的分配大可交给 Flink 本身去决定。如果需要依照业务特点做微调的话,建议首先修改 网络缓存占比 taskmanager.memory.network.fraction
(根据网络流量大小)与 托管内存 占比 taskmanager.memory.managed.fraction
(根据 RocksDB 状态大小等),进而能够间接影响任务内存的配额。手动指定较多的参数,特别是固定内存量的参数,容易使内存配额出现冲突,导致部署失败,要小心。
Demo
假设 Flink on YARN 环境,设置如下:
taskmanager.memory.process.size = 4096MB
taskmanager.memory.network.fraction = 0.15
taskmanager.memory.managed.fraction = 0.45
可以推算得出各内存指标为:
taskmanage.memory.jvm-overhead = 4096 * 0.1 = 409.6MB
taskmanager.memory.flink.size = 4096 - 409.6 - 256 = 3430.4MB
taskmanager.memory.network = 3430.4 * 0.15 = 514.56MB
taskmanager.memory.managed = 3430.4 * 0.45 = 1543.68MB
taskmanager.memory.task.heap.size = 3430.4 - 128 * 2 - 1543.68 - 514.56 = 1116.16MB
更直观的完整配置示例
#==============================================================================
# Flink on YARN
#==============================================================================
# Total size of the TaskManager process.
taskmanager.memory.process.size: 4096mb
# Framework Heap and Off-Heap Memory size for TaskExecutors.
# taskmanager.memory.framework.heap.size: 128mb
# taskmanager.memory.framework.off-heap.size: 128mb
# Fraction/Size of Total Process Memory to be reserved for JVM Overhead and JVM Metaspace.
# taskmanager.memory.jvm-overhead.fraction: 0.1
# taskmanager.memory.jvm-overhead.min: 192mb
# taskmanager.memory.jvm-overhead.max: 1gb
# taskmanager.memory.jvm-metaspace.size: 256mb
# Fraction of Total Flink Memory to be used as Managed Memory
taskmanager.memory.managed.fraction: 0.45
# When running a stateless job or using a heap state backend (MemoryStateBackend or FsStateBackend), set managed memory to zero.
# taskmanager.memory.managed.size: 0b
# taskmanager.memory.managed.fraction: 0
# Fraction/Size of Total Flink Memory to be used as Network Memory.
taskmanager.memory.network.fraction: 0.15
taskmanager.memory.network.min: 64mb
taskmanager.memory.network.max: 1gb
JobManager 是 Flink 集群的控制单元。 它由三种不同的组件组成:ResourceManager、Dispatcher 和每个正在运行作业的 JobMaster 。 本篇文档将介绍 JobManager 内存在整体上以及细粒度上的配置方法。
本文接下来介绍的内存配置方法适用于 1.11 及以上版本。 Flink 在 1.11 版本中对内存配置部分进行了较大幅度的改动,从早期版本升级的用户请参考 升级指南。
提 示 \color{blue}提示 提示 本篇内存配置文档仅针对 JobManager。与 4.2 配置 TaskManager 内存 相比,JobManager 具有相似但更加简单的内存模型。
配置 JobManager 内存最简单的方法就是进程的 配置总内存。 本地执行模式 下不需要为 JobManager 进行内存配置,配置参数将不会生效。
Flink JVM process for JobManager
- Total Process Memory
- Total Flink Memory
- JVM Heap Memory
- Flink framework
- User code executed during job submission (e.g. for certain batch sources) or in checkpoint completion callbacks
- Off-heap Memory
- JVM specific memory(JVM to run the Flink process)
- JVM Metaspace
- JVM Overhead
Component/组成部分 | Configuration options/配置参数 | Default | Description/描述 |
---|---|---|---|
JVM Heap | jobmanager.memory.heap.size | (none) | JobManager 的 JVM 堆内存 |
Off-heap Memory | jobmanager.memory.off-heap.size | 128mb | JobManager 的堆外内存(直接内存或本地内存) |
JVM metaspace | jobmanager.memory.jvm-metaspace.size | 256mb | Flink JVM 进程的 Metaspace |
JVM Overhead | jobmanager.memory.jvm-overhead.min jobmanager.memory.jvm-overhead.max jobmanager.memory.jvm-overhead.fraction | 192mb 1gb 0.1 | ***用于其他 JVM 开销的本地内存,例如栈空间、垃圾回收空间等。***该内存部分为基于 配置总内存 的 受限的等比内存部分 |
如 4.1.1 配置总内存 中所述,另一种配置 JobManager 内存的方式是明确指定 JVM 堆内存的大小(jobmanager.memory.heap.size
)。 通过这种方式,用户可以更好地掌控用于以下用途的 JVM 堆内存大小:
Flink 需要多少 JVM 堆内存,很大程度上取决于运行的作业数量、作业的结构及上述用户代码的需求。
提 示 \color{blue}提示 提示 如果已经明确设置了 JVM 堆内存(jobmanager.memory.heap.size)
,建议不要再设置 进程总内存(jobmanager.memory.process.size)
或 Flink 总内存(jobmanager.memory.flink.size)
,否则可能会造成内存配置冲突。
在启动 JobManager 进程时,Flink 启动脚本及客户端通过设置 JVM 参数 -Xms 和 -Xmx 来管理 JVM Heap Memory
的大小。 请参考 JVM 参数。
堆外内存包括 JVM 直接内存
和 本地内存
。 可以通过配置参数 jobmanager.memory.enable-jvm-direct-memory-limit
设置是否启用 JVM 直接内存限制。 如果该配置项设置为 true,Flink 会根据配置的堆外内存大小设置 JVM 参数 -XX:MaxDirectMemorySize
。 请参考 JVM 参数。
可以通过配置参数 jobmanager.memory.off-heap.size
设置堆外内存的大小。 如果遇到 JobManager 进程抛出 “OutOfMemoryError: Direct buffer memory”
的异常,可以尝试调大这项配置。 请参考 4.5 常见问题 。
以下情况可能用到堆外内存:
提 示 \color{blue}提示 提示 如果同时配置了 Flink 总内存(jobmanager.memory.flink.size)
和 JVM 堆内存(jobmanager.memory.heap.size)
,且没有配置堆外内存,那么堆外内存的大小将会是 Flink 总内存(jobmanager.memory.flink.size)
减去 JVM 堆内存(jobmanager.memory.heap.size)
,这种情况下,堆外内存的默认大小将不会生效。
如果你是在本地运行 Flink(例如在 IDE 中)而非创建一个集群,那么 JobManager 的内存配置将不会生效。
总的来说,通过指定 JVM 堆内存(jobmanager.memory.heap.size
) 的大小,用户可以更好地掌控:Flink 框架;在作业提交时(例如一些特殊的批处理 Source)及 Checkpoint 完成的回调函数中执行的用户代码 的 JVM 堆内存大小。Flink 需要多少 JVM 堆内存,很大程度上取决于运行的作业数量、作业的结构及上述用户代码的需求。
在配置时,一般选用设置 进程总内存(jobmanager.memory.process.size)
或 Flink 总内存(jobmanager.memory.flink.size)
的方式进行配置,一般 1-2G 就已经足够。
对于 JobManager 进程,可以尝试启用 JVM 直接内存限制(jobmanager.memory.enable-jvm-direct-memory-limit)
,以排除 JVM 直接内存泄漏的可能性。
配置示例
#==============================================================================
# Flink on YARN
#==============================================================================
# Total size of the JobManager (JobMaster / ResourceManager / Dispatcher) process.
jobmanager.memory.process.size: 2048mb
jobmanager.memory.enable-jvm-direct-memory-limit: true
# jobmanager.memory.heap.size: 1.5gb
# jobmanager.memory.off-heap.size: 128mb
# jobmanager.memory.jvm-metaspace.size: 256mb
# jobmanager.memory.jvm-overhead.min: 192mb
# jobmanager.memory.jvm-overhead.max: 1gb
# jobmanager.memory.jvm-overhead.fraction: 0.1
本文在 4.1 配置 Flink 进程的内存 的基础上,介绍如何根据具体的使用场景调整内存配置,以及在不同使用场景下分别需要重点关注哪些配置参数。
独立部署模式下,我们通常更关注 Flink 应用本身使用的内存大小。 建议配置 Flink 总内存(taskmanager.memory.flink.size
或者 jobmanager.memory.flink.size
)或其组成部分。 此外,如果出现 Metaspace 不足 的问题,可以调整 JVM Metaspace 的大小。
这种情况下通常无需配置进程总内存,因为不管是 Flink 还是部署环境都不会对 JVM 开销 进行限制,它只与机器的物理资源相关。
demo
taskmanager.memory.flink.size: 4096mb
jobmanager.memory.flink.size: 2048mb
在容器化部署模式(Containerized Deployment)下(Kubernetes、Yarn 或 Mesos),建议配置 进程总内存(taskmanager.memory.process.size 或者 jobmanager.memory.process.size)
。 该配置参数用于指定分配给 Flink JVM 进程的总内存,也就是需要申请的容器大小。
提 示 \color{blue}提示 提示 如果配置了 Flink 总内存,Flink 会自动加上 JVM 相关的内存部分,根据推算出的进程总内存大小申请容器。
注意:如果 Flink 或者用户代码分配超过容器大小的非托管的堆外(本地)内存,部署环境可能会杀掉超用内存的容器,造成作业执行失败。
请参考 4.5.6 容器内存超用 中的相关描述。
demo
taskmanager.memory.process.size: 4096mb
jobmanager.memory.process.size: 2048mb
jobmanager.memory.enable-jvm-direct-memory-limit: true
本章节内容仅与 TaskManager 相关。
在部署 Flink 流处理应用时,可以根据 State Backend 的类型对集群的配置进行优化。
执行无状态作业 或者 使用 Heap State Backend(MemoryStateBackend 或 FsStateBackend)时,建议将托管内存设置为 0。 这样能够最大化分配给 JVM 上用户代码的内存。
# When running a stateless job or using a heap state backend (MemoryStateBackend or FsStateBackend), set managed memory to zero.
taskmanager.memory.managed.size: 0bytes
taskmanager.memory.managed.fraction: 0
RocksDBStateBackend 使用本地内存。
默认情况下,RocksDB 会限制其内存用量不超过用户配置的 托管内存
。 因此,使用这种方式存储状态时,配置足够多的托管内存是十分重要的。
如果你关闭了 RocksDB 的内存控制,那么在容器化部署模式下如果 RocksDB 分配的内存超出了 申请容器的大小(进程总内存 - taskmanager.memory.process.size)
,可能会造成 TaskExecutor 被部署环境杀掉。
请同时参考如何 3.4.4.3 调整 RocksDB 内存 以及 state.backend.rocksdb.memory.managed。
相关参数有:
taskmanager.memory.process.size: # Default (none)
taskmanager.memory.managed.size: # Default (none)
taskmanager.memory.managed.fraction: # Default 0.4
state.backend.rocksdb.memory.managed: # Default true
Flink 批处理算子使用 托管内存
来提高处理效率。
算子运行时,部分操作可以直接在原始数据上进行,而无需将数据反序列化成 Java 对象。
这意味着 托管内存
对应用的性能具有实质上的影响。
因此 Flink 会在不超过其配置限额的前提下,尽可能分配更多的 托管内存
。 Flink 明确知道可以使用的内存大小,因此可以有效避免 OutOfMemoryError 的发生。 当 托管内存
不足时,Flink 会优雅地将数据落盘。
如果遇到从 TaskExecutorProcessUtils
或 JobManagerProcessUtils
抛出的 IllegalConfigurationException
异常,这通常说明您的配置参数中存在无效值(例如内存大小为负数、占比大于 1 等)或者配置冲突。 请根据异常信息,确认出错的 内存部分的相关文档及配置信息 。
该异常说明 JVM 的堆空间过小。 可以通过增大 总内存(Total Process Memory 或 Total Flink Memory)
、TaskManager 的任务堆内存(taskmanager.memory.task.heap.size)
、JobManager 的 JVM 堆内存(jobmanager.memory.heap.size)
等方法来增大 JVM 堆空间。
提 示 \color{blue}提示 提示 也可以增大 TaskManager 的框架堆内存(taskmanager.memory.framework.heap.size)
。 这是一个进阶配置,只有在确认是 Flink 框架自身需要更多内存时才应该去调整。
该异常通常说明 JVM 的直接内存限制过小,或者存在直接内存泄漏(Direct Memory Leak) 。
请确认用户代码及外部依赖中是否使用了 JVM 直接内存,以及如果使用了直接内存,是否配置了足够的内存空间。 可以通过调整 堆外内存 来增大直接内存限制。 有关堆外内存的配置方法,请参考 TaskManager 的 4.2.3 配置堆外内存 、 JobManager 的 4.3.2.2 配置堆外内存 以及 4.1.2 JVM 参数 的相关文档。
相关参数如下:
# taskmanager off-heap
taskmanager.memory.task.off-heap.size: # Default 0 bytes
taskmanager.memory.network.fraction: # Default 0.1
taskmanager.memory.network.min: # Default 64mb
taskmanager.memory.network.max: # Default 1gb
# jobmanager off-heap
jobmanager.memory.enable-jvm-direct-memory-limit: # Default false
jobmanager.memory.off-heap.size: # Default 128mb
该异常说明 JVM Metaspace 限制过小。 可以尝试调整 TaskManager、JobManager 的 JVM Metaspace。
相关参数如下:
taskmanager.memory.jvm-metaspace.size: # Default 256mb
jobmanager.memory.jvm-metaspace.size: # Default 256mb
该异常仅与 TaskManager 相关。
该异常通常说明网络内存过小。 可以通过调整以下配置参数增大网络内存:
相关参数如下:
taskmanager.memory.network.fraction: # Default 0.1
taskmanager.memory.network.min: # Default 64mb
taskmanager.memory.network.max: # Default 1gb
如果 Flink 容器尝试分配超过其申请大小的内存(Yarn、Mesos 或 Kubernetes),这通常说明 Flink 没有预留出足够的本地内存。 可以通过外部监控系统或者容器被部署环境杀掉时的错误信息判断是否存在容器内存超用。
对于 JobManager 进程,你还可以尝试 启用 JVM 直接内存限制 (jobmanager.memory.enable-jvm-direct-memory-limit
),以排除 JVM 直接内存泄漏的可能性。
如果使用了 RocksDBStateBackend 且没有开启内存控制,也可以尝试增大 TaskManager 的托管内存(taskmanager.memory.managed.size)
。
此外,还可以尝试增大 JVM 开销。相关参数如下:
# 增大总内存(建议)
taskmanager.memory.process.size: # Default (none)
jobmanager.memory.process.size: # Default (none)
# 以下为细粒度的设置,建议使用总内存设置即可
# taskmanager 托管内存(使用 RocksDBStateBackend 或 批处理作业时使用)
taskmanager.memory.managed.size: # Default (none)
# taskmanager JVM overhead
taskmanager.memory.jvm-overhead.min: # Default 192mb
taskmanager.memory.jvm-overhead.max: # Default 1gb
taskmanager.memory.jvm-overhead.fraction: # Default 0.1
# JobManager JVM overhead
jobmanager.memory.jvm-overhead.min: # Default 192mb
jobmanager.memory.jvm-overhead.max: # Default 1gb
jobmanager.memory.jvm-overhead.fraction: # Default 0.1
在 1.10 和 1.11 版本中,Flink 分别对 TaskManager 和 JobManager 的内存配置方法做出了较大的改变。 部分配置参数被移除了,或是语义上发生了变化。 本篇升级指南将介绍如何将 Flink 1.9 及以前版本的 TaskManager 内存配置升级到 Flink 1.10 及以后版本, 以及如何将 Flink 1.10 及以前版本的 JobManager 内存配置升级到 Flink 1.11 及以后版本。
注意: 请仔细阅读本篇升级指南。 使用原本的和新的内存配制方法可能会使内存组成部分具有截然不同的大小。 未经调整直接沿用 Flink 1.10 以前版本的 TaskManager 配置文件或 Flink 1.11 以前版本的 JobManager 配置文件,可能导致应用的行为、性能发生变化,甚至造成应用执行失败。
提 示 \color{blue}提示 提示 在 1.10/1.11 版本之前,Flink 不要求用户一定要配置 TaskManager/JobManager 内存相关的参数,因为这些参数都具有默认值。 新的内存配置要求用户至少指定下列配置参数(或参数组合)的其中之一,否则 Flink 将无法启动。
Option | for TaskManager | for JobManager |
---|---|---|
Option 1 | taskmanager.memory.flink.size | jobmanager.memory.flink.size |
Option 2 | taskmanager.memory.process.size | jobmanager.memory.process.size |
Option 3 | taskmanager.memory.task.heap.size taskmanager.memory.managed.size | jobmanager.memory.heap.size |
Flink 自带的默认 flink-conf.yaml
文件指定了 taskmanager.memory.process.size
(>= 1.10)和 jobmanager.memory.process.size
(>= 1.11),以便与此前的行为保持一致。
可以使用这张 电子表格 来估算和比较原本的和新的内存配置下的计算结果。
本节简要列出了 Flink 1.10 引入的配置参数变化,并援引其他章节中关于如何升级到新配置参数的相关描述。
下列配置参数已被彻底移除,配置它们将不会产生任何效果。
移除的配置参数 | 备注 |
---|---|
taskmanager.memory.fraction | 请参考新配置参数 taskmanager.memory.managed.fraction 的相关描述。 新的配置参数与被移除的配置参数在语义上有所差别,因此其配置值通常也需要做出适当调整。 升级请参考 4.6.1.4 托管内存 |
taskmanager.memory.off-heap | Flink 不再支持堆上的(On-Heap)托管内存。升级请参考 4.6.1.4 托管内存 |
taskmanager.memory.preallocate | Flink 不再支持内存预分配,今后托管内存将都是惰性分配的。升级请参考 4.6.1.4 托管内存 |
下列配置参数将被弃用,出于向后兼容性考虑,配置它们将被解读成对应的新配置参数。
弃用的配置参数 | 对应的新配置参数 |
---|---|
taskmanager.heap.size | 独立部署模式/StandaloneDeployment:taskmanager.memory.flink.size 容器化部署模式/Containerized Deployement:taskmanager.memory.process.size 升级请参考 4.6.1.2 总内存(原堆内存) |
taskmanager.memory.size | taskmanager.memory.managed.size。升级请参考 托管内存 |
taskmanager.network.memory.min | taskmanager.memory.network.min |
taskmanager.network.memory.max | taskmanager.memory.network.max |
taskmanager.network.memory.fraction | taskmanager.memory.network.fraction |
尽管网络内存的配置参数没有发生太多变化,我们仍建议您检查其配置结果。 网络内存的大小可能会受到其他内存部分大小变化的影响,例如总内存变化时,根据占比计算出的网络内存也可能发生变化。 请参考 4.2.4 内存模型详解 。
容器切除(Cut-Off)内存相关的配置参数(containerized.heap-cutoff-ratio 和 containerized.heap-cutoff-min)将不再对 TaskManager 进程生效。 请参考如何升级 4.6.4 容器切除(Cut-Off)内存
在原本的内存配置方法中,用于指定用于 Flink 的总内存的配置参数是 taskmanager.heap.size
或 taskmanager.heap.mb
。 尽管这两个参数以“堆(Heap)”命名,实际上它们指定的内存既包含了 JVM 堆内存,也包含了其他堆外内存部分。 这两个配置参数目前已被弃用。
Flink 在 Mesos 上还有另一个具有同样语义的配置参数 mesos.resourcemanager.tasks.mem
,目前也已经被弃用。
如果配置了上述弃用的参数,同时又没有配置与之对应的新配置参数,那它们将按如下规则对应到新的配置参数。
taskmanager.memory.flink.size
)taskmanager.memory.process.size
)建议您尽早使用新的配置参数取代启用的配置参数,它们在今后的版本中可能会被彻底移除。
在旧版中,JVM 堆空间 包含 托管内存(若配置在堆上)。新版本中,JVM 堆空间 由 总内存 减去 所有其他非堆内存得到。
且新版本中可以更直接地控制用于任务和算子的 JVM 的堆内存(taskmanager.memory.task.heap.size
)。
如果流处理作业选择使用 Heap State Backend(MemoryStateBackend 或 FsStateBackend),那么它同样需要使用 JVM 堆内存。
Flink 现在总是会预留一部分 JVM 堆内存供框架使用(taskmanager.memory.framework.heap.size
)。
明确的大小
原本用于指定明确的托管内存大小的配置参数(taskmanager.memory.size)已被弃用,与它具有相同语义的新配置参数为 taskmanager.memory.managed.size。 建议使用新的配置参数,原本的配置参数在今后的版本中可能会被彻底移除。
占比
此前,如果不指定明确的大小,也可以将托管内存配置为占用总内存减去网络内存和容器切除内存(仅在 Yarn 和 Mesos 上)之后剩余部分的固定比例(taskmanager.memory.fraction)。 该配置参数已经被彻底移除,配置它不会产生任何效果。 请使用新的配置参数 taskmanager.memory.managed.fraction。 在未通过 taskmanager.memory.managed.size 指定明确大小的情况下,新的配置参数将指定托管内存在 Flink 总内存中的所占比例。
RocksDB State Backend
流处理作业如果选择使用 RocksDBStateBackend,它使用的本地内存现在也被归为托管内存。 默认情况下,RocksDB 将限制其内存用量不超过托管内存大小,以避免在 Yarn 或 Mesos 上容器被杀。 你也可以通过设置 state.backend.rocksdb.memory.managed
来关闭 RocksDB 的内存控制。 请参考如何升级 4.6.4 容器切除(Cut-Off)内存 。
其他变化
此外,Flink 1.10 对托管内存还引入了下列变化:
在原本的内存配置方法中,用于指定 JVM 堆内存 的配置参数是:
尽管这两个参数以“堆(Heap)”命名,在此之前它们实际上只有在独立部署模式才完全对应于 JVM 堆内存。 在容器化部署模式下(Kubernetes 和 Yarn),它们指定的内存还包含了其他堆外内存部分。 JVM 堆空间的实际大小,是参数指定的大小减去容器切除(Cut-Off)内存后剩余的部分。 容器切除内存在 1.11 及以上版本中已被彻底移除。
上述两个参数此前对 Mesos 部署模式并不生效。 Flink 在 Mesos 上启动 JobManager 进程时并未设置任何 JVM 内存参数。 从 1.11 版本开始,Flink 将采用与独立部署模式相同的方式设置这些参数。
这两个配置参数目前已被弃用。 如果配置了上述弃用的参数,同时又没有配置与之对应的新配置参数,那它们将按如下规则对应到新的配置参数。
jobmanager.memory.heap.size
)jobmanager.memory.process.size
)建议您尽早使用新的配置参数取代启用的配置参数,它们在今后的版本中可能会被彻底移除。
如果仅配置了 Flink 总内存或进程总内存,那么 JVM 堆内存将是 总内存 减去其他内存部分后剩余的部分。 此外,也可以通过配置 jobmanager.memory.heap.size
的方式直接指定 JVM 堆内存。
从 1.10 版本开始,Flink 通过设置相应的 JVM 参数,对 TaskManager 进程使用的 JVM Metaspace
和 JVM 直接内存
进行限制。
从 1.11 版本开始,Flink 同样对 JobManager 进程使用的 JVM Metaspace
进行限制。
此外,还可以通过设置 jobmanager.memory.enable-jvm-direct-memory-limit
对 JobManager 进程的 JVM 直接内存
进行限制。
Flink 通过设置上述 JVM 内存限制降低内存泄漏问题的排查难度,以避免出现 容器内存溢出 等问题。 请参考常见问题中关于 JVM Metaspace 和 JVM 直接内存 OutOfMemoryError 异常的描述。
在容器化部署模式(Containerized Deployment)下,此前你可以指定切除内存。 这部分内存将预留给所有未被 Flink 计算在内的内存开销。
其主要来源是不受 Flink 直接管理的依赖使用的内存,例如 RocksDB、JVM 内部开销等。
相应的配置参数(containerized.heap-cutoff-ratio 和 containerized.heap-cutoff-min)不再生效。 新的内存配置方法引入了新的内存组成部分来具体描述这些内存用量。
流处理作业如果使用了 RocksDBStateBackend
,RocksDB 使用的 本地内存
现在将被归为 托管内存
。 默认情况下,RocksDB 将限制其内存用量不超过托管内存大小。
使用以下两个参数配置 TaskManager 的托管内存:
其他 堆外(直接或本地)内存 开销,现在可以通过下列配置参数进行设置:
可以通过下列配置参数设置 堆外(直接或本地)内存 开销:
本节描述 Flink 自带的默认 flink-conf.yaml
文件中的变化。
原本的 TaskManager 总内存(taskmanager.heap.size)被新的配置项 taskmanager.memory.process.size 所取代。 默认值从 1024Mb 增加到了 1728Mb。
原本的 JobManager 总内存(jobmanager.heap.size)被新的配置项 jobmanager.memory.process.size 所取代。 默认值从 1024Mb 增加到了 1600Mb。
注 意 \color{blue}注意 注意: 使用新的默认 flink-conf.yaml
可能会造成各内存部分的大小发生变化,从而产生性能变化。
所有配置都在中完成 conf/flink-conf.yaml
,这应该是格式为 YAML 键值对的平面集合 key: value。
启动 Flink 进程时,将分析并评估配置。对配置文件的更改要求重新启动相关进程。
开箱即用的配置将使用默认的 Java 安装。如果要手动覆盖要使用的 Java 运行时,则可以手动设置环境变量 JAVA_HOME 或 配置键 conf/flink-conf.yaml 中的 env.java.home
默认配置支持在不进行任何更改的情况下启动单节点 Flink 会话群集。本节中的选项是基本的分布式 Flink 设置中最常用的选项。
主机和端口
Memory Sizes
注:总大小包括所有内容。Flink 将为 JVM 自己的内存需求减去一些内存(metaspace 和其他),并在其组件(JVM Heap、Off-Heap、TaskManagers 以及网络、托管内存等)之间自动划分和配置剩余的内存。这些值配置为内存大小,例如 1536m 或 2g。
并行度
Checkpointing
您可以直接在 Flink 作业或应用程序中的代码中配置检查点。在应用程序不进行任何配置的情况下,将这些值放在配置中会将它们定义为默认值。
.Web UI
其他
默认情况下,放在这些目录中的数据包括 RocksDB 创建的文件,溢出的中间结果(批处理算法)和缓存的 jar 文件。
持久性/恢复不依赖此数据,但是如果删除此数据,通常会导致重量级的恢复操作。因此,建议将其设置为不会自动定期清除的目录。
默认情况下,Yarn,Mesos 和 Kubernetes 设置会自动将此值配置为本地工作目录。
JobManager 主机名和端口 仅与没有高可用性的独立设置相关。在该设置中, TaskManager 使用配置值来查找(并连接到) JobManager。
在所有高度可用的设置中,TaskManager 都通过高可用性服务(例如 ZooKeeper)发现 JobManager。
Key - Default - Description
这些配置选项控制 Flink 在执行过程中发生故障时的重启行为。通过在中配置这些选项 flink-conf.yaml,可以定义集群的默认重启策略。
仅当未通过设置特定于作业的重启策略时,默认重启策略才会生效。
restart-strategy: (none)
定义在作业失败的情况下使用的重新启动策略。可接受的值为:
如果禁用了 checkpoint,则默认值为 none。如果 checkpoint 已启用,默认值是 fixed-delay 与 Integer.MAX_VALUE 重启尝试和 “1s” 延迟。
固定延迟重启策略 - Fixed Delay Restart Strategy
故障率重启策略 - Failure Rate Restart Strategy
restart-strategy.failure-rate.delay: 1s
如果重新启动策略设置为 failure-rate,则两次连续重启尝试之间的延迟。可以使用符号 1min、20s 来指定。
restart-strategy.failure-rate.failure-rate-interval: 1min
如果重新启动策略设置为 failure-rate,测量失败率的时间间隔。可以使用符号 1min、20s 来指定。
restart-strategy.failure-rate.max-failures-per-interval: 1
如果重新启动策略设置为 failure-rate,则在作业被声明为失败之前,Flink 重试执行的次数。
这些选项仅与以连续流方式执行的 作业/应用程序 相关。
以批处理方式执行的 作业/应用程序 不使用状态后端和检查点,而是使用针对批处理进行了优化的不同内部数据结构。
ZooKeeper 的高可用性设置的选项
eg:
high-availability: zookeeper
high-availability.cluster-id: /flink_cluster
high-availability.storageDir: hdfs:///flink/ha
high-availability.zookeeper.path.root: /flink
high-availability.zookeeper.quorum: 10.0.0.1:2181,10.0.0.2:2181,10.0.0.3:2181
这些配置值控制 TaskManager 和 JobManager 使用内存的方式。
Flink 尝试使用户免受配置 JVM 进行数据密集型处理的复杂性的影响。在大多数情况下,用户只需要设置 taskmanager.memory.process.size
或 taskmanager.memory.flink.size
(取决于设置的方式),可能还会通过 taskmanager.memory.managed.fraction
调整 JVM堆 和 托管内存 的比例。下面的其他选项可用于执行性能调整和修复与内存相关的错误。
有关这些选项如何交互的详细说明,请参阅 4.2 配置 TaskManager 内存 和 4.3 配置 JobManager 内存 的文档。
jobmanager
jobmanager.memory.process.size: (none)
JobManager 的总进程内存大小。这包括 JobManager JVM 进程消耗的所有内存,包括 Flink 总内存,JVM metaspace 和 JVM overhead。在容器化设置中,应将其设置为容器内存
jobmanager.memory.flink.size: (none)
JobManager 的总内存大小。包括 JobManager 消耗的所有内存(JVM Metaspace 和 JVM Overhead 除外)。它由 JVM 堆内存(JVM Heap Memory) 和 堆外内存(Off-heap Memory) 组成
jobmanager.memory.heap.size: (none)
JobManager 的 JVM堆内存 大小。建议的最小值为 128.000mb(134217728字节)
jobmanager.memory.enable-jvm-direct-memory-limit: false
是否启用 JobManager 进程的 JVM 直接内存 限制(-XX:MaxDirectMemorySize)。这个限制将被设置为 jobmanager.memory.off-heap.size
的值
jobmanager.memory.off-heap.size: 128mb
JobManager 的堆外内存大小。此选项涵盖所有堆外内存使用情况,包括直接和本机内存分配。如果 jobmanager.memory.enable-jvm-direct-memory-limit
为 true,则将设置为该值
jobmanager.memory.jvm-metaspace.size: 256mb
JobManager 的 JVM metaspace 大小
jobmanager.memory.jvm-overhead.fraction: 0.1
jobmanager.memory.jvm-overhead.max: 1gb
jobmanager.memory.jvm-overhead.min: 192mb
这是为 JobManager JVM 开销 保留的 堆外内存
,例如 线程堆栈空间
, 编译缓存
等。这包括本机内存,但不包括直接内存,并且在 Flink 计算 JVM 最大直接内存 大小参数时将不进行计数
taskmanager
taskmanager.memory.process.size: (none)
TaskExecutor 的 总进程内存 大小。这包括 TaskExecutor 消耗的所有内存,包括 Flink 总内存,JVM Metaspace 和 JVM Overhead。在容器化设置中,应将其设置为容器内存
taskmanager.memory.flink.size: (none)
TaskExecutor 的 Flink 总内存大小。这包括 TaskExecutor 占用的所有内存(JVM Metaspace 和 JVM Overhead 除外)。它由 框架+任务的堆内和堆外内存,托管内存 和 网络内存组成
taskmanager.memory.task.heap.size: (none)
TaskExecutor 的 任务堆内存 大小。这是为任务保留的 JVM 堆内存的大小。如果未指定,它将导出为 Flink 总内存 减去 框架堆内存,框架堆内存,任务堆外内存,托管内存和网络内存
taskmanager.memory.task.off-heap.size: 0 bytes
TaskExecutor 的 任务堆外内存 大小。这是为任务保留的 堆外内存(JVM 直接内存和本机内存)的大小。当 Flink 计算 JVM 最大直接内存 大小参数时,将完全计算此配置的值
taskmanager.memory.framework.heap.size: 128mb
TaskExecutor 的 框架堆内存 大小。这是为 TaskExecutor 框架保留的 JVM 堆内存的大小,不会分配给任务插槽
taskmanager.memory.framework.off-heap.size: 128mb
TaskExecutor 的 框架外堆内存 大小。这是为 TaskExecutor 框架保留的 堆外内存(JVM 直接内存和本机内存)的大小,不会分配给任务插槽
当 Flink 计算 JVM 最大直接内存 大小参数时,将完全计算此配置的值
taskmanager.memory.managed.fraction: 0.4
taskmanager.memory.managed.size: (none)
TaskExecutor 的 托管内存 大小。这是由 内存管理器 管理的 堆外内存 的大小,保留用于排序,哈希表,中间结果的缓存 和 RocksDB 状态后端
taskmanager.memory.network.fraction: 0.1
taskmanager.memory.network.max: 1gb
taskmanager.memory.network.min: 64mb
TaskExecutor 的 网络内存 大小。网络内存 是为 ShuffleEnvironment 保留的 堆外内存(例如,网络缓冲区)
taskmanager.memory.jvm-metaspace.size: 256mb
TaskExecutor 的 JVM metaspace 大小
taskmanager.memory.jvm-overhead.fraction: 0.1
taskmanager.memory.jvm-overhead.max: 1gb
taskmanager.memory.jvm-overhead.min: 192mb
这是为 JVM 开销 保留的 堆外内存
,例如 线程堆栈空间
, 编译缓存
等。这包括本机内存,但不包括直接内存,并且在 Flink 计算 JVM 最大直接内存 大小参数时将不进行计数
java.io.File.pathSeparator
分隔。用于配置 Flink 的安全性和与外部系统的安全交互的选项。
Flink 的网络连接可以通过 SSL 进行保护。有关详细的设置指南和背景,请参阅 SSL 设置文档 。
请参阅 十一、Kerberos 以获取设置指南以及 Flink 可以通过 Kerberos 对其进行身份验证的外部系统列表。
org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler
。详见官网: https://ci.apache.org/projects/flink/flink-docs-release-1.11/zh/ops/config.html#mesos
这些是配置RocksDB状态后端通常需要的选项。有关高级低级配置和故障排除所需的选项,请参见本节的 Advanced State Backends Options 。
state.backend.rocksdb.memory.managed
选项。如果既未设置此选项,也未设置 state.backend.rocksdb.memory.managed
选项,则每个 RocksDB 列族状态都有其自己的内存缓存(由列族选项控制)。state.backend.rocksdb.memory.managed
或 state.backend.rocksdb.memory.fixed-per-slot
时,此选项才有效。写缓冲区,索引,块缓存
等。这样,RocksDB 内存的三种主要用途将是封顶。state.backend.rocksdb.memory.managed
或 state.backend.rocksdb.memory.fixed-per-slot
时,此选项才有效。对于使用 RocksDB 状态后端的应用程序,Flink 可以从 RocksDB 的本机代码报告指标。此处的指标适用于 operator ,然后按列族进一步细分。值报告为无符号的 longs。
注意:启用RocksDB的本机指标可能会导致性能下降,应谨慎设置。
历史记录服务器保留已完成作业的信息(graphs, runtimes, statistics)。要启用它,您必须在 JobManager(jobmanager.archive.fs.dir
)中启用 “job archiving” 。
有关详细信息,请参见 History Server Docs 。
jobmanager.archive.fs.dir
配置的目录,以便 historyserver 能够读取到已完成的任务信息。Flink 中的实验功能选项。
可查询状态是一项实验性功能,可让您访问Flink的内部状态,如键/值存储。
详见官网。
下面的选项适用于专业用户和修复/调试问题。大多数设置不需要配置这些选项。
Flink 为加载到会话集群的作业动态加载代码。另外,Flink 尝试从应用程序隐藏类路径中的许多依赖项。这有助于减少应用程序代码和类路径中的依赖关系之间的依赖关系冲突。
有关详细信息,请参阅 调试类加载文档 。
state.backend.fs.memory-threshold
的最大值。调整 RocksDB 和 RocksDB 检查点的高级选项。
RocksDB 可配置选项
这些选项可以对 ColumnFamilies 的行为和资源进行细粒度的控制。随着 state.backend.rocksdb.memory.managed
和 state.backend.rocksdb.memory.fixed-per-slot
(Apache Flink 1.10)的引入,只需要使用此处的选项进行高级性能调整。也可以通过在应用程序中指定这些选项 RocksDBStateBackend.setRocksDBOptions(RocksDBOptionsFactory)
。
这些参数可以帮助解决与故障转移以及与错误地将彼此视为故障的组件有关的问题。
jobmanager.rpc.port
。值 “0” 表示选择了一个随机的空闲端口。TaskManager 通过高可用性服务发现此端口(领导者选举 - leader election),因此可以使用随机端口或端口范围工作,而无需任何其他服务发现手段。JobManager
Blob Server
Blob Server 是 JobManager 中的组件。它用于分发太大而无法附加到 RPC 消息且受益于缓存的对象(例如 Jar 文件或大型序列化代码对象)。
ResourceManager
这些配置键独立于所使用的资源编排管理框架(YARN,Mesos等)来控制基本的 ResourceManager 行为。
Data Transport Network Stack
这些选项适用于处理 TaskManager 之间的 streaming 和 batch 处理数据交换的 网络堆栈。
Flink 将 Akka 用于组件(JobManager/TaskManager/ResourceManager)之间的 RPC。Flink 不使用 Akka 进行数据传输。
在 Yarn/Mesos上启动时,可以配置环境变量设置在 JobManager 和 TaskManager 进程上。
containerized.master.env.
:前缀,用于将自定义环境变量传递给 Flink 的 JobManager 进程。LD_LIBRARY_PATH
作为 env 变量传递给 JobManager,请在 flink-conf.yaml
中设置 containerized.master.env.LD_LIBRARY_PATH: "/usr/lib/native"
。containerized.taskmanager.env
. :与上面的类似,这个配置前缀允许为 TaskManagers 设置自定义环境变量。这些选项与 Flink 中不再积极开发的部分有关。这些选项可能会在将来的版本中删除。
DataSet API Optimizer(优化器)
DataSet API Runtime Algorithms
DataSet File Sinks
以 StandAlone HA 模式(适配 Flink on Yarn)为例:
<property>
<name>yarn.resourcemanager.am.max-attemptsname>
<value>10value>
<description>
The maximum number of application master execution attempts.
description>
property>
#==============================================================================
# Rest & web frontend
#==============================================================================
# rest.port: 8081 # 客户端连接到的端口。如果未指定 rest.bind-port,则 REST 服务器将绑定到该端口。
# rest.address: 0.0.0.0 # 客户端用于连接服务器的地址
# rest.bind-port: 8080-8090 # 服务器绑定自身的端口。接受端口列表(50100,50101),范围(50100-50200)或两者的组合
# rest.bind-address: 0.0.0.0
web.submit.enable: true # 启用通过 Flink UI 上传和启动作业
web.upload.dir: /tmp # 存储上载作业的目录(本地目录)
#==============================================================================
# High Availability
#==============================================================================
high-availability: zookeeper
high-availability.zookeeper.path.root: /flink
high-availability.zookeeper.quorum: 10.0.0.1:2181,10.0.0.2:2181,10.0.0.3:2181
high-availability.storageDir: hdfs:///flink/ha # JobManager 元数据保留在文件系统 storageDir 中,并且仅将指向此状态的指针存储在 ZooKeeper 中
#==============================================================================
# Fault tolerance and checkpointing
#==============================================================================
# 控制 Flink 在执行过程中发生故障时的重启行为。当 checkpoint 配置时才能生效,不配 checkpoint 默认为 none,配了则默认为 fixed-delay
restart-strategy: fixed-delay # Default (none)
restart-strategy.fixed-delay.attempts: 2147483647
restart-strategy.fixed-delay.delay: 15s
state.backend: filesystem
state.savepoints.dir: hdfs:///flink/savepoints/default
state.checkpoints.dir: hdfs:///flink/checkpoints/default
state.checkpoints.num-retained: 3
#==============================================================================
# JobManager
#==============================================================================
jobmanager.memory.process.size: 2048mb
# jobmanager.memory.flink.size: 2048mb
jobmanager.memory.enable-jvm-direct-memory-limit: true
# jobmanager.memory.heap.size: 1.5gb
# jobmanager.memory.off-heap.size: 128mb
# jobmanager.memory.jvm-metaspace.size: 256mb
# jobmanager.memory.jvm-overhead.min: 192mb
# jobmanager.memory.jvm-overhead.max: 1gb
# jobmanager.memory.jvm-overhead.fraction: 0.1
jobmanager.archive.fs.dir: hdfs:///flink/completed/ # 将已完成的任务归档存储的目录
#==============================================================================
# TaslManager
#==============================================================================
taskmanager.memory.process.size: 4096mb
# taskmanager.memory.flink.size: 4096mb
taskmanager.numberOfTaskSlots: 4
parallelism.default: 1
# taskmanager.memory.task.heap.size: (none) # TaskExecutor 的任务堆内存 大小,不建议指定具体大小
# taskmanager.memory.task.off-heap.size: 0 bytes # TaskExecutor 的任务堆外内存大小,不建议指定具体大小
# taskmanager.memory.framework.heap.size: 128mb
# taskmanager.memory.framework.off-heap.size: 128mb
# taskmanager.memory.managed.fraction: 0.4 # 由内存管理器管理的堆外内存的大小,保留用于排序,哈希表,中间结果的缓存和 RocksDB 状态后端
# taskmanager.memory.managed.size: (none)
# taskmanager.memory.network.fraction: 0.1
# taskmanager.memory.network.max: 1gb
# taskmanager.memory.network.min: 64mb
# taskmanager.memory.jvm-overhead.fraction: 0.1 # 为 JVM 开销 保留的 堆外内存,例如线程堆栈空间, 编译缓存等。这包括本机内存,但不包括直接内存
# taskmanager.memory.jvm-overhead.max: 1gb
# taskmanager.memory.jvm-overhead.min: 192mb
# taskmanager.memory.jvm-metaspace.size: 256mb
#==============================================================================
# ResourceManager
#==============================================================================
# YARN
yarn.application-attempts: 10 # 当 Jobmanager/ApplicationMaster 失败时,ApplicationMaster 的最大重新启动次数。请注意,整个 Flink 群集将重新启动,并且 YARN Client 将失去连接。该值不应该超过 yarn-site.xml 中的 yarn.resourcemanager.am.max-attemps 的值。
yarn.application-attempt-failures-validity-interval: 10000 # 以毫秒为单位的失败重试间隔窗口
#==============================================================================
# RPC / Akka
#==============================================================================
# Flink 将 Akka 用于组件(JobManager/TaskManager/ResourceManager)之间的 RPC。Flink 不使用 Akka 进行数据传输。
# JobManager 和 TaskManager 通信连接的超时时间。如果网络拥挤经常出现超时错误,可以增大该配置值。
# 超时可能是由于计算机运行缓慢或网络拥塞引起的。超时值需要一个时间单位说明符(ms/s/min/h/d)。
akka.ask.timeout: 2min # Default 10s
# 用于查找 JobManager 的超时。
akka.lookup.timeout: 1min # Default 10s
akka.tcp.timeout: 20s # 所有出站连接超时。如果由于网络速度慢而在连接 TaskManager 时遇到问题,则应增加此值。
akka.transport.heartbeat.interval: 1000s # 心跳间隔,用于检测失效的 TaskManager
akka.transport.heartbeat.pause: 6000s # 如果超过该时间仍未收到 TaskManager 的心跳,认为已挂掉。
#==============================================================================
# HistoryServer
#==============================================================================
historyserver.web.port: 8082
historyserver.web.address: 10.0.0.1
historyserver.web.refresh-interval: 10000
historyserver.archive.fs.dir: hdfs:///flink/completed/
#==============================================================================
# Metrics
#==============================================================================
metrics.reporters: prom
metrics.reporter.prom.class: org.apache.flink.metrics.prometheus.PrometheusReporter
metrics.reporter.prom.port: 9250-9260
metrics.reporter.prom.interval: 10s
# metrics.internal.query-service.port: 0
# metrics.reporter.influxdb.class: org.apache.flink.metrics.influxdb.InfluxdbReporter
# metrics.reporter.influxdb.host: xx.xx.xx.xx
# metrics.reporter.influxdb.port: 8086
# metrics.reporter.influxdb.db: flink
# metrics.reporter.influxdb.username:
# metrics.reporter.influxdb.password:
#==============================================================================
# Security
#==============================================================================
# SSL
# ZooKeeper
# Kerberos
#==============================================================================
# Advanced
#==============================================================================
10.0.0.1:8081
10.0.0.2:8082
10.0.0.1
10.0.0.2
10.0.0.3
生产准备清单提供了配置选项的概述,在将 Apache Flink 作业投入生产之前,应仔细考虑这些选项。尽管 Flink 社区尝试为每种配置提供合理的默认值,以便更轻松地使用和采用 Flink。对于许多用户和场景,这些默认值是开发的良好起点,并且完全足以用于 “一次性” 作业。
但是,一旦您计划将 Flink 应用程序投入生产,通常会增加需求。例如,您希望您的工作(重新)可扩展,并为您的工作和新的 Flink 版本提供良好的升级故事。
在下文中,我们提供了一系列配置选项,您应该在作业投入生产之前检查这些选项。
在每个作业和每个 operator 的粒度上设置的最大并行度决定了有状态 operator 可以扩展到的最大并行度。当前无法在作业开始后更改 operator 的最大并行度而不丢弃该 operator 的状态。
与允许状态算子无限扩展相比,存在最大并行度的原因是,它对应用程序的性能和状态大小有一定影响。 Flink 必须维护特定的元数据,以使其具有重新调整状态的能力,该状态随最大并行度线性增长。
通常,您应该选择足够高的最大并行度,以适应将来对可伸缩性的需求,同时又要使其足够低以保持合理的性能。
注意:最大并行度必须满足以下条件:0 < parallelism <= max parallelism <= 2^15(32767)
您可以使用显式设置最大并行度 setMaxParallelism(int maxparallelism)
。如果未设置最大并行度,则 Flink 将在作业首次启动时使用一个函数来决定 operator 的最大并行度:
如 3.2 Savepoints 文档所述,用户应为算子设置 uid。Uid 对于 Flink 将 算子状态映射到 算子非常重要,而算子状态对于保存点至关重要。默认情况下,通过遍历 JobGraph 并哈希特定的算子属性来生成算子 uid。尽管从用户角度来看这很舒服,但它也非常脆弱,因为对 JobGraph 的更改(例如,交换算子)会导致新的 UUID。要建立稳定的映射,我们需要用户通过提供的稳定的算子 uid setUid(String uid)。
当前,Flink 的保存点二进制格式是特定于状态后端的。使用一个状态后端获取的保存点无法使用另一个状态还原,因此在生产之前,应仔细考虑使用哪个后端。
通常,我们建议避免 MemoryStateBackend 在生产环境中使用,因为它会将快照存储在 JobManager 而不是永久磁盘中。
在 FsStateBackend 和 RocksDB 之间进行选择时,可以在性能和可伸缩性之间进行选择。
FsStateBackend 每个状态访问和更新都对 Java 堆上的对象进行操作,因此速度非常快;但是,状态大小受群集中可用内存的限制。
RocksDB 可以根据可用磁盘空间进行扩展,并且是唯一支持增量快照的状态后端。但是,每个状态访问和更新都需要反序列化,并且可能需要从磁盘读取,这导致平均性能比内存状态后端慢一个数量级。
仔细阅读 3.3 状态后端 文档 充分了解每种选择的利弊。
JobManager 协调每个 Flink 任务部署,负责集群的调度和资源管理。
默认情况下,每个 Flink 群集都有一个 JobManager 实例。这是集群中的单点故障,如果崩溃,则无法提交任何新作业,并且运行的应用程序将失败。与 Apache Zookeeper 一起配置高可用性,可以快速恢复,强烈建议在生产设置中使用。
Flink 提供了命令行界面(CLI),以运行打包为 JAR 文件的程序,并控制其执行。CLI 是任何 Flink 设置的一部分,可在本地单节点设置和分布式设置中使用。它位于
默认情况下,并连接到从同一安装目录启动的正在运行的JobManager。
命令行可以用来:
Flink 具有执行程序的概念,用于定义可用的部署目标。您可以在的输出中看到可用的执行程序 bin/flink --help
,例如:
Options for Generic CLI mode:
-D Generic configuration options for
execution/deployment and for the configured executor.
The available options can be found at
https://ci.apache.org/projects/flink/flink-docs-stabl
e/ops/config.html
-e,--executor DEPRECATED: Please use the -t option instead which is
also available with the "Application Mode".
The name of the executor to be used for executing the
given job, which is equivalent to the
"execution.target" config option. The currently
available executors are: "collection", "remote",
"local", "kubernetes-session", "yarn-per-job",
"yarn-session".
-t,--target The deployment target for the given application,
which is equivalent to the "execution.target" config
option. The currently available targets are:
"collection", "remote", "local",
"kubernetes-session", "yarn-per-job", "yarn-session",
"yarn-application" and "kubernetes-application".
这些示例是关于如何通过脚本提交一个作业
运行不带参数的示例程序:
./bin/flink run ./examples/batch/WordCount.jar
运行带有输入和结果文件参数的示例程序:
./bin/flink run ./examples/batch/WordCount.jar \
--input file:///home/user/hamlet.txt --output file:///home/user/wordcount_out
运行具有并行性16以及输入和结果文件参数的示例程序:
./bin/flink run -p 16 ./examples/batch/WordCount.jar \
--input file:///home/user/hamlet.txt --output file:///home/user/wordcount_out
在禁用flink日志输出的情况下运行示例程序:
./bin/flink run -q ./examples/batch/WordCount.jar
在分离模式下运行示例程序:
./bin/flink run -d ./examples/batch/WordCount.jar
在特定的 JobManager 上运行示例程序:
./bin/flink run -m myJMHost:8081 \
./examples/batch/WordCount.jar \
--input file:///home/user/hamlet.txt --output file:///home/user/wordcount_out
以特定类作为入口点运行示例程序:
./bin/flink run -c org.apache.flink.examples.java.wordcount.WordCount \
./examples/batch/WordCount.jar \
--input file:///home/user/hamlet.txt --output file:///home/user/wordcount_out
使用具有 2 个 TaskManagers(p-每个TaskManager有几个slot) 的 YARN per-job Mode 运行示例程序:
./bin/flink run -m yarn-cluster -p 2 \
-ys 1 -yjm 1024m -ytm 2048m \
-z /flink/yarn_test \
-ynm yarn_test \
./examples/batch/WordCount.jar \
--input hdfs:///user/hamlet.txt --output hdfs:///user/wordcount_out
在 Yarn Session 上运行示例程序:
./bin/flink run -yid application_xxxxxxx \
./examples/batch/WordCount.jar \
--input hdfs:///user/hamlet.txt --output hdfs:///user/wordcount_out
用 Yarn application 运行示例程序:
hadoop fs -mkdir /flink/lib
hadoop fs -mkdir /flink/plugins
hadoop fs -mkdir /flink/dist
hadoop fs -put ./lib/* /flink/lib
hadoop fs -put ./plugins/*/*.jar /flink/plugins
hadoop fs -put flink-clients_2.11-1.11.1.jar flink-core-1.11.1.jar flink-java-1.11.1.jar flink-scala_2.11-1.11.1.jar /flink/dist
hadoop fs -put ./examples/batch/WordCount.jar /tmp
./bin/flink run-application -t yarn-application \
-Dyarn.application.name=flink_word_count_demo \
-Dtaskmanager.numberOfTaskSlots=1 \
-Djobmanager.memory.process.size=1024m \
-Dtaskmanager.memory.process.size=1024m \
-yD yarn.provided.lib.dirs="hdfs:///flink/lib;hdfs:///flink/plugins;hdfs:///flink/dist" \
hdfs:///tmp/WordCount.jar \
--input hdfs:///tmp/LICENSE-2.0.txt --output hdfs:///tmp/wordcount_out
将 WordCount 示例程序的优化执行计划显示为 JSON:
./bin/flink info ./examples/batch/WordCount.jar \
--input file:///home/user/hamlet.txt --output file:///home/user/wordcount_out
列出计划的和正在运行的作业(包括其JobID):
./bin/flink list
列出计划的作业(包括其JobID):
./bin/flink list -s
列出正在运行的作业(包括其JobID):
./bin/flink list -r
列出所有现有作业(包括其JobID):
./bin/flink list -a
在 Flink YARN 会话中列出正在运行的 Flink 作业:
./bin/flink list -m yarn-cluster -yid -r
取消工作:
./bin/flink cancel
使用保存点取消作业(不建议使用;改为使用“停止”):
# -s,--withSavepoint
./bin/flink cancel -s [targetDirectory]
使用保存点正常停止作业(仅用于流作业):
# -p,--savepointPath
./bin/flink stop [-p targetDirectory] [-d]
./bin/flink savepoint [savepointDirectory]
./bin/flink savepoint [savepointDirectory] -yid
# -p,--savepointPath
./bin/flink stop [-p targetDirectory] [-d]
# -s,--withSavepoint
./bin/flink cancel -s [targetDirectory]
./bin/flink run -s :runArgs
./bin/flink run -s -n :runArgs
默认情况下,我们尝试将所有保存点状态与正在提交的作业进行匹配。如果要允许跳过无法通过新作业还原的保存点状态,则可以设置该 allowNonRestoredState 标志。./bin/flink savepoint -d
./bin/flink savepoint -d -j
取消和停止(流处理)作业的区别如下:
在 取消 呼叫中,作业中的算子立即接收 cancel() 方法调用以尽快取消它们。如果算子在取消呼叫后没有停止,Flink 将开始定期中断线程,直到它停止。仅当保存点成功后,作业才会被取消。
停止 呼叫是一种更优雅的方式来停止正在运行的流处理作业。因为 “stop” 信号从 source 流向 sink。当用户请求停止工作时,所有 source 将发送最后一个触发保存点的 checkpoint barrier,在成功完成该保存点之后,它们将通过调用 cancel() 方法结束。
如果指定了 -d 标志,那么将在最后一个检查点屏障之前发出一个 MAX_WATERMARK。
这将导致所有已注册的事件时间计时器触发,从而清除等待特定水印的任何状态,例如窗口。该作业将继续运行,直到所有源都正确关闭。这允许作业完成对所有运行中的数据的处理。
./flink [OPTIONS] [ARGUMENTS]
The following actions are available:
Action "run" compiles and runs a program.
Syntax: run [OPTIONS]
"run" action options:
... ...
略
... ...
详见官网:https://ci.apache.org/projects/flink/flink-docs-release-1.11/zh/ops/python_shell.html#python-repl
Flink 附带了一个集成的交互式 Scala Shell。它可以在本地设置和群集设置中使用。
要将shell与集成的Flink集群一起使用,只需执行:
bin/start-scala-shell.sh local
# Usage: start-scala-shell.sh [local|remote|yarn] [options] ...
该 shell 支持 DataSet,DataStream,Table API 和 SQL。启动后会自动预绑定四个不同的环境。使用 benv
和 senv
分别访问 Batch 和 Streaming ExecutionEnvironment。 使用 btenv
和 stenv
分别访问 BatchTableEnvironment 和 StreamTableEnvironment。
以下示例将在 Scala shell 中执行 wordcount 程序:
Scala-Flink> val text = benv.fromElements(
"To be, or not to be,--that is the question:--",
"Whether 'tis nobler in the mind to suffer",
"The slings and arrows of outrageous fortune",
"Or to take arms against a sea of troubles,")
Scala-Flink>
val counts = text.flatMap {
_.toLowerCase.split("\\W+") }.map {
(_, 1) }.groupBy(0).sum(1)
Scala-Flink> counts.print()
print() 命令将自动将指定的任务发送到 JobManager 进行执行,并在终端中显示计算结果。
可以将结果写入文件。但是,在这种情况下,您需要调用 execute,以运行程序:
Scala-Flink> benv.execute("MyProgram")
与上述批处理程序类似,我们可以通过DataStream API执行流式程序:
Scala-Flink> val textStreaming = senv.fromElements(
"To be, or not to be,--that is the question:--",
"Whether 'tis nobler in the mind to suffer",
"The slings and arrows of outrageous fortune",
"Or to take arms against a sea of troubles,")
Scala-Flink>
val countsStreaming = textStreaming.flatMap {
_.toLowerCase.split("\\W+") }.map {
(_, 1) }.keyBy(_._1).sum(1)
Scala-Flink> countsStreaming.print()
Scala-Flink> senv.execute("Streaming Wordcount")
Stream
Scala-Flink> import org.apache.flink.table.functions.TableFunction
Scala-Flink> val textSource = stenv.fromDataStream(
senv.fromElements(
"To be, or not to be,--that is the question:--",
"Whether 'tis nobler in the mind to suffer",
"The slings and arrows of outrageous fortune",
"Or to take arms against a sea of troubles,"),
'text)
Scala-Flink> class $Split extends TableFunction[String] {
def eval(s: String): Unit = {
s.toLowerCase.split("\\W+").foreach(collect)
}
}
Scala-Flink> val split = new $Split
Scala-Flink> textSource.join(split('text) as 'word).
groupBy('word).select('word, 'word.count as 'count).
toRetractStream[(String, Long)].print
Scala-Flink> senv.execute("Table Wordcount")
Batch
Scala-Flink> import org.apache.flink.table.functions.TableFunction
Scala-Flink> val textSource = btenv.fromDataSet(
benv.fromElements(
"To be, or not to be,--that is the question:--",
"Whether 'tis nobler in the mind to suffer",
"The slings and arrows of outrageous fortune",
"Or to take arms against a sea of troubles,"),
'text)
Scala-Flink> class $Split extends TableFunction[String] {
def eval(s: String): Unit = {
s.toLowerCase.split("\\W+").foreach(collect)
}
}
Scala-Flink> val split = new $Split
Scala-Flink> textSource.join(split('text) as 'word).
groupBy('word).select('word, 'word.count as 'count).
toDataSet[(String, Long)].print
Stream
Scala-Flink> import org.apache.flink.table.functions.TableFunction
Scala-Flink> val textSource = stenv.fromDataStream(
senv.fromElements(
"To be, or not to be,--that is the question:--",
"Whether 'tis nobler in the mind to suffer",
"The slings and arrows of outrageous fortune",
"Or to take arms against a sea of troubles,"),
'text)
Scala-Flink> stenv.createTemporaryView("text_source", textSource)
Scala-Flink> class $Split extends TableFunction[String] {
def eval(s: String): Unit = {
s.toLowerCase.split("\\W+").foreach(collect)
}
}
Scala-Flink> stenv.registerFunction("split", new $Split)
Scala-Flink> val result = stenv.sqlQuery("""SELECT T.word, count(T.word) AS `count`
FROM text_source
JOIN LATERAL table(split(text)) AS T(word)
ON TRUE
GROUP BY T.word""")
Scala-Flink> result.toRetractStream[(String, Long)].print
Scala-Flink> senv.execute("SQL Wordcount")
Batch
Scala-Flink> import org.apache.flink.table.functions.TableFunction
Scala-Flink> val textSource = btenv.fromDataSet(
benv.fromElements(
"To be, or not to be,--that is the question:--",
"Whether 'tis nobler in the mind to suffer",
"The slings and arrows of outrageous fortune",
"Or to take arms against a sea of troubles,"),
'text)
Scala-Flink> btenv.createTemporaryView("text_source", textSource)
Scala-Flink> class $Split extends TableFunction[String] {
def eval(s: String): Unit = {
s.toLowerCase.split("\\W+").foreach(collect)
}
}
Scala-Flink> btenv.registerFunction("split", new $Split)
Scala-Flink> val result = btenv.sqlQuery("""SELECT T.word, count(T.word) AS `count`
FROM text_source
JOIN LATERAL table(split(text)) AS T(word)
ON TRUE
GROUP BY T.word""")
Scala-Flink> result.toDataSet[(String, Long)].print
可以将外部类路径添加到 Scala-shell。当调用 execute 时,这些将与您的 Shell 程序一起自动发送到 Jobmanager。
使用参数 -a
或 --addclasspath
加载其他类。
bin/start-scala-shell.sh [local | remote | yarn] --addclasspath
start-scala-shell.sh -h
许多计算任务需要使用除了 CPU 与内存外的资源,如用深度学习场景需要使用 GPU 来进行加速。为了支持这种扩展资源,Flink 提供了一个扩展资源框架。 该框架支持从底层资源管理系统(如 Kubernetes)请求各种类型的资源,并向算子提供使用这些资源所需的信息。该框架以插件形式支持不同的资源类型。 目前 Flink 仅内置了支持 GPU 资源的插件,你可以为你想使用的资源类型实现第三方插件。
详见官网:https://ci.apache.org/projects/flink/flink-docs-release-1.11/ops/external_resources.html#external-resource-framework
详见官网:https://ci.apache.org/projects/flink/flink-docs-release-1.11/ops/security-kerberos.html
相关配置参数见 5.3.1 ssl
详见官网:https://ci.apache.org/projects/flink/flink-docs-release-1.11/ops/security-ssl.html
Apache Flink 使用文件系统来消费和持久化地存储数据,以处理应用结果以及容错与恢复。以下是一些最常用的文件系统:本地存储,hadoop-compatible,Amazon S3,MapR FS,OpenStack Swift FS,阿里云 OSS 和 Azure Blob Storage。
文件使用的文件系统通过其 URI Scheme 指定。例如 file:///home/user/text.txt 表示一个在本地文件系统中的文件,hdfs://namenode:50010/data/user/text.txt 表示一个在指定 HDFS 集群中的文件。
文件系统在每个进程实例化一次,然后进行缓存/池化,从而避免每次创建流时的配置开销,并强制执行特定的约束,如连接/流的限制。
详见官网: https://ci.apache.org/projects/flink/flink-docs-release-1.11/ops/filesystems/
需要注意的是,使用外部文件系统时,在启动 Flink 之前需将对应的 JAR 文件从 opt 目录复制到 Flink 发行版 plugin 目录下的某一文件夹中,例如:
mkdir ./plugins/s3-fs-hadoop
cp ./opt/flink-s3-fs-hadoop-1.11.0.jar ./plugins/s3-fs-hadoop/
注意,文件系统的插件机制在 Flink 版本 1.9 中引入,以支持每个插件专有 Java 类加载器,并避免类隐藏机制。您仍然可以通过旧机制使用文件系统,即将对应的 JAR 文件复制到 lib 目录中,或使用您自己的实现方式,但是从版本 1.10 开始,S3 插件必须通过插件机制加载,因为这些插件不再被隐藏(版本 1.10 之后类不再被重定位),旧机制不再可用。
尽可能通过基于插件的加载机制使用支持的文件系统。未来的 Flink 版本将不再支持通过 lib 目录加载文件系统组件。
Apache Flink 提供了一些对所有文件系统均适用的基本配置。
如果文件路径未明确指定文件系统的 scheme(和 authority),将会使用默认的 scheme(和 authority):
fs.default-scheme:
例如默认的文件系统配置为 fs.default-scheme: hdfs://localhost:9000/,则文件路径 /user/hugo/in.txt 将被处理为 hdfs://localhost:9000/user/hugo/in.txt。
如果文件系统不能处理大量并发读/写操作或连接,可以为文件系统同时打开的总连接数设置上限。
例如在一个大型 Flink 任务建立 checkpoint 时,具有少量 RPC handler 的小型 HDFS 集群可能会由于建立了过多的连接而过载。
要限制文件系统的连接数,可将下列配置添加至 Flink 配置中。设置限制的文件系统由其 scheme 指定:
fs..limit.total: (数量,0/-1 表示无限制)
fs..limit.input: (数量,0/-1 表示无限制)
fs..limit.output: (数量,0/-1 表示无限制)
fs..limit.timeout: (毫秒,0 表示无穷)
fs..limit.stream-timeout: (毫秒,0 表示无穷)
输入和输出连接(流)的数量可以分别进行限制(fs.
和 fs.
),也可以限制并发流的总数(fs.
)。如果文件系统尝试打开更多的流,操作将被阻塞直至某些流关闭。如果打开流的时间超过 fs.
,则流打开失败。
为避免不活动的流占满整个连接池(阻止新连接的建立),可以在配置中添加无活动超时时间,如果连接至少在 fs.
时间内没有读/写操作,则连接会被强制关闭。
连接数是按每个 TaskManager/filesystem 来进行限制的。因为文件系统的创建是按照 scheme 和 authority 进行的,所以不同的 authority 具有独立的连接池,例如 hdfs://myhdfs:50010/ 和 hdfs://anotherhdfs:4399/ 会有单独的连接池。
Flink DataStream 程序通常设计为可以长时间运行,例如数周,数月甚至数年。与所有长期运行的服务一样,需要维护 Flink 流应用程序,包括修复错误,实施改进或将应用程序迁移到更高版本的Flink群集。
本文档介绍了如何更新 Flink 流应用程序以及如何将正在运行的流应用程序迁移到其他 Flink 群集。
升级流应用程序或将应用程序迁移到其他群集的操作基于 Flink 的 Savepoint 功能。保存点是特定时间点应用程序状态的一致 SNAPSHOT。
有两种方法可以从正在运行的流应用程序中获取保存点。
获取保存点并继续处理。
./bin/flink savepoint [pathToSavepoint]
建议定期获取保存点,以便能够从之前的某个时间点重新启动应用程序。
使用 Savepoint 取消作业。
./bin/flink cancel -s [pathToSavepoint]
./bin/flink stop [-p targetDirectory] [-d]
这意味着在保存点完成之后立即取消应用程序,即,在保存点之后不执行任何其他检查点。
给定从应用程序获取的保存点,可以从该保存点启动相同或兼容的应用程序(请参阅下面的“应用程序状态兼容性”部分)。从保存点启动应用程序意味着初始化其算子的状态,并在保存点中保存算子状态。这是通过使用保存点启动应用程序来完成的。
./bin/flink run -d -s [pathToSavepoint] ~/application.jar
启动应用程序的算子在获取保存点时使用原始应用程序的算子状态(即从中获取保存点的应用程序)进行初始化。启动的应用程序从这一点开始继续处理。
注意:即使 Flink 始终恢复应用程序的状态,它也不能将写入操作还原到外部系统。如果从未停止应用程序的保存点恢复,则可能会出现问题。在这种情况下,应用程序可能在获取保存点后发出数据。重新启动的应用程序可能(取决于您是否更改了应用程序逻辑)再次发出相同的数据。根据 SinkFunction 存储系统的 Distinct,此行为的确切影响可能会有很大差异。如果对像 Cassandra 这样的键值存储进行幂等写入算子操作,则发出两次的数据可能是正常的,但如果附加到像 Kafka 这样的持久日志中则会出现问题。无论如何,您应该仔细检查并测试重新启动的应用程序的行为。
在升级应用程序以修复错误或改进应用程序时,通常的目标是在保存其状态的同时替换正在运行的应用程序的应用程序逻辑。我们通过从原始应用程序中获取的保存点启动升级的应用程序来完成此算子操作。但是,这仅在两个应用程序都是状态兼容的情况下才有效,这意味着升级后的应用程序的算子能够使用原始应用程序的算子的状态初始化其状态。
在本节中,我们将讨论如何修改应用程序以保持状态兼容。
从保存点重新启动应用程序时,Flink会将保存点中存储的算子状态与已启动应用程序的有状态算子进行匹配。匹配基于 算子 ID
完成,算子 ID
也存储在保存点中。每个算子都有一个默认 ID,该 ID 是从算子在应用程序算子拓扑中的位置派生而来的。因此,可以始终从其自己的保存点之一重新启动未修改的应用程序。但是,如果修改了应用程序,则算子的默认 ID 可能会更改。因此,如果已明确指定了算子 ID,则只能从保存点启动已修改的应用程序。为算子分配 ID 非常简单,使用以下uid(String)方法完成:
val mappedEvents: DataStream[(Int, Long)] = events
.map(new MyStatefulMapFunc()).uid("mapper-1")
注意:由于存储在保存点中的算子 ID 和要启动的应用程序中的算子 ID 必须相等,因此强烈建议为将来可能升级的应用程序的所有算子分配唯一的 ID。此建议适用于所有算子,即具有和不具有显式声明的算子状态的算子,因为某些算子具有用户不可见的内部状态。升级没有分配算子 ID 的应用程序要困难得多,并且可能只能通过使用该 setUidHash() 方法的低级解决方法来实现。
重要提示:从 1.3.x 开始,这也适用于属于链的算子。
默认情况下,存储在保存点中的所有状态必须与启动应用程序的算子匹配。但是,用户可以明确同意跳过(从而丢弃)从保存点启动应用程序时无法与算子匹配的状态。在保存点中找不到状态的有状态算子将使用其默认状态进行初始化。用户可以通过调用最佳实践来实现 ExecutionConfig#disableAutoGeneratedUIDs ,如果任何算子不包含自定义唯一 ID ,则调用将使作业提交失败。
升级应用程序时,可以通过一个限制自由修改用户函数和算子。无法更改算子状态的数据类型。这很重要,因为从保存点开始的状态在加载到算子之前(当前)不能转换为不同的数据类型。因此,在升级应用程序时更改算子状态的数据类型会中断应用程序状态一致性,并阻止升级的应用程序从保存点重新启动。
算子状态可以是用户定义的,也可以是内部的。
算子 | 内部算子状态的数据类型 |
---|---|
ReduceFunction[IOT] | IOT (Input and output type) [, KEY] |
FoldFunction[IT, OT] | OT (Output type) [, KEY] |
WindowFunction[IT, OT, KEY, WINDOW] | IT (Input type), KEY |
AllWindowFunction[IT, OT, WINDOW] | IT (Input type) |
JoinFunction[IT1, IT2, OT] | IT1, IT2 (Type of 1. and 2. input), KEY |
CoGroupFunction[IT1, IT2, OT] | IT1, IT2 (Type of 1. and 2. input), KEY |
Built-in Aggregations (sum, min, max, minBy, maxBy) | Input Type [, KEY] |
除了改变一个或多个现有算子的逻辑之外,还可以通过更改应用程序的拓扑结构来升级应用程序,即通过添加或删除算子,更改算子的并行性或修改算子链接行为。
通过更改其拓扑来升级应用程序时,需要考虑一些事项以保持应用程序状态的一致性。
本节介绍了跨版本升级 Flink 以及在各版本之间迁移作业的一般方法。
简而言之,此过程包括 2 个基本步骤:
除了这两个基本步骤之外,还可能需要一些其他步骤,具体取决于您要更改 Flink 版本的方式。在本指南中,我们区分两种跨 Flink 升级的方法:in-place
升级和 shadow copy
升级。
对于 in-place
升级,在获取保存点之后,您需要:
对于 shadow copy
升级,您需要:
在下文中,我们将首先介绍成功进行工作迁移的前提条件,然后再详细介绍之前概述的步骤。
开始迁移之前,请检查要迁移的作业是否遵循保存点的最佳做法。另外,请查看《API 迁移指南》 ,以查看是否有与将保存点迁移到较新版本有关的 API 更改。
特别是,我们建议您检查是否为作业中的算子设置了显式的 uid。
这是一个软前置条件,如果您忘记分配 uid,恢复应该仍然有效。如果遇到无效情况,您可以使用 setUidHash(String hash)
调用手动将以前 Flink 版本中生成的遗留顶点 id 添加到您的作业中。对于每个算子(在算子链中:只有 head 算子),您必须分配 32 个字符的十六进制字符串,表示您可以在 Web ui 或日志中看到的哈希值。
除了算子 uid 之外,目前有两个难以进行的作业迁移前提条件会导致迁移失败:
State Processor API
修改得到的其他引用的保存点。当前,任何保存点数据都由元数据文件内的绝对路径引用,因此无法通过典型的文件系统操作来重定位保存点。Step 1 : 在旧的 Flink 版本中获取一个保存点。
$ bin/flink savepoint :jobId [:targetDirectory]
Step 2 : 将集群更新为新的 Flink 版本。
在此步骤中,我们将更新集群的框架版本。这基本上意味着用新版本替换 Flink 安装的内容。此步骤取决于您如何在群集中运行 Flink(例如,独立运行,在 Mesos 上运行,等等)。
如果您不熟悉在集群中安装 Flink 的信息,请阅读 部署和集群设置文档 。
Step 3 : 从保存点以新的 Flink 版本恢复作业。
$ bin/flink run -s :savepointPath :runArgs
保存点与 Flink 版本兼容,如下表所示:
详见官网: https://ci.apache.org/projects/flink/flink-docs-release-1.11/zh/ops/upgrading.html#compatibility-table
插件通过受限的类加载器促进严格的代码分离。插件无法访问其他插件或Flink中未明确列入白名单的类。这种严格的隔离允许插件包含相同库的冲突版本,而无需重新定位类或收敛到通用版本。当前,文件系统和 metric reporters 是可插拔的,但是将来,连接器,格式甚至用户代码也应该是可插拔的。
插件位于它们自己的文件夹中,并且可以包含多个jar。插件文件夹的名称是任意的。
flink-dist
├── conf
├── lib
...
└── plugins
├── s3
│ ├── aws-credential-provider.jar
│ └── flink-s3-fs-hadoop.jar
└── azure
└── flink-azure-fs-hadoop.jar
每个插件都通过自己的类加载器加载,并且与其他任何插件完全隔离。因此,flink-s3-fs-hadoop
和 flink-azure-fs-hadoop
可能取决于不同的冲突库版本。在创建 FatJar (shading) 期间,无需重新定位任何类。
插件可以从 Flink 的 lib/ 文件夹中访问某些列入白名单的软件包。特别是,所有必需的服务提供程序接口(SPI)都是通过系统类加载器加载的,因此 org.apache.flink.core.fs.FileSystem
即使用户不小心将其捆绑在 FatJar 中,在任何给定的时间都不会存在两个版本。此单例类要求是绝对必要的,以便 Flink 运行时在插件中具有入口点。通过可以发现服务类 java.util.ServiceLoader
,因此请确保 META-INF/services 在 shading 期间保留服务定义。
注意 当前,随着我们完善 SPI 系统,仍然可以从插件访问更多 Flink 核心类。
此外,最常用的记录器框架也已列入白名单,因此可以跨 Flink 核心,插件和用户代码统一进行记录。
除 MapR 之外的所有文件系统 都是可插入的。这意味着它们可以并且应该用作插件。要使用可插入文件系统,请在启动 Flink 之前将相应的 JAR 文件从 ./opt 目录复制到 Flink 发行版 ./plugins 目录下的目录中,例如
mkdir ./plugins/s3-fs-hadoop
cp ./opt/flink-s3-fs-hadoop-1.11.0.jar ./plugins/s3-fs-hadoop/
警告 : s3 file systems(flink-s3-fs-presto
和 flink-s3-fs-hadoop
)只能用作插件,因为我们已经删除了重定位。将它们放在 libs/ 中会导致系统故障。
注意 由于严格的 隔离和插件结构,文件系统再也无法访问 lib/ 中的凭据提供程序。请将任何需要的提供程序添加到相应的插件文件夹中。
Flink 提供的所有度量标准报告程序都可以用作插件。有关更多详细信息,请参阅 Metrics 文档。
每个独立的 JobManager,任务管理器,HistoryServer 和 ZooKeeper 守护重定向 stdout 和 stderr 与一个文件 .out 名的后缀,并写入内部记录到一个文件 .log 后缀。
通过在用户配置的 Java 选项 env.java.opts,env.java.opts.jobmanager,env.java.opts.taskmanager,env.java.opts.historyserver 并且 env.java.opts.client 同样可以定义与使用脚本变量的日志文件 FLINK_LOG_PREFIX,并通过封闭在双引号中的选项评价晚了。使用的日志文件 FLINK_LOG_PREFIX 与默认文件 .out 和 .log 文件一起旋转。
Java Flight Recorder 是 Oracle JDK 中内置的概要分析和事件收集框架。 Java Mission Control 是一组高级工具,可对 Java Flight Recorder 收集的大量数据进行高效且详细的分析。配置示例:
env.java.opts: "-XX:+UnlockCommercialFeatures -XX:+UnlockDiagnosticVMOptions -XX:+FlightRecorder -XX:+DebugNonSafepoints -XX:FlightRecorderOptions=defaultrecording=true,dumponexit=true,dumponexitpath=${FLINK_LOG_PREFIX}.jfr"
JITWatch 是 Java HotSpot JIT 编译器的日志分析器和可视化工具,用于检查内联决策,热门方法,字节码和汇编。配置示例:
env.java.opts: "-XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation -XX:LogFile=${FLINK_LOG_PREFIX}.jit -XX:+PrintAssembly"
如果遇到 OutOfMemoryExceptions Flink 应用程序,则最好在出现内存不足错误时启用堆转储。
env.java.opts: "-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${FLINK_LOG_PREFIX}.hprof"
堆转储将使您能够分析用户代码中的潜在内存泄漏。如果内存泄漏应由 Flink 引起,请联系 dev 邮件列表。
内存使用和垃圾回收会对您的应用程序产生深远的影响。如果GC暂停时间过长,则影响可能从轻微的性能下降到整个群集故障。如果您想更好地了解应用程序的内存和GC行为,则可以在上启用内存日志记录TaskManagers。
taskmanager.debug.memory.log: true
taskmanager.debug.memory.log-interval: 10000 // 10s interval
如果您对更详细的 GC 统计信息感兴趣,则可以通过以下方式激活 JVM 的 GC 日志记录:
env.java.opts: "-Xloggc:${FLINK_LOG_PREFIX}.gc.log -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M -XX:+PrintPromotionFailure -XX:+PrintGCCause"