闪电般的统一分析引擎

Useful Developer Tools

Reducing Build Times

SBT: Avoiding Re-Creating the Assembly JAR

Spark的默认构建策略是组装一个包含所有依赖项的jar. 在进行迭代开发时,这可能很麻烦. 在本地进行开发时,可以创建一个包含所有Spark依赖项的程序集jar,然后在进行更改时仅重新打包Spark本身.

$ build/sbt clean package
$ ./bin/spark-shell
$ export SPARK_PREPEND_CLASSES=true
$ ./bin/spark-shell # Now it's using compiled classes
# ... do some local development ... #
$ build/sbt compile
# ... do some local development ... #
$ build/sbt compile
$ unset SPARK_PREPEND_CLASSES
$ ./bin/spark-shell
 
# You can also use ~ to let sbt do incremental builds on file changes without running a new sbt session every time
$ build/sbt ~compile

Maven: Speeding up Compilation with Zinc

Zinc是SBT增量编译器的长期运行的服务器版本. 当在本地作为后台进程运行时,它可以加快基于Scala的项目(如Spark)的构建. 定期使用Maven重新编译Spark的开发人员将对Zinc最感兴趣. 项目现场提供了zinc和运行指导; OS X用户可以使用brew install zinc来安装它.

如果使用build/mvn软件包, zinc将自动下载并用于所有构建. 除非设置了ZINC_PORT环境变量,否则此过程将在首次调用build/mvn后自动启动并绑定到端口3030. 随后,可以通过运行build/zinc-<version>/bin/zinc -shutdown随时关闭zinc工艺,并在调用build/mvn时自动重启.

Building submodules individually

例如,您可以使用以下命令构建Spark Core模块:

$ # sbt
$ build/sbt
> project core
> package

$ # or you can build the spark-core module with sbt directly using:
$ build/sbt core/package

$ # Maven
$ build/mvn package -DskipTests -pl core

Running Individual Tests

在本地进行开发时,运行单个测试或几个测试而不是运行整个测试套件通常很方便.

Testing with SBT

运行单个测试的最快方法是使用sbt控制台. 保持sbt控制台最快,并在需要时使用它重新运行测试是最快的. 例如,要运行特定项目中的所有测试,例如core

$ build/sbt
> project core
> test

您可以使用testOnly命令运行一个测试套件. 例如,运行DAGSchedulerSuite:

> testOnly org.apache.spark.scheduler.DAGSchedulerSuite

testOnly命令接受通配符; 例如,您还可以使用以下DAGSchedulerSuite运行DAGSchedulerSuite

> testOnly *DAGSchedulerSuite

或者,您可以运行调度程序包中的所有测试:

> testOnly org.apache.spark.scheduler.*

如果您只想在DAGSchedulerSuite运行单个测试,例如名称中包含" SPARK-12345"的测试,则可以在sbt控制台中运行以下命令:

> testOnly *DAGSchedulerSuite -- -z "SPARK-12345"

如果愿意,可以在命令行上运行所有这些命令(但这比使用打开的控制台运行测试要慢). 为此,您需要将testOnly和以下参数括在引号中:

$ build/sbt "core/testOnly *DAGSchedulerSuite -- -z SPARK-12345"

有关如何使用sbt运行单个测试的更多信息,请参见sbt文档 .

Testing with Maven

使用Maven,可以使用-DwildcardSuites标志来运行单独的Scala测试:

build/mvn -Dtest=none -DwildcardSuites=org.apache.spark.scheduler.DAGSchedulerSuite test

您需要-Dtest=none以避免运行Java测试. 有关ScalaTest Maven插件的更多信息,请参考ScalaTest文档 .

要运行各个Java测试,可以使用-Dtest标志:

build/mvn test -DwildcardSuites=none -Dtest=org.apache.spark.streaming.JavaAPISuite test

Testing PySpark

要运行单独的PySpark测试,您可以使用python目录下的run-tests脚本. 测试用例位于每个PySpark软件包下的tests软件包中. 请注意,如果您在Apache Spark的Scala或Python端添加了一些更改,则需要在运行PySpark测试之前再次手动构建Apache Spark才能应用更改. 运行PySpark测试脚本不会自动生成它.

另外,请注意,在macOS High Serria +上使用PySpark仍存在问题. 为了运行某些测试,应将OBJC_DISABLE_INITIALIZE_FORK_SAFETY设置为YES . 有关更多详细信息,请参见PySpark问题Python问题 .

要在特定模块中运行测试用例:

$ python/run-tests --testnames pyspark.sql.tests.test_arrow

要在特定的类中运行测试用例:

