我使用Apache Spark 1.4设置了IntelliJ IDEA。
我希望能够将调试点添加到我的Spark Python脚本中,以便我可以轻松地调试它们。
我目前正在运行这一点来初始化spark过程
proc = subprocess.Popen([SPARK_SUBMIT_PATH, scriptFile, inputFile], shell=SHELL_OUTPUT, stdout=subprocess.PIPE)
if VERBOSE:
print proc.stdout.read()
print proc.stderr.read()
当spark-submit
最终调用myFirstSparkScript.py
时,调试模式未启用,并且正常执行。遗憾的是,编辑Apache Spark源代码并运行自定义副本是不可接受的解决方案。
有谁知道是否可以在调试模式下使用spark-submit调用Apache Spark脚本?如果是这样,怎么样?
答案 0 :(得分:24)
据我了解你的意图,你想要的东西在Spark架构下是不可能直接实现的。即使没有subprocess
调用,您可以直接在驱动程序上访问程序的唯一部分是SparkContext
。从其他部分开始,您可以通过不同的通信层有效隔离,包括至少一个(在本地模式下)JVM实例。为了说明这一点,我们可以使用PySpark Internals documentation中的图表。
左侧框中的内容是可在本地访问的部分,可用于附加调试器。由于它最受限于JVM调用,因此除非您实际修改PySpark本身,否则实际上没有任何内容可供您使用。
右边的内容是远程发生的,从用户的角度来看,你使用的集群管理器几乎就是一个黑盒子。此外,在很多情况下,右边的Python代码只是调用JVM API。
这是不好的部分。好的部分是大多数时候不需要远程调试。除了可以轻松模拟的TaskContext
访问对象之外,代码的每个部分都应该可以在本地轻松运行/测试,而无需使用Spark实例。
传递给操作/转换的函数采用标准和可预测的Python对象,并且还希望返回标准Python对象。同样重要的是这些应该是无副作用
因此,在一天结束时,你需要部分程序 - 一个薄层,可以交互式访问,并完全基于输入/输出和"计算核心"哪个不需要Spark进行测试/调试。
据说你在这里并没有完全没有选择。
(被动地将调试器附加到正在运行的解释器)
普通GDB和PySpark调试器都可以附加到正在运行的进程。一旦启动了PySpark守护程序和/或工作进程,就可以执行此操作。在本地模式下,您可以通过执行虚拟操作来强制它,例如:
sc.parallelize([], n).count()
其中n
是多个"核心"在本地模式下可用(local[n]
)。在类Unix系统上逐步执行示例程序:
启动PySpark shell:
$SPARK_HOME/bin/pyspark
使用pgrep
检查没有运行守护进程:
➜ spark-2.1.0-bin-hadoop2.7$ pgrep -f pyspark.daemon
➜ spark-2.1.0-bin-hadoop2.7$
同样的事情可以通过以下方式在PyCharm中确定:
alt + shift + a 并选择附加到本地流程:
或运行 - > 附加到本地流程。
此时你应该只看到PySpark shell(可能还有一些不相关的进程)。
执行虚拟动作:
sc.parallelize([],1).count()
现在您应该看到daemon
和worker
(此处只有一个):
➜ spark-2.1.0-bin-hadoop2.7$ pgrep -f pyspark.daemon
13990
14046
➜ spark-2.1.0-bin-hadoop2.7$
和
较低pid
的进程是守护进程,pid
较高的进程是(可能)临时工作者。
此时,您可以将调试程序附加到感兴趣的进程:
通过调用简单的GDB:
gdb python <pid of running process>
这种方法的最大缺点是你在适当的时候找到了正确的翻译。
(使用连接到调试器服务器的活动组件)
与PyCharmPyCharm提供Python Debug Server,可以与PySpark作业一起使用。
首先,您应该为远程调试器添加配置:
根据您自己的配置配置主机和端口(确保从远程计算机到达该端口)
启动调试服务器:
移 + F9
你应该看到调试器控制台:
确保工作节点上可以访问pyddev
,方法是安装它或分发egg
文件。
pydevd
使用必须包含在您的代码中的活动组件:
import pydevd
pydevd.settrace(<host name>, port=<port number>)
棘手的部分是找到包含它的正确位置,除非你调试批处理操作(比如传递给mapPartitions
的函数),否则可能需要修补PySpark源本身,例如pyspark.daemon.worker
或{{ 1}}像RDD
这样的方法。让我们说我们对调试工作人员的行为很感兴趣。可能的补丁可能如下所示:
RDD.mapPartitions
如果您决定修补Spark源代码,请务必使用位于diff --git a/python/pyspark/daemon.py b/python/pyspark/daemon.py
index 7f06d4288c..6cff353795 100644
--- a/python/pyspark/daemon.py
+++ b/python/pyspark/daemon.py
@@ -44,6 +44,9 @@ def worker(sock):
"""
Called by a worker process after the fork().
"""
+ import pydevd
+ pydevd.settrace('foobar', port=9999, stdoutToServer=True, stderrToServer=True)
+
signal.signal(SIGHUP, SIG_DFL)
signal.signal(SIGCHLD, SIG_DFL)
signal.signal(SIGTERM, SIG_DFL)
的已修补源代码未打包版本。
执行PySpark代码。回到调试器控制台,玩得开心:
有许多工具,包括python-manhole或pyrasite
,可以通过一些努力与PySpark一起使用。
注意强>:
当然你可以使用&#34; remote&#34;具有本地模式的(主动)方法,并且在某种程度上&#34;本地&#34;具有分布式模式的方法(您可以连接到工作节点并执行与本地模式相同的步骤)。
答案 1 :(得分:0)
查看这个名为 pyspark_xray 的工具,下面是从其文档中提取的高级摘要。
pyspark_xray 是一个诊断工具,采用 Python 库的形式,供 pyspark 开发者在本地调试和排查 PySpark 应用程序,具体来说,它可以本地调试运行在从节点上的 PySpark RDD 或 DataFrame 转换函数。< /p>
开发 pyspark_xray 的目的是创建一个开发框架,使 PySpark 应用程序开发人员能够在本地进行调试和故障排除,并使用与 pyspark 应用程序相同的代码库远程进行生产运行。对于本地调试 Spark 应用代码部分,pyspark_xray 专门提供了本地调试运行在从节点上的 Spark 应用代码的能力,这个能力的缺失是目前 Spark 应用开发者的一个空缺。< /p>
对于开发者来说,在本地对应用程序的每个部分进行分步调试非常重要,以便在开发过程中诊断、排除故障和解决问题。
如果您开发 PySpark 应用程序,您就会知道 PySpark 应用程序代码由两类组成:
虽然主节点上的代码可以由本地调试器访问,但从节点上的代码就像一个黑匣子,调试器无法在本地访问。
网络上很多教程已经介绍了调试运行在主节点上的PySpark代码的步骤,但是当谈到调试运行在从节点上的PySpark代码时,没有找到解决方案,大多数人将这部分代码称为黑盒或不需要调试。
在从节点上运行的 Spark 代码包括但不限于:作为输入参数传递给 RDD transformation functions 的 lambda 函数。
pyspark_xray 库使开发人员能够locally debug(步入)100% 的 Spark 应用程序代码,不仅是在主节点上运行的代码,还包括在从节点上运行的代码,使用 PyCharm 和其他VSCode等流行的IDE。
该库通过使用以下技术实现这些功能:
CONST_BOOL_LOCAL_MODE
来自 pyspark_xray 的 const.py 自动检测本地模式是根据当前操作系统开启还是关闭,并带有值:
在您的 Spark 代码库中,您可以使用相同的代码库在本地调试和远程执行您的 Spark 应用程序。