计算框架喜欢Apache火花已被广泛采用以构建大规模数据应用。对于优步,数据是在战略决策和产品开发的核心。为了帮助我们更好地利用这一数据,我们可以在我们的全球工程办事处管理火花的大规模部署。
虽然Spark使数据技术更可访问,右侧尺寸分配给Spark应用程序的资源以及优化我们的数据基础架构的运营效率需要对这些系统的更细粒度的见解,即其资源使用模式。
为了在不改变用户代码的情况下,我们建立和开放的这些模式JVM Profiler.,一个分布式分布式分布式分布式分析器,用于收集性能和资源使用指标并为其提供进一步的分析。虽然为Spark构建,但其通用实现使其适用于基于任何Java虚拟机(JVM)的服务或应用程序。请继续阅读,了解Uber如何使用此工具来配置我们的Spark应用程序,以及如何为您的系统使用它。
分析挑战
在每天的基础上,Uber支持成千上万的应用程序运行在成千上万台机器上。随着我们技术堆栈的增长,我们很快意识到我们现有的性能分析和优化解决方案将不能满足我们的需求。特别是,我们希望能够:
在应用程序级别的大量过程中关联指标
在分布式环境中,多个Spark应用程序在同一服务器上运行,每个Spark应用程序都有大量的进程(例如,数千个求助者)在许多服务器上运行,如图1所示:
我们现有的工具只能监控服务器级度量标准,并没有为单个应用程序仪表指标。我们需要一个可以为每个进程收集指标的解决方案,并将它们与每个应用程序的进程相关联。此外,我们不知道这些进程何时将启动以及他们将需要多长时间。为了能够在此环境中收集指标,需要使用每个进程自动启动分析器。
使度量指标集合对任意用户代码不具有侵入性
在他们当前的实现中,Spark和Apache Hadoop库不会导出绩效指标;但是,在不改变用户或框架代码的情况下,我们需要收集这些指标的情况。例如,如果我们在Hadoop分布式文件系统(HDFS)NameNode上遇到高延迟,我们希望检查每个Spark应用程序所观察到的延迟,以确保尚未复制这些问题。由于NameNode客户端代码嵌入我们的Spark库中,因此修改其源代码添加到添加此特定度量标准时,它很麻烦。为了跟上我们数据基础架构的永久增长,我们需要能够随时进行任何应用程序,而不会更改代码。此外,实现更非侵入式度量收集过程将使我们能够在加载时间期间将代码动态注入Java方法。
介绍JVM分析器
为了解决这两个挑战,我们建立和开放我们的挑战JVM Profiler.。有一些现有的开源工具,如etsy的statsd-jvm-profiler,它可以在各个应用程序级别收集指标,但它们不提供动态注入代码的能力,以收集指标的现有Java二进制文件。灵感来自这些工具中的一些,我们构建了诸如更多功能,例如任意Java方法/参数分析。
JVM分析器做什么?
JVM Profiler由三个关键功能组成,使得更容易收集性能和资源使用量度,然后将这些指标(例如Apache Kafka)提供给其他系统以进行进一步分析:
- java代理:通过将Java代理合并到我们的Profiler中,用户可以以分布式方式收集用于JVM进程的各种度量(例如CPU /内存使用情况)和堆栈跟踪。
- 高级分析功能:我们的JVM Profiler允许我们跟踪用户代码中的任意Java方法和参数,而无需进行任何实际的代码更改。该特性可用于跟踪Spark应用程序的HDFS NameNode RPC调用延迟,识别慢的方法调用。它还可以跟踪每个Spark应用程序读取或写入的HDFS文件路径,以识别热文件,以便进一步优化。
- 数据分析报告:在优步,我们使用探查器向Kafka主题和Apache Hive表报告指标,使数据分析更快更容易。
典型用例
我们的JVM Profiler支持各种用例,最值得注意的是,可以介绍任意Java代码。使用简单的配置更改,JVM Profiler可以在Spark应用程序中附加到每个执行程序并收集Java方法运行时指标。下面,我们触摸其中一些用例:
- 调整执行器:我们使用来自JVM Profiler的内存度量来跟踪每个执行程序的实际内存使用情况,这样我们就可以为Spark“executor-memory”参数设置适当的值。
- 监视HDFS NameNode RPC延迟:我们在类上配置方法org.apache.hadoop.hdfs.protocolpb.clientnamoodeprotocoltranslatorpb.在Spark应用程序中识别NameNode调用的长延迟。我们每天用数十亿这样的RPC调用监视超过5万个Spark应用程序。
- 监视器驱动程序删除事件:我们个人资料方法org.apache.spark.scheduler.livelistenerbus.ondropevent.追踪Spark驱动程序事件队列变得太长并丢弃事件的情况。
- 跟踪数据血统:我们在方法上配置文件路径参数org.apache.hadoop.hdfs.protocolpb.clientnamoodeprotocoltranslatorpb.getblocklocations.和org.apache.hadoop.hdfs.protocolpb.clientnamodepropoltranslatorpb.addblock.追踪Spark应用程序读取和写入哪些文件。
实施细节和可扩展性
为了使实现尽可能无缝,JVM Profiler有一个非常简单和可扩展的设计。人们可以很容易地添加额外的profiler实现来收集更多的指标,也可以部署自己的定制记录器,将指标发送到不同的系统进行数据分析。
JVM Profiler代码通过A加载到Java进程中Java代理参数,一旦进程开始。它主要由三部分组成:
- 类文件变换器:在进程中使用Java方法字节码来分析任意用户代码并将度量保存在内部度量缓冲区中。
- 度量分析器
- CPU /内存分析器:通过通过收集CPU /内存使用量度指标JMX并将他们发送给记者。
- 方法持续时间分析器:读取方法持续时间(延迟)来自度量缓冲区的指标并发送给记者。
- 方法参数分析器:从metrics缓冲区读取方法参数值并发送给报告器。
- 记者
- 控制台记者:在控制台输出中写下指标。
- 卡夫卡记者:向Kafka主题发送指标。
如何扩展JVM分析器以通过自定义报告器发送指标
用户可以实现自己的记者,并使用-javaagent选项指定他们,如:
java.
-JavaAgent:JVM-Profiler-0.0.5.jar =Reporter = com.uber.profiping.reporters.CustomReporter.
与优步数据基础架构集成
我们将我们的JVM分析器指标与Uber的内部数据基础架构集成,以启用:
- 整个集群范围的数据分析:指标首先被送入Kafka并摄取到HDFS,然后用Hive / Presto / Spark查询。
- 实时火花应用调试:我们使用flink实时使用flink为单个应用程序聚合,并写入我们的MySQL数据库,然后用户可以通过基于Web的界面查看指标。
使用JVM Profiler
下面,我们提供如何使用我们的JVM Profiler来跟踪简单的Java应用程序的说明:
首先,我们git克隆项目:
通过运行以下命令,我们构建项目:
接下来,我们调用构建结果jar文件(例如,e.g.target/jvm-profiler -0.0.5.jar),并使用以下命令运行JVM Profiler内的应用程序:
该命令运行示例Java应用程序,并将其性能和资源使用度量报告给输出控制台。例如:
分析器也可以通过如下命令向Kafka主题发送指标:
使用Profiler来配置Spark应用程序
现在,让我们演练一下如何使用Spark应用程序运行分析器。
假设我们已经有一个HDFS集群,我们将JVM Profiler JAR文件上传到我们的HDFS:
然后我们使用Spark-Subment命令行启动带有Profiler的Spark应用程序:
度量标准查询示例
在Uber,我们将我们的指标发送到Kafka主题和程序背景数据管道,以自动将它们摄入到蜂巢表中。用户可以设置类似的管道,并使用SQL查询分析器指标。他们还可以编写自己的记者,将指标发送到SQL数据库,如MySQL和那里的查询。以下是Hive Table Schema的示例:
下面,我们在运行以前的SQL查询时提供示例结果,该查询显示了Spark Executors的每个进程的内存和CPU度量:
| 角色 | processuuid. | maxHeapMemoryMB | avgprocesscpuload. |
| 执行者 | 6D3AA4EE-4233-4CC7-A628-657E1A87825D | 2805.255325 | 7.61E-11. |
| 执行者 | 21F418D1-6D4F-440D-B28A-4EBA1A3BB53D | 3993.969582 | 9.56E-11. |
| 执行者 | A5DA6E8C-149B-4722-8FA8-74A16BAABCF8 | 3154.484474 | 8.18E-11. |
| 执行者 | a1994e27 - 59 - bd - 4 - cda - 9 - de3 - 745 ead954a27 | 2561.847374 | 8.58E-11. |
结果和下一步
我们将JVM Profiler应用于Uber最大的Spark应用之一(它使用1000多个executor),在这个过程中,每个executor的内存分配减少了2GB,从7GB减少到5GB。对于这个Spark应用程序,我们节省了2TB内存。
我们还将JVM Profiler应用到Uber内部Spark应用的所有Hive中,发现了一些提高内存使用效率的机会。下面的图3显示了我们发现的一个结果:大约70%的应用程序使用了不到80%的已分配内存。我们的研究结果表明,我们可以为大多数这些应用程序分配更少的内存,并将内存利用率提高20%。
随着我们继续发展我们的解决方案,我们期待着通过我们的jvm减少更多的内存。
JVM Profiler.是一个独立的开源项目,我们欢迎其他开发人员使用此工具并贡献(例如提交拉请求)!
我们在西雅图,帕洛阿尔托和旧金山的大数据工程团队正在致力于扩展整个Hadoop生态系统,包括HDFS,Hive,Presto和Spark。我们构建了这家族开源软件的顶部的技术,以帮助我们做出更好的数据驱动的业务决策。如果这听起来有吸引力,请查看我们的工作机会并考虑加入我们的团队!
照片信用头:Seahorse,RoatanConor Myhrvold著,洪都拉斯。
订阅我们的新闻跟上超级工程的最新创新。