$ python/run-tests --testnames 'pyspark.sql.tests.test_arrow ArrowTests'

要在特定类中运行单个测试用例:

$ python/run-tests --testnames 'pyspark.sql.tests.test_arrow ArrowTests.test_null_conversion'

您还可以在特定模块中运行doctests:

$ python/run-tests --testnames pyspark.sql.dataframe

最后,在同一位置还有另一个脚本,称为" run-tests-with-coverage ,它为PySpark测试生成覆盖率报告. 它接受与run-tests相同的参数.

$ python/run-tests-with-coverage --testnames pyspark.sql.tests.test_arrow --python-executables=python
...
Name                              Stmts   Miss Branch BrPart  Cover
-------------------------------------------------------------------
pyspark/__init__.py                  42      4      8      2    84%
pyspark/_globals.py                  16      3      4      2    75%
...
Generating HTML files for PySpark coverage under /.../spark/python/test_coverage/htmlcov

您可以通过直观下HTMLS检查覆盖报告/.../spark/python/test_coverage/htmlcov .

请通过python/run-tests[-with-coverage] --help检查其他可用选项.

Testing K8S

如果您对Apache Spark中的K8S绑定进行了更改,那么您应该在提交PR之前在本地进行测试. 这样做相对简单,但是需要在本地(对您)安装minikube . 由于minikube与主机系统的交互方式,请确保进行如下设置:

  • minikube版本v0.34.1(或更高版本,但版本之间的向后兼容性差强人意)
  • 您必须使用VM驱动程序! 使用--vm-driver=none选项运行minikube要求启动minikube / k8s的用户具有root访问权限. 我们的Jenkins工人使用kvm2驱动程序. 更多细节在这里 .
  • kubernetes版本v1.13.3(可以通过执行minikube config set kubernetes-version v1.13.3

正确设置minikube并成功完成快速入门后,您可以在本地测试更改. 所有后续命令应从您的根spark / repo目录运行:

1)建立一个tarball来测试:

export DATE=`date "+%Y%m%d"`
export REVISION=`git rev-parse --short HEAD`
export ZINC_PORT=$(python -S -c "import random; print random.randrange(3030,4030)")

./dev/make-distribution.sh --name ${DATE}-${REVISION} --pip --tgz -DzincPort=${ZINC_PORT} \
     -Phadoop-2.7 -Pkubernetes -Pkinesis-asl -Phive -Phive-thriftserver

2)使用该tarball并运行K8S集成测试:

PVC_TMP_DIR=$(mktemp -d)
export PVC_TESTS_HOST_PATH=$PVC_TMP_DIR
export PVC_TESTS_VM_PATH=$PVC_TMP_DIR

minikube --vm-driver=<YOUR VM DRIVER HERE> start --memory 6000 --cpus 8

minikube mount ${PVC_TESTS_HOST_PATH}:${PVC_TESTS_VM_PATH} --9p-version=9p2000.L --gid=0 --uid=185 &

MOUNT_PID=$(jobs -rp)

kubectl create clusterrolebinding serviceaccounts-cluster-admin --clusterrole=cluster-admin --group=system:serviceaccounts || true

./resource-managers/kubernetes/integration-tests/dev/dev-run-integration-tests.sh \
    --spark-tgz ${WORKSPACE}/spark-*.tgz

kill -9 $MOUNT_PID
minikube stop

运行完成后,集成测试日志保存在此处: ./resource-managers/kubernetes/integration-tests/target/integration-tests.log

直接从吊舱和容器中获取日志是读者的一项练习.

Kubernetes,更重要的是,minikube具有快速的发布周期,并且发现点发布存在漏洞,并且/或者破坏了旧的和现有的功能. 如果您无法通过Jenkins进行测试,但是在本地可行,请随时提出Jira问题.

ScalaTest Issues

如果在运行ScalaTest时发生以下错误

An internal error occurred during: "Launching XYZSuite.scala".
java.lang.NullPointerException

这是由于类路径中的Scala库不正确所致. 要解决这个问题:

  • Right click on project
  • Select Build Path | Configure Build Path
  • Add Library | Scala Library
  • Remove scala-library-2.10.4.jar - lib_managed\jars

在"找不到Web UI的资源路径:org / apache / spark / ui / static"的情况下,这是由于类路径问题(某些类可能未编译)引起的. 要解决此问题,从命令行运行测试就足够了:

build/sbt "test-only org.apache.spark.rdd.SortingSuite"

Running Different Test Permutations on Jenkins

