如何在调试模式下调用pyspark?

Tob*_*eup 19 python hadoop intellij-idea python-2.7 apache-spark

我使用Apache Spark 1.4设置了IntelliJ IDEA.

我希望能够将调试点添加到我的Spark Python脚本中,以便我可以轻松地调试它们.

我目前正在运行这一点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()
Run Code Online (Sandbox Code Playgroud)

spark-submit最终调用myFirstSparkScript.py,调试模式不从事并正常执行.遗憾的是,编辑Apache Spark源代码并运行自定义副本是不可接受的解决方案.

有谁知道是否有可能在调试模式下使用spark-submit调用Apache Spark脚本?如果是这样,怎么样?

zer*_*323 25

据我了解你的意图,你想要的东西在Spark架构下是不可能直接实现的.即使没有subprocess调用,您可以直接在驱动程序上访问程序的唯一部分是SparkContext.从其他部分开始,您可以通过不同的通信层实现隔离,包括至少一个(在本地模式下)JVM实例.为了说明这一点,我们可以使用PySpark Internals文档中的图表.

在此输入图像描述

左侧框中的部分是可在本地访问的部分,可用于附加调试器.由于它最受限于JVM调用,因此除非您实际修改PySpark本身,否则实际上没有任何内容可供您使用.

右边的内容是远程发生的,从用户的角度来看,你使用的集群管理器几乎就是一个黑盒子.此外,在很多情况下,右边的Python代码只是调用JVM API.

这是不好的部分.好的部分是大多数时候不需要远程调试.除了TaskContext可以轻松模拟的访问对象之外,代码的每个部分都应该可以在本地轻松运行/测试,而无需使用Spark实例.

传递给操作/转换的函数采用标准和可预测的Python对象,并且还希望返回标准Python对象.同样重要的是这些副作用应该是免费的

因此,在一天结束时,您需要部分程序 - 一个可以交互式访问的薄层,并且仅基于输入/输出和"计算核心"进行测试,这不需要Spark进行测试/调试.

其他选择

那就是说你在这里没有完全没有选择.

本地模式

(被动地将调试器连接到正在运行的解释器)

普通的GDB和PySpark调试器都可以附加到正在运行的进程中.一旦启动了PySpark守护程序和/或工作进程,就可以执行此操作.在本地模式下,您可以通过执行虚拟操作来强制它,例如:

sc.parallelize([], n).count()
Run Code Online (Sandbox Code Playgroud)

其中n是本地模式(local[n])中可用的多个"核心" .在类Unix系统上逐步执行示例过程:

  • 启动PySpark shell:

    $SPARK_HOME/bin/pyspark 
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用pgrep检查有没有守护进程在运行:

    ?  spark-2.1.0-bin-hadoop2.7$ pgrep -f pyspark.daemon
    ?  spark-2.1.0-bin-hadoop2.7$
    
    Run Code Online (Sandbox Code Playgroud)
  • 同样的事情可以在PyCharm中通过以下方式确定:

    alt+ shift+ a并选择Attach to Local Process:

    在此输入图像描述

    运行 - > 附加到本地进程.

    此时你应该只看到PySpark shell(可能还有一些不相关的进程).

    在此输入图像描述

  • 执行虚拟动作:

    sc.parallelize([],1).count()

  • 现在你应该看到两者daemonworker(这里只有一个):

    ?  spark-2.1.0-bin-hadoop2.7$ pgrep -f pyspark.daemon
    13990
    14046
    ?  spark-2.1.0-bin-hadoop2.7$
    
    Run Code Online (Sandbox Code Playgroud)

    在此输入图像描述

    较低pid的进程是守护进程,具有较高pid权限的进程是(可能)短暂的工作程序.

  • 此时,您可以将调试器附加到感兴趣的进程:

这种方法的最大缺点是你在适当的时候找到了正确的翻译.

分布式模式

(使用连接到调试器服务器的活动组件)

与PyCharm

PyCharm提供了Python调试服务器,可以与PySpark作业一起使用.

首先,您应该为远程调试器添加配置:

  • alt+ shift+ a并选择编辑配置运行 - > 编辑配置.
  • 单击Add new configuration(green plus)并选择Python Remote Debug.
  • 根据您自己的配置配置主机和端口(确保从远程计算机到达该端口)

    在此输入图像描述

  • 启动调试服务器:

    shift+F9

    您应该看到调试器控制台:

    在此输入图像描述

  • 确保pyddev可以在工作节点上访问它,方法是安装它或分发egg文件.

  • pydevd 使用必须包含在您的代码中的活动组件:

    import pydevd
    pydevd.settrace(<host name>, port=<port number>)
    
    Run Code Online (Sandbox Code Playgroud)

    棘手的部分是找到合适的位置来包含它,除非你调试批处理操作(比如传递给mapPartitions它的函数),它可能需要修补PySpark源本身,例如pyspark.daemon.workerRDD类似的方法RDD.mapPartitions.假设我们对调试工作者行为感兴趣.可能的补丁可能如下所示:

    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)
    
    Run Code Online (Sandbox Code Playgroud)

    如果您决定修补Spark源,请确保使用位于其中的已修补源而非打包版本$SPARK_HOME/python/lib.

  • 执行PySpark代码.回到调试器控制台,玩得开心:

    在此输入图像描述

其他工具

有许多工具,包括python-pyrasite manhole,或者可以通过一些努力与PySpark一起使用.

注意:

当然,您可以在本地模式下使用"远程"(活动)方法,在某种程度上使用分布式模式的"本地"方法(您可以连接到工作节点并按照与本地模式相同的步骤).