2012-06-13 174 views
15

我们的Django项目变得越来越庞大。我们有数百个应用程序,并使用大量的第三方Python包,其中很多需要C编译。当我们需要为主要版本创建新的虚拟环境时,我们的部署需要很长时间。有了这个说法,我希望能够加快速度,从Pip开始。有谁知道Pip的一个分支将并行安装软件包吗?并行Pip安装

步骤我已经采取了迄今:

  • 我寻找那些只是做这个收效甚微的一个项目。我确实发现了这个Github Gist:https://gist.github.com/1971720,但结果几乎与我们单线程的朋友完全一样。

  • 然后我在Github上找到了Pip项目,并开始查看fork的网络以查看是否可以找到任何提到正在执行的操作。那里很混乱。如果必须的话,我会分叉它并尝试自己并行化,我只是想避免花时间这样做。

  • 我在ep.io上看到了一个关于ep.io的演讲,解释了他们的部署内容,他们提到并行化pip,发布.so文件,而不是编译C和镜像Pypi,但他们没有涉及他们如何做或他们用了什么。

+0

使用虚拟机作为部署的单元,让一切都变成OS(Debian的)包是我们做什么。然后,您可以运行自己的存储库,并顺利进行增量升级并完成安装。预先构建OS包是确保您具有可重复安装的好方法,您可以使它们依赖于非python的东西,如apache或nginx。 –

+0

@ NickCraig-Wood虽然这是一个好主意,但我们人手不足,没有时间将所有的python包转换成我们用于.debs的版本。我们已经在KVM上运行了所有的东西。我们只需要尽快部署。 – Kyle

+0

这是一个古老的问题,但现在你可以建立一个pip控制室缓存,大大减少了软件包的安装时间。 –

回答

7

您是否分析了部署过程以查看时间真的到了哪里?令我感到惊讶的是,运行多个并行点子进程并没有加速太多。

如果时间去查询PyPI并找到软件包(特别是当您从Github和其他源下载时),那么设置您自己的PyPI可能会有所帮助。您可以自己主持的PyPI并添加以下到您的requirements.txt文件(docs):

--extra-index-url YOUR_URL_HERE 

或以下,如果你想完全取代了官方的PyPI:

--index-url YOUR_URL_HERE 

这可能会加快下载时间因为现在所有的软件包都在附近的机器上。

大量的时间也进入编译与C代码,如PIL包。如果这成为瓶颈,那么值得考虑在多个进程中编译代码。你甚至可以在你的机器之间共享已编译的二进制文件(但许多东西需要类似,比如操作系统,CPU字长等)

+0

我的第一步是使用z3c.pypimirror镜像Pypi,这有帮助。我认为下一步是使用二进制文件来编译或者并行化。我尽我所能了解了Gist代码中发生的事情。我相信它正在调度子进程,并在稍后运行。我不知道如何确保所有的子进程使用gevent同时运行。 – Kyle

+0

如果你想加快编译速度,我以前在ccache上运气很好。 –

3

如果你有你的构建系统,它会有帮助吗(例如Jenkins )构建并将所有内容安装到特定于构建的虚拟环境目录中?当构建成功时,您可以使虚拟环境可重定位,将其压缩并将生成的选项卡推送到“发布的tarball”存储。在部署时,您需要获取最新的tarball并将其解包到目标主机上,然后应该准备好执行。因此,如果需要2秒钟下载tarball,0.5秒钟将其解包到目标主机上,则您的部署需要2.5秒。

这种方法的优点是所有软件包的安装都在构建时发生,而不是在部署时发生。

注意事项:构建/编译/安装东西到虚拟环境中的构建系统工作者必须使用与目标硬件相同的架构。另外,您的生产箱配置系统需要处理一些Python包可能具有的各种C库依赖关系(例如,PIL需要在编译JPEG相关代码之前安装libjpeg,如果未在目标上安装libjpeg也会中断盒)

它适用于我们。

制作一个虚拟的env重定位:

virtualenv --relocatable /build/output/dir/build-1123423

在这个例子中build-1123423是特定生成的虚拟ENV目录。

6

并行PIP安装

此示例使用xargs大约4倍并行构建过程。您可以使用下面的max-procs来增加并行化因子(保持大约等于核心数)。

