首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于Kubernetes的Apache Spark结构化流的长GC暂停

基于Kubernetes的Apache Spark结构化流的长GC暂停
EN

Stack Overflow用户
提问于 2018-08-27 16:06:22
回答 1查看 1.5K关注 0票数 5

我试图使用运行在Kubernetes上的ApacheSpark2.3ScalaAPI来扩展结构化流管道。这项工作的基本流程如下:

  • 读取包含~1,000,000条记录的静态数据集,这些记录将单个源ids映射到输出聚合
  • 从Kafka读取流数据集,该数据集包含要聚合映射到源id的时间序列指标。
  • 根据源id重新划分每个数据集
  • 加入源id上的两个数据集(这将指标映射到正确的输出聚合,同时也过滤出不应该聚合的kafka数据)
  • 应用水印
  • 拖放重复
  • 汇总数据
  • 写入Kafka输出接收器

我在Kubernetes上运行,并配置了一个集群,每个集群有30个执行者,每个执行器有3个核心。Kafka目前正在每一个源id每秒流600000个指标,并且配置了600个分区。我正在尝试将它们聚合成10个不同的输出(即,每个输出聚合由60000个不同的源ids组成)。我每10秒就有管道触发器来处理卡夫卡的600万张记录。我的聚合窗口是1分钟不重叠的,我的水印设置为30秒。理想情况下,我希望使用更长的水印来解释延迟到达的数据,但是删除复制/水印阶段似乎是一个瓶颈,特别是在调用垃圾收集器时。以下是我最近运行的管道中的一些数据:

每秒处理和输入行

图形显示,管道每秒与输入行保持约8-9分钟,但橙色线下降到绿线以下(时间轴上为10:01),管道很难跟上输入数据速率。我在Spark中寻找为什么会出现减速的线索,并发现一个执行者在删除复制/水印阶段花费了55秒来执行GC。以下是舞台上的汇总统计数据以及事件时间表的放大部分:

我尝试了一些建议这里的技术,结果参差不齐。特别是:

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

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-12-10 17:09:52

所以我应该在解决方案新鲜的时候早点回答这个问题,但最后我做了一些有助于减少垃圾收集时间的事情。我不记得所有帮助我解决这个问题的文档来源,但是我花了很多时间研究它、gceasy推荐和一般的Java文献。不管怎么说,最后帮助你的是:

  • 有限公司参加一个完整的GC活动的核心数量:,我相信这是提高性能的最大贡献者。我注意到,某些执行器在给定的微批处理期间会有大量的GC时间,而在同一kubernetes VM上的其他执行者的计算时间将接近(如果不是完全) GC暂停的持续时间。这种相关性让我走上了一条研究之路,我最终发现JVM (至少对于Java 8)从底层kubernetes VM获得了GC的缺省值,而不是用于JVM运行的容器的有限资源。因为每个容器都有不同的JVM实例,所以每个执行器都有默认的GC参数,假设它是在底层kubernetes VM上运行的唯一JVM。指定一个完整GC事件可用的线程数的GC参数是ParallelGCThreads。JVM默认将其设置为VM上核心总数的百分比。对于一个32核心的kubernetes VM,如果我没记错的话,结果是23。因此,当发生一个完整的GC事件时,GC会引起其他正在执行正常计算的执行程序使用的CPU的争用。我的理论是,这种争论推高了发生在同一底层kubernetes VM上的GC/计算运行时。对于我的特定测试,我最终重写了ConcGCThreads (to 1)和ParallelGCThreads( to 5)的默认参数,因为我每运行32个核心kubernetes VM就运行6个执行器。
  • 增加了每个执行器上的内存:-- gceasy图从来没有真正显示过内存平台。它只是随着管道的继续运行而增加。最后,我把每个执行器专用的内存从8GB增加到了15 GB,之后就稳定在了10 GB左右。您需要的实际内存量可能取决于您的代码。
  • 启用字符串去复制:大部分数据集都是字符串,因此这有助于减少应用程序的内存足印。
  • 修改了最初的堆占用率:,这是在gcasy以及一些SO线程中推荐的。

因此,这是我在这之后使用的JVM参数的最后一组。我希望这能帮到你。

代码语言:javascript
复制
-XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:InitiatingHeapOccupancyPercent=35 -XX:+UseStringDeduplication -XX:ConcGCThreads=1 -XX:ParallelGCThreads=5
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52043133

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档