Flink内存设置思路

1.前言

  对于做实时计算的朋友来说,资源设置都是一个比较麻烦的问题。实时计算不同于离线计算,它的任务都是并行的,启动就会一直占用集群资源,如果资源设置的过多会造成极大的浪费,设置的过少任务会不断发生failover。这里说的资源主要指的就是内存资源,所以本文对Flink的内存设置提供一些思路,尤其是对于容器环境,内存的设置极为重要,否则会被频繁的kill。

  本文将分别介绍1.9版本之前和之后的两类设置方法,这是由于这个版本之后Flink的内存模型发生了极大的变化。

  本文是基于个人的一个使用经验,部分代码,和其他文章而成,里面可能存在错误,望指正。

2.Flink <= 1.9

2.1 例子

  这里用Flink1.8为例,计算内存的代码位于 org.apache.flink.runtime.clusterframework.ContaineredTaskManagerParameters类的create方法。

      按照计算步骤,以taskmanager.heap.size=6g为例子,其他参数保持不动,最终得到的参数如下:

    -Xms4148m  -Xmx4148m   -XX:MaxDirectMemorySize=1996m

            两块内存加起来是6144m = 6g jvm的设置符合参数。

      Flink Dashboard上面显示的是:

    JVM Heap Size:3.95 GB    Flink Managed Memory:2.74 GB

              JVM (Heap/Non-Heap) Commit: Heap:3.95 GB  Non-Heap:141 MB  Total:4.09 GB

      Outside JVM:Capacity:457 MB

      NetWork: count:  xxxxx

2.2 计算过程

  设容器内存总大小是x

  详细看create方法:

    1. cutoff:容器超过3g, 简单可以记成 0.25x

      flink为了防止内存溢出,计算的时候先切了一块内存下来不参与后续计算,这块就是cutoff

      计算公式:

        cutoff = Math.max(containerized.heap-cutoff-min, taskmanager.heap.size * containerized.heap-cutoff-ratio)

      默认值是600和0.25,所以6g的时候=Math.max(600, 6144*0.25) = 1536m

          剩余大小 0.75x6g = 4608m

    2. networkBufMB:简单记成 0.75*0.1x,最大1g

      网络buffer使用内存分成新旧版,这里只关注新版,涉及参数:

        taskmanager.memory.segment-size:32kb

        taskmanager.network.memory.fraction:0.1

        taskmanager.network.memory.min:64mb

        taskmanager.network.memory.max:1g

      计算公式:

        Math.min(taskmanager.network.memory.max,Math.max(taskmanager.network.memory.min, taskmanager.network.memory.fraction * (x - cutoff))

      这里的结果就是:Math.min(1g,  Math.max(64mb, 0.1 * 4608m) = 460.8m

    3. heapSizeMB:0.75 * 0.9x

      taskmanager.memory.off-heap默认为false,主要指的是Flink Managed Memory使用Heap还是Non-heap,默认使用Heap,如果开启使用Non-heap将再减少一部分资源。

        计算公式:x - cutoff - networkBufMB

      这里就是:4147.2    (注意:这个就是-xmx 4148m)

    4. offHeapSizeMB: x - heapSizeMB

      就是1996m       (注意:这个就是XX:MaxDirectMemorySize: 1996m)

      后续:上面只是一个jvm的参数预估设置,实际设置还与运行中环境有关,TaskManagerServices.fromConfiguration

       会计算一个 freeHeapMemoryWithDefrag,计算之前会手动触发gc,然后用Jvm最大内存 - 总内存 + 空闲内存。

       这个值可以认为是一个空运行的flink任务剩余的堆内存了。

       后面将计算Flink管理的内存,这个指的是Flink Managed Memory Segment:  taskmanager.memory.fraction默认是0.7,

       被Flink管理的内存就是:freeHeapMemoryWithDefrag * 0.7

 

2.3 内存划分

  

   所以虽然6g内存计算出来后,heap是4148,但是在dashbord中显示不足4148, 为3.95G=4044.8, Flink managed内存小于 0.75*0.9*0.7 = 2903.04 , dashboard上显示2.74g = 2805.76m

   框架运行需要:4148 - 4044.8 = 103.2m,3.95 * 0.7 = 2.765 >  2.74。没有相等,其他的内存使用暂时没有探究了。

   Flink Managed内存一般用于批处理作业,流处理作业可以调整 taskmanager.memory.fraction,使得这部分内存用于用户代码。

   Non - heap空间一般用于 JVM 的栈空间、方法区等堆外开销外,还包括网络 buffer、batch 缓存、RocksDB

3. Flink >= 1.10

  Flink 1.10对整个内存做了个大改版,需要参考官方文档进行升级:https://ci.apache.org/projects/flink/flink-docs-release-1.10/zh/ops/memory/mem_migration.html

3.1 例子

  这里设置单个taskmanager为14g,taskmanager.memory.managed.fraction为0.5,将会得到以下内容:

    -Xmx5721030656  = 5456MB = 5.328g

    -=1207959552  = 1152MB = 1.125g

    -XX:MaxMetaspaceSize=100663296 = 96MB

  可以发现,上面的加起来等于6704MB,远远不足14g,和1.8版本有很大的不同。

  再看dashboard:

    JVM Heap Size:5.19 GB   Flink Managed Memory:6.45 GB

              JVM (Heap/Non-Heap) : Heap:5.19 GB  Non-Heap:1.33 GB  Total:6.52 GB

      Outside JVM:Capacity:1.01GB

      NetWork: count:  xxxxx

  可以计算得到6.45+6.52+1.01 = 13.98 等于14

3.2 计算过程

  taskmanager.memory.process.size 设置的是容器的内存大小,等于之前的 taskmanager.heap.size

  计算过程在org.apache.flink.runtime.clusterframework.TaskExecutorProcessUtils中processSpecFromConfig方法,TaskExecutorProcessSpec类展示了1.10版本整个内存的组成。

  计算方法分成3种:

    1.指定了taskmanager.memory.task.heap.size和taskmanager.memory.managed.size   见方法:deriveProcessSpecWithExplicitTaskAndManagedMemory

    2.指定了taskmanager.memory.flink.size  见方法:deriveProcessSpecWithTotalFlinkMemory

    3.指定了taskmanager.memory.process.size(容器环境一般指定这个,决定全局容量)

      totalProcessMemorySize = 设置的值 14g,   jvmMetaspaceSize = taskmanager.memory.jvm-metaspace.size,默认96m,  这个对应参数-XX:MaxMetaspaceSize=100663296

      jvmOverheadSize:

        taskmanager.memory.jvm-overhead.min   192m

        taskmanager.memory.jvm-overhead.max  1g

        taskmanager.memory.jvm-overhead.fraction  0.1

        公式  14g * 0.1 = 1.4g  必须在[192m, 1g]之间,所以jvmOverheadSize的大小是1g

      totalFlinkMemorySize =  14g - 1g - 96m = 13216m

      frameworkHeapMemorySize:taskmanager.memory.framework.heap.size  默认128m

      frameworkOffHeapMemorySize:taskmanager.memory.framework.off-heap.size 默认128m

      taskOffHeapMemorySize:taskmanager.memory.task.off-heap.size 默认0

      确定好上面这些参数后,就是最重要的三个指标的计算了:taskHeapMemorySize,networkMemorySize,managedMemorySize

      计算分成确定了:taskmanager.memory.task.heap.size还是没确定。

         1)确定了taskmanager.memory.task.heap.size

            taskHeapMemorySize = 设置值

            managedMemorySize = 设置了使用设置值,否则使用 0.4 * totalFlinkMemorySize

            如果 taskHeapMemorySize + taskOffHeapMemorySize + frameworkHeapMemorySize + frameworkOffHeapMemorySize + managedMemorySize > totalFlinkMemorySize异常

            networkMemorySize 等于剩余的大小,之后还会check这块内存是否充足,可以自己查看对应代码

         2)未设置heap大小

            先确定 managedMemorySize = 设置了使用设置值,否则使用 0.4 * totalFlinkMemorySize,这里就是 0.5 * 13216m = 6608 = 6.45g (这里就是dashboard的显示内容)

            再确定network buffer大小,这个也是有两种情况,不细说。 [64mb, 1g] 0.1 * totalFlinkMemorySize = 1321.6, 所以是1g

            最后剩余的就是taskHeapMemorySize,不能为负数,这里等于  13216 - 6608 - 1024 - 128 - 128 = 5328 = 5.2g (这里约等于dashboard的显示heap大小)

      最后jvm的参数的计算过程:

            jvmHeapSize = frameworkHeapSize + taskHeapSize = 5328 + 128 = 5456

            jvmDirectSize = frameworkOffHeapMemorySize + taskOffHeapSize + networkMemSize = 128 + 1024 = 1152

            jvmMetaspaceSize = 96m

