Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/kubernetes/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark Kubernetes上Apache Spark结构化流媒体的长GC暂停_Apache Spark_Kubernetes_Garbage Collection_Jvm_Apache Spark Sql - Fatal编程技术网

Apache spark Kubernetes上Apache Spark结构化流媒体的长GC暂停

Apache spark Kubernetes上Apache Spark结构化流媒体的长GC暂停,apache-spark,kubernetes,garbage-collection,jvm,apache-spark-sql,Apache Spark,Kubernetes,Garbage Collection,Jvm,Apache Spark Sql,我正在尝试使用运行在Kubernetes上的ApacheSpark2.3Scala API扩展结构化流媒体管道。作业的基本流程如下所示: 读取包含约1000000条记录的静态数据集,这些记录将单个源ID映射到输出聚合 从Kafka读取流数据集,其中包含要聚合到其源id的时间序列度量 根据源id重新划分每个数据集 在源id上加入2个数据集(这将度量映射到正确的输出聚合,同时还从kafka中筛选出不应聚合的数据) 应用水印 删除重复项 汇总数据 写入卡夫卡输出接收器 我在Kubernetes上运

我正在尝试使用运行在Kubernetes上的ApacheSpark2.3Scala API扩展结构化流媒体管道。作业的基本流程如下所示:

  • 读取包含约1000000条记录的静态数据集,这些记录将单个源ID映射到输出聚合
  • 从Kafka读取流数据集,其中包含要聚合到其源id的时间序列度量
  • 根据源id重新划分每个数据集
  • 在源id上加入2个数据集(这将度量映射到正确的输出聚合,同时还从kafka中筛选出不应聚合的数据)
  • 应用水印
  • 删除重复项
  • 汇总数据
  • 写入卡夫卡输出接收器
我在Kubernetes上运行,配置了一个集群,其中有30个执行器,每个执行器有3个核心。Kafka目前每秒为每个源id传输600000个度量,并配置了600个分区。我正在尝试将它们聚合为10个不同的输出(即,每个输出聚合由60000个不同的源ID组成)。我每10秒就有一个管道触发器来处理来自卡夫卡的6000000条记录。我的聚合窗口为1分钟不重叠,我的水印设置为30秒。理想情况下,我希望使用更长的水印来解释延迟到达的数据,但丢弃重复项/水印阶段似乎是一个瓶颈,特别是在调用垃圾收集器时。以下是我最近运行的管道中的一些数据:

该图显示,管道每秒跟踪输入行大约8-9分钟,但随后橙色线下降到绿线以下(时间轴上约10:01),管道很难跟踪输入数据速率。我查看了Spark UI,寻找减速原因的线索,发现一个执行者在删除副本/水印阶段花费55秒执行GC。以下是该阶段的汇总统计数据和事件时间轴的放大图:

我尝试了一些建议的技巧,结果好坏参半。特别是:

  • Kryo系列化似乎收效甚微
  • 使用这些设置-XX:+UseG1GC-XX:MaxGCPauseMillis=500可以减少长时间暂停的频率,但它们仍然会发生
  • 我打开GC日志并通过进行处理,并尝试遵循他们的建议。这表明长时间的暂停来自一个完整的GC事件,并且日志没有显示增加GC线程数会有所帮助的症状。平均创建速率为182.18 mb/秒,平均升级速率为49.8 mb/秒
  • 我尝试将NewRatio减少到1,但这会导致更频繁的长暂停,持续时间更短(即每次暂停约25秒,而不是50秒以上)
  • 很难知道我的流数据集使用了多少内存,因为如果我尝试缓存它,就会出现错误

内存建议的其余部分类似于“尝试修改这个参数或那个参数”,但很难尝试每一种排列,并且它没有指出我应该期望的行为。有人能告诉我下一步的方向吗?我觉得55秒对于GC来说是不合理的,应该有一些方法来调整它,这样我的工作就不会受到1个执行者的阻碍。

所以我应该在解决方案还在我脑海中的时候尽快回答这个问题,但我最后做了一些事情,这有助于减少垃圾收集时间。我不记得所有帮助我解决这个问题的文档来源,但我花了很多时间研究了SO、gceasy建议和一般Java GC文献。不管怎样,以下是最终起到帮助作用的:

  • 限制了参与完整GC活动的内核数量:我认为这是提高性能的最大因素。我注意到,在给定的微批处理过程中,某些执行器将有大量的GC时间,而同一kubernetes VM上的其他执行器将有大量的计算时间,这些时间接近(如果不是完全)GC暂停的持续时间。这种相关性引导我走上了一条研究之路,我最终发现JVM(至少对于Java8)从底层kubernetes VM获得其GC默认值,而不是专门用于JVM运行的容器的有限资源。因为每个容器都有一个不同的JVM实例,所以每个执行器都有默认的GC参数,假设它是底层kubernetes VM上运行的唯一JVM。指定可用于完整GC事件的线程数的GC参数为ParallelGCThreads。默认情况下,JVM将其设置为VM上内核总数的百分比。对于一个32核的kubernetes虚拟机,如果我没记错的话,结果是23。因此,当一个完整的GC事件发生时,GC将导致其他执行器在执行正常计算时所使用的CPU上发生争用。我的理论是,这种争论推高了发生在同一底层kubernetes VM上的GC/计算运行时。对于我的特定测试,我最终覆盖了ConcGCThreads(到1)和ParallelGCThreads(到5)的默认参数,因为我每个32核kubernetes VM运行6个执行器
  • 增加了每个执行器的内存:gceasy图形从未真正显示内存平台。它只是随着管道的继续运行而增加。最后,我将每个执行器的专用内存从8GB增加到了15GB,此后,内存稳定在10GB左右。实际需要的内存量可能取决于代码
  • 启用了字符串重复数据消除:我的大多数数据集都是字符串,因此这有助于减少我的应用程序的总体内存足迹
  • 在中修改了
    -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:InitiatingHeapOccupancyPercent=35 -XX:+UseStringDeduplication -XX:ConcGCThreads=1 -XX:ParallelGCThreads=5