上一章我们实现了nginx+uWSGI+Flask的应用部署,并且研究了一下uWSGI启动的进程,这一章聊一下uWSGI的一些特性和需要注意的地方
本章概览
- uWSGI与多线程application的关系
- uWSGI启动的应用如何加载虚拟环境中的包
- 永远不要使用root
- 一个释放work的优化方式——卸载
- 如何让uWSGI支持多版本的Python应用。
uWSGI与多线程
如果在启动uWSGI的时候没有设置threads参数,那么uWSGI将不会启动Python的全局解释器锁(GIL),所以uWSGI application中生成的线程将不会运行。这种情况下,可以使用参数来强制uWSGI启用GIL。只需要添加--enable-threads选项(在ini文件中是enable-threads = true)
虚拟环境
如果应用程序使用了虚拟环境中的包,那么uWSGI在启动应用程序的时候可能无法正常引入虚拟环境中的包。同样,这种情况下也可以使用参数来指定所使用的虚拟环境,添加参数:virtualenv = <path>
安全性
永远避免使用root用户启动uWSGI
卸载
uWSGI提供了一个卸载子系统,可以尽快将可能的任务从你的worker卸载,交给一个纯C的线程。比如从文件系统发送一个静态的文件,从网络发送数据给客户端等。卸载子系统非常复杂,但是对用户是透明的。如果想尝试,只需要加一个配置项即可:--offload-threads <n>。这里<n>是生成的线程数(每个CPU对应一个线程是个不错的开始)。
当卸载线程启动,程序会自动匹配可以的优化项进行卸载。
我们在上一章的flaskapp.ini文件中增加这个配置项:offload-threads = 1
[uwsgi]
socket = 127.0.0.1:3031
chdir = /home/zhr/disk1/study/blog_code/uwsgi/p3_uwsgi/
wsgi-file = flaskapp.py
processes = 4
threads = 2
offload-threads = 1
stats = 127.0.0.1:9191
然后运行命令uwsgi --ini flaskapp.ini,可以看到如下log:
可以看到,uWSGi为每个worker启动了一个offload线程。
让uWSGI支持不同的Python版本
uWSGI包含了一个很小的内核和多种多样的插件。插件可以在uWSGI的bin文件运行时动态加载。当我们编译一个为Python应用程序使用的uWSGI bin文件的时候,一系列的Python插件被安装到了这个bin文件中,这造成一个问题,我们无法使用一个uWSGI的bin文件支持多个Python版本的应用程序。
最好的解决方案是我们可以编译一个独立于Python语言的uWSGI内核,然后为每个Python版本编译一系列的插件。然后在运行的过程中选择插件。
可以使用下面的命令编译一个语言无关的uWSGI:
make PROFILE=nolang
然后可以为每个Python版本编译一个包含插件的动态链接库,比如:
PYTHON=python3.4 ./uwsgi --build-plugin "plugins/python python34" PYTHON=python2.7 ./uwsgi --build-plugin "plugins/python python27" PYTHON=python2.6 ./uwsgi --build-plugin "plugins/python python26"
这会生成三个文件:python34_plugin.so,python27_plugin.so,python26_plugin.so。将这些文件拷贝到需要的路径(默认情况下,uWSGI在当前工作路径搜索插件)
现在可以在配置文件的最上面添加插件路径和要选择的插件:
[uwsgi]
plugins-dir = <path_to_your_plugin_directory>
plugin = python26
这样,uWSGI在运行时会加载python26_plugin.so插件。