3.3 内存划分

  https://ci.apache.org/projects/flink/flink-docs-release-1.10/ops/memory/mem_detail.html

  

 

  从计算过程,结合上图可以看出Flink 1.10中的一个内存划分了。

  总内存 =  Flink 内存 + JVM Metaspace (96m)+ JVM Overhead (计算为0.1 * 全局大小,结果必须在[192m, 1g]之间)

  Flink内存被划分成6部分:框架运行需要的Heap和Non Heap,默认都是128m

               任务需要的Heap和Non Heap(默认0), Heap是通过计算其他5部分内存,Flink内存剩余得到

               网络缓冲 (0.1 * Flink内存,结果必须在[64mb, 1g]之间)

               Flink管理内存:0.4 * Flink内存

  

 

 4. 总结

  Flink 1.10之前对内存的划分比较简单,主要就是Heap + Non-Heap,之后对内存做了更细致的切分。

  Flink 1.8可以调整taskmanager.memory.fraction 减少Heap中的管理的内存,增大用户代码的内存使用,调整containerized.heap-cutoff-ratio,控制Non-heap空间,这个影响rocksdb。

  Flink 1.10可以调整taskmanager.memory.managed.fraction 控制managed内存,这个影响rocksdb,也会影响taskHeap大小,需要衡量。

  也可以看到Flink内存模型的变化managed内存位置也发生了变化,作用也有了些许变化。

  JVM 主要划分 Heap 和 Non-Heap,Non-Heap又划分为Direct和Native等。

   1.8的Non-Heap都是通过XX:MaxDirectMemorySize设置的

   1.10的Network buffer在Direct里面,另一部分是Native(包括Managed Memory),主要用于rocksdb,如果使用的是Heap状态后台,可以设置小点,也用于Batch。

 

posted @ 2020-06-06 16:37  dark_saber  阅读(16117)  评论(0编辑  收藏  举报