• 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。

  • 相关阅读:
    使用Emacs:生存篇
    编程之美:平面最近点对
    SOA体系结构之基础培训教程-大纲篇
    DNS:域名系统
    IIS7中 ASP.NET授权功能如何实现对静态文件的控制
    JVM内存管理学习总结(一)
    FMX中实现PostMessage的方法
    ddd
    4部门明确软件IC产业企业所得税优惠政策
    不要过分相信虚拟机,特别是网络连接方面
  • 原文地址:https://www.cnblogs.com/lighten/p/13053828.html
Copyright © 2020-2023  润新知