Jupyter Notebook PySpark 内核引用主机站点包中降低的 pip 版本

Jupyter Notebook PySpark Kernel referencing lowered pip version from host machine site-packages

我正在使用 Jupyter Notebook,它由名为 EMR Studio 的 AWS 托管服务提供。我对这些笔记本如何工作的理解是,它们托管在我作为我的 EMR 集群的一部分提供的 EC2 实例上。特别是使用任务节点的 PySpark 内核。

当前,当我 运行 命令 sc.list_packages() 时,我看到 pip 的版本是 9.0.1,而如果我通过 SSH 连接到主节点并且 运行 pip list 我看到 pip 的版本是 20.2.2。由于 Notebook 中降低的 pip 版本,我在执行命令 sc.install_pypi_package() 时遇到问题 运行。

在笔记本单元中,如果我 运行 import pip 那么 pip 我看到模块位于

<module 'pip' from '/mnt1/yarn/usercache/<LIVY_IMPERSONATION_ROLE>/appcache/application_1652110228490_0001/container_1652110228490_0001_01_000001/tmp/1652113783466-0/lib/python3.7/site-packages/pip/__init__.py'> 

我假设这很可能是在某种 virtualenv 中 运行ning 作为任务节点上的应用程序?我不确定这一点,如果有的话,我也没有具体的证据证明 virtualenv 是如何配置的。

如果我 运行 sc.uninstall_package('pip') 然后 sc.list_packages() 我看到 pip 的版本是 20.2.2,这是我最初想要开始的。模块路径和前面说的一样

如何在 virtualenv 中获取 pip 20.2.2 而不是 pip 9.0.1?

如果我导入像 numpy 这样的包,我会看到该模块位于与 pip 所在的不同位置。有什么原因吗?

<module 'numpy' from '/usr/local/lib64/python3.7/site-packages/numpy/__init__.py'>

至于 pip 9.0.1,我目前唯一能找到的参考资料是 /lib/python2.7/site-packages/virtualenv_support/pip-9.0.1-py2.py3-none-any.whl。在此之外的一个目录中,我看到一个名为 virtualenv-15.1.0-py2.7.egg-info 的文件,如果我 cat 该文件表明它升级到 pip 9.0.1。我试图删除 pip 9.0.1 wheel 文件并将其替换为 pip 20.2.2 wheel,这导致 PySpark 内核无法正确配置。还有一个 virtualenv.py 文件确实引用了 __version__ = "15.1.0".

我找到了在 PySpark 使用的 virtualenv 中更新 pip、setuptools 和 wheel 的解决方案。

我最初必须确定 pip 9 的来源。通过 SSH 连接到我的 EMR 主节点,我将目录更改为根 cd /,然后 运行 命令 sudo find . -name "pip*" 递归搜索 pip 文件可能位于的位置。

在我的场景中有一个 pip 9 轮位于:

./usr/lib/python2.7/site-packages/virtualenv_support/pip-9.0.1-py2.py3-none-any.whl

通过在 /usr/lib/python2.7/site-packages 中多搜索一下,有一个 virtualenv.py 被调用来创建 virtualenv,下面会做更多解释。

在 PySpark notebook 会话中使用 %%info 显示 virtualenv 是从此文件路径创建的(感谢 Parag):

'spark.pyspark.virtualenv.bin.path': '/usr/bin/virtualenv'

运行 cat /usr/bin/virtualenv 显示正在从以下命令调用 virtualenv:

#!/usr/bin/python
import virtualenv
virtualenv.main()

/usr/bin中python的这个版本是python2.7。在终端我 运行 按顺序执行以下命令:

  1. /usr/bin/python
  2. import virtualenv
  3. virtualenv

这输出:

<module 'virtualenv' from '/usr/lib/python2.7/site-packages/virtualenv.py'>

我有时看到这里使用了 virtualenv.pyc 文件,它位于 /usr/lib/python2.7/site-packages/,但我看到其他用户建议可以删除 .pyc 文件。

在 EMR 主节点上,我 运行 命令 /usr/bin/virtualenv 显示了一些可以使用的标志。首先我使用了 /usr/bin/virtualenv --verbose ./myVE 这表明 pip 9.0.1 被打包到我创建的 virtualenv 中。如果我 运行 /usr/bin/virtualenv --verbose --download ./myVE2 这会显示更新版本的 pip、setuptools 和 wheel 正在从 Artifactory(我们的私有 PyPi 镜像)下载到 virtualenv 中。我们使用 /etc/pip.conf 来设置 index-url 和可信主机,以便使用 Artifactory 而不是 PyPi。

在这一点上,似乎 EMR 集群的 virtualenv.py 文件默认不会从 Artifactory/PyPi 下载更新的 wheel,而是使用位于 /usr/lib/python2.7/site-packages/virtualenv_support/*.whl[=45 的 wheel 文件=]

运行 cat /usr/lib/python2.7/site-packages/virtualenv.py 显示此版本的 virtualenv 是 15.1.0 非常过时(2016 版)。

进一步阅读virtualenv.py发现main()函数有如下代码块:

parser.add_option(
        "--download",
        dest="download",
        action="store_true",
        help="Download preinstalled packages from PyPI.",
    )

我将我的 EMR 主机上的这个 virtualenv.py 文件与 PyPi (https://pypi.org/project/virtualenv/15.1.0/) 的 virtualenv==15.1.0 官方版本进行了比较。我下载了 tar.gz 文件并在我的本地机器上解压。解压后的文件夹中有一个virtualenv.py文件。使用官方 virtualenv.py 文件的 diff 的内容与 EMR 集群的 virtualenv.py 文件进行比较时,只有几行不相同。主要区别在于上面代码块中的 parser.add_option 在官方 virtualenv.py 文件中具有 default=True,。 EMR集群的virtualenv.py文件没有这个。

parser.add_option(
        "--download",
        dest="download",
        action="store_true",
        default=True,
        help="Download preinstalled packages from PyPI.",
    )

我从这里所做的是复制 EMR 集群的 virtualenv.py 并更新代码行以设置 default=True,。然后,我将这个更新后的 virtualenv.py 作为 EMR bootstrap 脚本的一部分,以便在所有节点类型 (master/core/task) 上更新此文件。

bootstrap 脚本执行以下操作:

  1. sudo rm /usr/lib/python2.7/site-packages/virtualenv.pyc
  2. sudo rm /usr/lib/python2.7/site-packages/virtualenv.py
  3. sudo aws s3 cp <UPDATED_VIRTUALENV_S3_PATH> /usr/lib/python2.7/site-packages/

确保从 S3 复制的文件只是调用 virtualenv.py,以防因文件名不一致而导致任何问题。

现在,当我启动 PySpark 内核时,spark.pyspark.virtualenv.bin.path 调用更新后的 virtualenv.py 文件,我能够确认 pip 的版本号更高(20+),这就是我一直在寻找实现。