在Jenkins上对拉取请求运行测试时,可以在拉取请求的标题中添加特殊短语以更改测试行为. 这包括:

  • [test-maven] - signals to test the pull request using maven
  • [test-hadoop2.7] -使用Spark的Hadoop 2.7配置文件进行测试的信号
  • [test-hadoop3.2] -使用Spark的Hadoop 3.2配置文件进行测试的信号
  • [test-hadoop3.2][test-java11] -使用JDK 11使用Spark的Hadoop 3.2配置文件进行测试的信号
  • [test-hive1.2] -使用Spark的Hive 1.2配置文件进行测试的信号
  • [test-hive2.3] -使用Spark的Hive 2.3配置文件进行测试的信号

Binary compatibility

为了确保二进制兼容性,Spark使用MiMa .

Ensuring binary compatibility

处理问题时,最好在打开拉取请求之前检查您的更改是否不会引入二进制不兼容性.

您可以通过运行以下命令来这样做:

$ dev/mima

MiMa报告的二进制不兼容可能类似于以下内容:

[error] method this(org.apache.spark.sql.Dataset)Unit in class org.apache.spark.SomeClass does not have a correspondent in current version
[error] filter with: ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.spark.SomeClass.this")

如果您无论如何打开包含二进制不兼容的请求请求,Jenkins都会通过测试构建失败并通过以下消息提醒您:

Test build #xx has finished for PR yy at commit ffffff.

  This patch fails MiMa tests.
  This patch merges cleanly.
  This patch adds no public classes.

Solving a binary incompatibility

如果您认为自己的二进制不兼容是合理的,或者MiMa报告了误报(例如,所报告的二进制不兼容是关于非面向用户的API),则可以通过在project / MimaExcludes.scala中添加包含建议内容的排除项来过滤掉它们通过MiMa报告以及包含您正在处理的问题的JIRA号及其标题的评论.

对于上述问题,我们可以添加以下内容:

// [SPARK-zz][CORE] Fix an issue
ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.spark.SomeClass.this")

否则,您将必须解决那些不兼容问题,然后再打开或更新您的请求请求. 通常,由MiMa报告的问题是不言自明的,并且围绕缺少的成员(方法或字段)而发生,您必须添加这些成员才能保持二进制兼容性.

Checking Out Pull Requests

Git提供了一种将远程请求请求提取到您自己的本地存储库中的机制. 当在本地检查代码或测试补丁时,这很有用. 如果尚未克隆Spark Git存储库,请使用以下命令:

$ git clone https://github.com/apache/spark.git
$ cd spark

要启用此功能,您需要配置git远程存储库以获取拉取请求数据. 为此,请修改Spark目录中的.git/config文件. 如果您使用其他名称,则该遥控器可能不会被命名为" origin":

