Flink系统配置

Flink 系统配置

Flink 提供了多个配置参数,用于调整Flink的行为与性能,所有参数均在flink-config.yaml 文件中。下面我们介绍一下几个主要配置。

 

Java and Classloading

默认情况下,Flink启动JVM进程时,会使用系统环境变量里的PATH路径。当然,如果要使用自定义的Java 版本,可以指定JAVA_HOME 环境变量,或是Flink配置文件里的env.java.home 参数。Flink的JVM进程在启动时,也可以配置自定义的JVM 选项(例如 gc 参数),配置的参数为env.java.opts,或者 env.java.opts.jobmanager,以及 env.java.opts.taskmanager.

如果执行的Flink任务使用的是外部依赖(而不是系统本地依赖),则一般不会有Classloading(类加载)的问题。在执行一个Flink应用时,此Flink程序jar包中所有的classes都必须通过一个classloader载入。Flink会将每个job的classes注册到一个独立的user-code classloader中,以确保执行的job的依赖不会与Flink的runtime依赖、或者其他job的依赖产生冲突。User-code class loaders 在job停掉的时候,会被清除。Flink系统的class loader会载入 lib 目录下所有的jar 包文件,而user-code classloaders 亦是源于Flink系统的classloader。

默认情况下,Flink首先在child classloader(也就是user-code classloader)中查询user-code classes,然后在parent classloader(也就是系统classloader)查询classes。此机制可以避免job与Flink系统的版本冲突。不过,我们也可以通过配置classloader.resolve-order 参数转变此顺序,默认为child-first,可以修改为parent-first。

需要注意的是,有些在parent classloader中的类会永远优先于child classloader载入,这些类在参数classloader.parent-first-patterns.default中指定。我们也可以在参数 classloader.parent-first-patterns.additional中指定一组classes,用于优先载入。

 

CPU

Flink 并不会主动限制它消耗的CPU资源,它通过processing slots来控制一个worker 进程(也就是TaskManager)可以被分配的tasks数。一个TaskManger提供了特定数目的slots,它们注册于ResourceManager,并被其所管理。在执行程序时,一个JobManager会申请一个或多个slots,用于执行任务。一个slot可以运行一个application中任意operator的一个并行任务。所以JobManager需要至少申请operator最大并行度的slots数,才能保证任务正常执行。Task在TaskManager中以线程的方式执行,并且按需使用CPU资源。

TaskManager可提供的slots数量由taskmanager.numberOfTaskSlots 参数指定,默认为1。也就是每个TaskManager会提供一个slot。一般仅会在standalone模式下需要调整此参数,在YARN、Kubernetes、Mesos中不需要调整,因为它们可以根据资源申请更多container,而多个container也可以运行在单个节点上,效果与TaskManager中的slot基本一致。

 

Main Memory and NetworkBuffers

Flink的master与worker进程有不同的内存需求。Master进程主要管理计算资源(也就是ResourceManager)以及协调applications的执行(也就是JobManager)。而worker进程的需要进行各类计算并处理数据(可能是大量数据)。

一般来说,master进程的内存需求并不是特别大。默认情况下,它使用1GB的JVM堆内存。如果一个master进程需要管理多个applications,或者有多个operators的一个application,则我们可能需要通过jobmanager.heap.size配置增加它的堆内存。

配置worker进程的内存时,考虑的方面会更多,因为其中会有不同的组件分配不同类型的内存资源。最重要的是JVM 堆内存,通过taskmanager.heap.size进行配置。堆内存由所有objects使用,包括TaskManager runtime、operators、application的functions、以及传输的数据。若一个应用使用的是in-memory或是filesystem 的state backend,则state数据也会存储在JVM。需要注意的是单个task也是有可能消耗掉它所处JVM所有堆内存的。为每个TaskManager仅配置一个slot,会有更好的资源分离,并且防止不同application之间的异常干扰。如果一个application有很多依赖包,则JVM noheap内存也可以增长到很大,因为这部分noheap内存存储了所有TaskManager classes与user-code classes。

除了JVM,还有另外两部分内存消耗:Flink的网络栈与RocksDB(若是使用了它作为state backend)。Flink的网络栈基于的是Netty库,它从native memory(也就是off-heap memory)中分配网络缓冲区(network buffers)。Flink需要足够数量的network buffers,用于在worker 进程之间交换records。缓冲区的数量取决于operator tasks之间的网络连接数量。若是一个application有多个partitioning steps,则此数量的总量可能会非常大,并需要大量的内存用于网络传输。

Flink的默认配置仅适用于较小的计算规模,若是集群计算规模较大,则需要做对应参数调整。如果buffers的数量配置的不合适,则job提交后会抛出以下异常:

java.io.IOException: Insufficient number of network buffers

遇到此情况后,需要为网络栈提供更多的内存。

分配给network buffers内存大小的参数由taskmanager.network.memory.fraction 指定,表示的是JVM内存的百分比多少用于network buffers。taskmanager.memory.segment-size参数指定的是一个network buffer的大小,默认是32KB。调小此参数,也就意味了可以增加network buffers数,但是会影响网络栈的效率。当然,也可以设置network buffer使用内存的最小值(taskmanager.network.memory.min)与最大值(taskmanager.network.memory.max),默认分别为 64MB 与 1GB。这两个绝对值可以限制配置的相对值(也就是之前提到的内存比例)。