如果您尝试加速您正在反复进行的成像过程,它可能会更容易,更低的带宽消耗,直接在结果上成像,而不是每次都做,或使用pip -tvirtualenv构建图像。

下载和并行安装软件包,四在一个时间:

xargs --max-args=1 --max-procs=4 sudo pip install < requires.txt 

注:xargs的具有不同Linux发行版本不同的参数名。检查您的发行版的手册页以了解具体情况。有一种遥远的可能性,这种方法的速度可能会混淆软件包清单(取决于你的发行版)如果多个PIP的安装尝试:用here-doc:

cat << EOF | xargs --max-args=1 --max-procs=4 sudo pip install 
awscli 
bottle 
paste 
boto                   
wheel 
twine                   
markdown 
python-slugify 
python-bcrypt 
arrow 
redis 
psutil 
requests 
requests-aws 
EOF 

警告

同样的事情,内联在同一时间同样的依赖关系,但是如果你一次只做4个,这是不太可能的。它可以很容易地通过pip install --uninstall depname修复。

+1

很酷的黑客,但我讨厌不得不调试一个依赖关系的问题:)你是怎么来的顺序? –

+0

谢谢@ItamarHaber ..我同意 - 这不会很有趣:)它是我通常使用的包文件的一个片段(它在一点上是按字母顺序排列的)。 Spooky与Redis一起工作尤其酷(因为它似乎并不在此列表中)。 –

-1

Jamieson Becker's answer的启发,我修改了一个安装脚本来执行并行点安装,它看起来像和改进。我的bash脚本现在包含这样的代码片段:

requirements=''\ 
'numpy '\ 
'scipy '\ 
'Pillow '\ 
'feedgenerator '\ 
'jinja2 '\ 
'docutils '\ 
'argparse '\ 
'pygments '\ 
'Typogrify '\ 
'Markdown '\ 
'jsonschema '\ 
'pyzmq '\ 
'terminado '\ 
'pandas '\ 
'spyder '\ 
'matplotlib '\ 
'statlab '\ 
'ipython[all]>=3 '\ 
'ipdb '\ 
''tornado>=4' '\ 
'simplepam '\ 
'sqlalchemy '\ 
'requests '\ 
'Flask '\ 
'autopep8 '\ 
'python-dateutil '\ 
'pylibmc '\ 
'newrelic '\ 
'markdown '\ 
'elasticsearch '\ 
"'"'docker-py==1.1.0'"'"' '\ 
"'"'pycurl==7.19.5'"'"' '\ 
"'"'futures==2.2.0'"'"' '\ 
"'"'pytz==2014.7'"'"' ' 

echo requirements=${requirements} 
for i in ${requirements}; do (pip install $i > /tmp/$i.out 2>&1 &); done 

我至少可以手动查找问题。

+0

您应该使用需求文件(例如'pip install -r requirements.txt')。不太重要的是,Bash允许在字符串中换行,所以你不需要关闭字符串并跳过换行符 – Leons

8

基于Jamieson Becker的回答,下面的代码会并行Pip下载,然后快速安装软件包。

首先,我们将软件包并行下载到发行版(“dist”)目录中。这很容易并行且没有冲突。下载之前打印出每个包装名称,这有助于调试。要获得额外帮助,请将-P9更改为-P1,以便按顺序下载。

下载后,下一个命令会告诉Pip安装/更新软件包。文件不下载,它们从快速本地目录中获取。

它与当前版本的PIP 1.7兼容,也与PIP 1.5兼容。

要仅安装一个软件包的子集,请将“cat requirements.txt”语句替换为您的自定义命令,例如, “egrep的-v github上requirement.txt”

cat requirements.txt | xargs -t -n1 -P9 pip install -q --download ./dist 

pip install --no-index --find-links=./dist -r ./requirements.txt 
+2

我喜欢它!这会慢一些(如果你正在编译C扩展,它不会并行实际安装),但是这很好地防止了任何并发写入问题。很酷的想法。 –

+0

不幸的是,这很容易弄乱依赖关系的版本。但是,如果所有库版本都受到限制(使用-c开关),它应该可以正常工作。 – allprog