[remote "origin"]
  url = git@github.com:apache/spark.git
  fetch = +refs/heads/*:refs/remotes/origin/*
  fetch = +refs/pull/*/head:refs/remotes/origin/pr/*   # Add this line

完成此操作后,您可以获取远程请求请求

# Fetch remote pull requests
$ git fetch origin
# Checkout a remote pull request
$ git checkout origin/pr/112
# Create a local branch from a remote pull request
$ git checkout origin/pr/112 -b new-branch

Generating Dependency Graphs

$ # sbt
$ build/sbt dependency-tree
 
$ # Maven
$ build/mvn -DskipTests install
$ build/mvn dependency:tree

Organizing Imports

您可以使用Aaron Davidson的IntelliJ Imports Organizer来帮助您组织代码中的导入. 可以配置它以匹配样式指南中的导入顺序.

Formatting Code

要格式化Scala代码,请在提交PR之前运行以下命令:

$ ./dev/scalafmt

默认情况下,此脚本将格式化与git master不同的文件. 有关更多信息,请参阅scalafmt文档 ,但使用现有脚本而不是scalafmt的本地安装版本.

IDE Setup

IntelliJ

尽管许多Spark开发人员在命令行上使用SBT或Maven,但我们使用的最常见的IDE是IntelliJ IDEA. 您可以免费获得社区版(Apache提交者可以获得免费的IntelliJ Ultimate Edition许可证),并可以从Preferences > Plugins安装JetBrains Scala插件.

要为IntelliJ创建Spark项目:

  • 下载IntelliJ并安装IntelliJ的Scala插件 .
  • 转到File -> Import Project ,找到spark源目录,然后选择" Maven项目".
  • 在导入向导中,可以将设置保留为默认设置. 但是,启用"自动导入Maven项目"通常很有用,因为对项目结构的更改将自动更新IntelliJ项目.
  • 如《 Building Spark》中所述 ,某些构建配置要求启用特定的配置文件. 可以在"导入"向导的"配置文件"屏幕上启用与上面的-P[profile name]启用的配置文件相同的配置文件. 例如,如果为支持YARN的Hadoop 2.7开发,请启用profile yarnhadoop-2.7 . 稍后可以通过从"视图"菜单访问" Maven项目"工具窗口并展开"配置文件"部分来更改这些选择.

其他提示:

  • 第一次编译项目时," Rebuild Project"可能会失败,因为不会自动生成生成源文件. 尝试单击" Maven项目"工具窗口中的"为所有项目生成源并更新文件夹"按钮,以手动生成这些源.
  • 与IntelliJ捆绑在一起的Maven版本可能不足以支持Spark. 如果发生这种情况,"为所有项目生成源和更新文件夹"操作可能会静默失败. 请记住要重置项目的Maven主目录( Preference -> Build, Execution, Deployment -> Maven -> Maven home directory ),以指向较新的Maven安装. 您也可以先使用build/mvn脚本来构建Spark. 如果脚本找不到足够新的Maven安装,它将下载Maven的最新版本并将其安装到文件夹build/apache-maven-<version>/ .
  • 一些模块具有基于Maven概要文件的可插入源目录(即支持Scala 2.11和2.10或允许针对不同版本的Hive进行交叉构建). 在某些情况下,IntelliJ无法正确检测到使用maven-build-plugin添加源目录的情况. 在这些情况下,您可能需要显式添加源位置以编译整个项目. 如果是这样,请打开"项目设置",然后选择"模块". 根据您选择的Maven配置文件,您可能需要将源文件夹添加到以下模块:
    • spark-hive:添加v0.13.1 / src / main / scala
    • spark-streaming-flume-sink:添加target \ scala-2.11 \ src_managed \ main \ compiled_avro
    • spark-catalyst:添加target \ scala-2.11 \ src_managed \ main
  • 编译可能会失败,并显示诸如" scalac:错误的选项:-P:/home/jakub/.m2/repository/org/scalamacros/paradise_2.10.4/2.0.1/paradise_2.10.4-2.0.1.jar"之类的错误. 如果是这样,请转到"首选项">"构建,执行,部署">" Scala编译器",然后清除"其他编译器选项"字段. 这样,它将起作用,尽管在重新导入项目时该选项将返回. 如果尝试使用准引用(例如sql)构建任何项目,则需要将该jar设为编译器插件(仅在"其他编译器选项"下方). 否则,您将看到类似以下的错误:
     /Users/irashid/github/spark/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/codegen/CodeGenerator.scala Error:(147, 9) value q is not a member of StringContext Note: implicit class Evaluate2 is not applicable here because it comes after the application point and it lacks an explicit result type q""" ^ 

Debug Spark Remotely

本部分将向您展示如何使用IntelliJ远程调试Spark.

Set up Remote Debug Configuration

遵循打开默认的远程配置模板:

通常,默认值应足以使用. and select the right JDK version to generate proper . 确保选择" 将远程JVM作为 侦听",并选择正确的JDK版本生成正确的 .

一旦完成配置并保存. to start remote debug process and wait for SBT console to connect: 您可以按照开始远程调试过程,并等待SBT控制台连接:

Trigger the remote debugging

通常,有两个步骤:

  1. 使用在上一步中生成的的设置JVM选项.
  2. 启动Spark执行(SBT测试,pyspark测试,spark-shell等)

以下是如何使用SBT单元测试触发远程调试的示例.

Enter in SBT console

./build/sbt

切换到目标测试所在的项目,例如:

sbt > project core

复制粘贴的

sbt > set javaOptions in Test += "-agentlib:jdwp=transport=dt_socket,server=n,suspend=n,address=localhost:5005"

使用IntelliJ设置断点,并使用SBT运行测试,例如:

sbt > testOnly *SparkContextSuite -- -t "Only one SparkContext may be active at a time"

当您在IntelliJ控制台中看到"已连接到目标VM,地址:'localhost:5005',传输:'socket'"时,它应该已成功连接到IntelliJ. 然后,您可以照常在IntelliJ中启动调试.

要退出远程调试模式(这样就不必继续启动远程调试器),请在项目中时在SBT控制台中键入" session clear".

Eclipse

Eclipse可用于开发和测试Spark. 已知以下配置有效:

最简单的方法是从Scala IDE下载页面下载Scala IDE捆绑包. 它预装了ScalaTest. 或者,使用Scala IDE更新站点或Eclipse Marketplace.

SBT可以创建Eclipse .project.classpath文件. 要为每个Spark子项目创建这些文件,请使用以下命令:

sbt/sbt eclipse

要导入特定项目,例如spark-core,请选择File | Import | Existing Projects File | Import | Existing Projects File | Import | Existing Projects进入工作区. 不要选择"将项目复制到工作区".

如果要在Scala 2.10上进行开发,则需要为用于编译Spark的确切Scala版本配置Scala安装. 由于Scala IDE捆绑了最新版本(此时为2.10.5和2.11.8),因此您需要通过指向Scala 2.10.5发行版的lib/目录在Eclipse Preferences -> Scala -> Installations添加一个. 完成后,选择所有Spark项目,然后右键单击,选择Scala -> Set Scala Installation并指向2.10.5安装. 这应该清除所有有关无效的交叉编译库的错误. 干净的构建现在应该可以成功.

ScalaTest可以通过右键单击源文件并选择Run As | Scala Test来执行单元测试Run As | Scala Test Run As | Scala Test .

如果发生Java内存错误,则可能有必要增加Eclipse安装目录中eclipse.ini中的设置. 根据需要增加以下设置:

--launcher.XXMaxPermSize
256M

Nightly Builds

Spark publishes SNAPSHOT releases of its Maven artifacts for both master and maintenance branches on a nightly basis. To link to a SNAPSHOT you need to add the ASF snapshot repository to your build. Note that SNAPSHOT artifacts are ephemeral and may change or be removed. To use these you must add the ASF snapshot repository at <a href=”https://repository.apache.org/snapshots/.

groupId: org.apache.spark
artifactId: spark-core_2.12
version: 3.0.0-SNAPSHOT

Profiling Spark Applications Using YourKit

以下是有关使用YourKit Java Profiler分析Spark应用程序的说明.

On Spark EC2 images

  • 登录到主节点后,从YourKit下载页面下载适用于Linux的YourKit Java Profiler. 该文件很大(〜100 MB),YourKit下载站点的速度有些慢,因此您可以考虑对该文件进行镜像或将其包含在自定义AMI中.
  • 将此文件解压缩到某处(在本例中为/root ): unzip YourKit-JavaProfiler-2017.02-b66.zip
  • 使用copy-dir将扩展的YourKit文件复制到每个节点: ~/spark-ec2/copy-dir /root/YourKit-JavaProfiler-2017.02
  • 通过编辑~/spark/conf/spark-env.sh并添加以下行,将Spark JVM配置为使用YourKit分析代理
     SPARK_DAEMON_JAVA_OPTS+=" -agentpath:/root/YourKit-JavaProfiler-2017.02/bin/linux-x86-64/libyjpagent.so=sampling" export SPARK_DAEMON_JAVA_OPTS SPARK_EXECUTOR_OPTS+=" -agentpath:/root/YourKit-JavaProfiler-2017.02/bin/linux-x86-64/libyjpagent.so=sampling" export SPARK_EXECUTOR_OPTS 
  • 将更新的配置复制到每个节点: ~/spark-ec2/copy-dir ~/spark/conf/spark-env.sh
  • 重新启动Spark集群: ~/spark/bin/stop-all.sh~/spark/bin/start-all.sh
  • 默认情况下,YourKit探查器代理使用端口10001-10010 . 要将YourKit桌面应用程序连接到远程事件探查器代理,您必须在集群的EC2安全组中打开这些端口. 为此,请登录AWS管理控制台. 转到EC2部分,然后从页面左侧的" Network & Security部分中选择" Security Groups . 查找与您的群集相对应的安全组; 如果启动了名为test_cluster的集群,则将需要修改test_cluster-slavestest_cluster-master安全组的设置. 对于每个组,从列表中选择它,单击" Inbound选项卡,然后创建一个新的" Custom TCP Rule打开端口范围10001-10010 . 最后,点击Apply Rule Changes . 确保对两个安全组都执行此操作. 注意:默认情况下, spark-ec2重用安全组:如果停止该集群并启动另一个具有相同名称的集群,则安全组设置将被重用.
  • 在您的桌面上启动YourKit分析器.
  • 从欢迎屏幕中选择"连接到远程应用程序…",然后输入您的Spark主计算机或工作计算机的地址,例如ec2--.compute-1.amazonaws.com
  • YourKit现在应该已连接到远程配置代理. 概要分析信息可能需要一些时间.

请参阅完整的YourKit文档以获取探查器代理启动选项的完整列表.

In Spark unit tests

通过SBT运行Spark测试时,将javaOptions in Test += "-agentpath:/path/to/yjp"中的SparkBuild.scala添加到SparkBuild.scala ,以在启用YourKit Profiler代理的情况下启动测试.
YourKit文档中列出了探查器代理的特定于平台的路径.

by  ICOPY.SITE