RocksDB是另一个需要考虑的内存消耗因素(此处仍然是worker 进程中的内存)。但是衡量RocksDB消耗多少内存一般很难有个直接的结果,因为它取决于一个application中keyed states的数量。Flink会为一个keyed operator的每个task均创建一个独立的(也是内嵌的)RocksDB实例。在每个实例内部,每个不同的state均被存储在一个特定的列族(或表)中。在默认配置下,每个列族需要大约200MB到240MB的堆外内存。对于RocksDB的参数调整,暂时没有一个万金油,需要根据业务进行多个参数调整与测试,然后观察性能。

所以我们在配置调整TaskManager的内存时,主要调整的是JVM的堆内存、RocksDB(如果它是作为state backend)、以及用于网络栈的内存。

 

磁盘

一个Flink worker 进程会因多种原因将数据存储到本地文件系统,包括:

  1. 接收application JAR 文件
  2. 写日志文件
  3. (若是配置了RocksDB为state backend)维护application state

与磁盘相关的配置项有 io.tmp.dirs,我们可以指定一个或多个文件夹(以冒号为分隔符),用于存储数据到本地文件系统。默认情况下,数据会写入到默认的临时文件夹(由Java 的 java.io.tmpdir 指定)或是Linux的临时文件夹(/tmp)。

需要注意的是:请确保临时目录不会被自动清除,有些Linux 发行版会自动清除临时文件夹/tmp。请务必关闭此功能,否则会在job recovery时,由于/tmp文件夹被清理,导致丢失metadata,并最终job 失败。

blob.storage.directory 的参数指定了blob server的本地存储文件夹,用于exchange较大的文件(例如application JAR 文件)。env.log.dir 的参数指定的是TaskManager写入日志的文件夹。最后,RocksDB state backend 会将application的state维持在本地文件系统中。此目录由state.backend.rocksdb.localdir 参数指定。如果此配置文件未显示指定,则RocksDB会使用io.tmp.dirs 参数的值。

 

Checkpointing State Backends

Flink提供几种选项,用于设置:state backends 如何给它们的state做检查点(checkpoint)。一般我们会在application 代码里手动指定。当然我们也可以通过 Flink 的配置文件,提供默认选项。如果未在代码里指定此选项,则会使用默认选项。

State backend 维护的是application的state,所以它也会直接影响到一个application的性能。我们可以通过state.backend 指定默认的state backend。进一步的,我们可以启用异步检查点(state.backend.async)以及增量检查点(state.backend.incremental)。一些backend 并不支持所有的这些选项,所以可能会直接忽视这些配置。我们也可以配置用于检查点(checkpoint)与保存点(savepoint)写入的远端存储根目录。配置参数分别为 state.checkpoint.dir 以及 state.savepoints.dir

一些检查点的选项是某些state backend 特有的。对于RocksDB state backend来说,我们可以定义一个或多个RocksSB存储它本地文件的路径(state.backend.rocksdb.localdir),以及timer state是存储在堆内存(默认是存堆内存)还是RocksDB(配置的参数项为state.backend.rocksdb.timer-service.factory)。

最后,我们可以为一个Flink集群默认启用并配置本地recovery,参数为 state.backend.local-recovery(设置为true即可)。Local state的副本存储的位置也可以配置,参数为 taskmanager.state.local.root-dirs

 

安全

在Flink中,需要对无授权的访问以及数据访问进行安全地限制。对此,Flink支持Kerberos认证,并且可以配置使用SSL对所有网络通信加密。

Flink可以支持Kerberos接入Hadoop生态(YARN,HDFS,HBase)、以及ZooKeeper与Kafka。Flink支持两种认证模式:Keytabs与Hadoop delegation tokens。Keytabs是较好的选择,因为tokens会在一段时间后失效,对长时间流处理应用产生影响。需要注意的是,认证密钥是绑定于Flink集群,而不是一个单独的任务。所有运行在同一个集群上的applications使用同样的认证token。如果需要换另外的credentials,则可以启动一个新集群。配置方法可以参考Flink官方文档。

Flink支持两个通信端的双向认证,并且可以通过SSL对内部或外部网络通信进行加密。对于内部的通信(RPC调用,数据传输,以及blob 服务通信(用于分发libraries等文件),所有的Flink 进程(Dispathcer、ResourceManager、JobManager以及TaskManager)均可以执行双向认证 – 也就是发送端与服务端可以通过SSL证书进行验证。此证书作为一个共享密钥,可以内嵌到containers或附加到YARN启动项里。

对于所有外部与Flink服务的通信(提交任务、控制任务、以及访问REST 接口等),我们也可以启用SSL为这些通信进行加密。双向认证也可以被启用。不过,较为推荐的方法是:配置一个代理服务,用于控制对REST终端节点的访问。因为代理服务可以提供更多的认证与配置选项(相对于Flink来说)。

默认情况下,SSL认证与加密未启用,因为需要额外的手动配置项(如证书、设置KeyStores与TrustStores等)。若有需要,可以参考Flink官方文档进行配置。

 

References

Vasiliki Kalavri, Fabian Hueske. Stream Processing With Apache Flink. 2019

 

posted @ 2019-11-08 13:43  ZacksTang  阅读(5580)  评论(0编辑  收藏  举报