perl/PSGI 应用快速入门

下面的说明将会引导你安装运行一个基于 perl 的目的在于运行 PSGI apps 的 uWSGI 发行版。

安装带 Perl 支持的 uWSGI

为了构建 uWSGI 你需要一个 c 编译器(gcc 和 clang 都支持)以及 python 二进制文件(它只会用于运行 uwsgiconfig.py 脚本来执行一些比较复杂的步骤)。 为了构建带有 perl 支持的 uWSGI 二进制文件我们也需要 perl 开发版的头文件(在 debian 系发行版上是 libperl-dev 这个包)。

你可以手动构建 uWSGI:

python uwsgiconfig.py --build psgi

这和下面一样:

UWSGI_PROFILE=psgi make

或者使用网络安装:

curl http://uwsgi.it/install | bash -s psgi /tmp/uwsgi

这将会在 /tmp/uwsgi (你可以随便改变成你想要的路径) 目录下创建一个 uWSGI 二进制文件。

使用发行版包需要注意的地方

你的发行版很有可能已经包含了一个 uWSGI 的包集合。这些 uWSGI 包趋向于高度模块化, 所以除了 core 你还需要安装需要的插件。 在你的配置中插件必须被加载。在学习阶段我们强烈建议不要使用发行版的包,简单地跟着文档和教程走就可以了。

一旦你对 “uWSGI 方式” 感到习惯了,你可以为你的部署选择最好的途径。

你的第一个 PSGI 应用

把它以 myapp.pl 文件名保存

my $app = sub {
     my $env = shift;
     return [
             '200',
             [ 'Content-Type' => 'text/html' ],
             [ "<h1>Hello World</h1>" ],
     ];
};

然后以 http 模式运行 uWSGI:

uwsgi --http :8080 --http-modifier1 5 --psgi myapp.pl

(如果 uwsgi 不在你当前的 $PATH 里的话记着替换它)

或者如果你使用了模块化安装(比如你的发行版里的包)

uwsgi --plugins http,psgi --http :8080 --http-modifier1 5 --psgi myapp.pl

注解

当你有一个前段 web 服务器的时候不要使用 -http 选项,使用 –http-socket。继续阅读这个快速入门你就会明白为什么要这么做

‘–http-modifier1 5’ 是什么鬼???

uWSGI 支持多种语言和平台。当服务器收到一个请求时它必须知道“路由”它到哪里去。

每一个 uWSGI 插件都有一个分配的数字(modifier),perl/psgi 的数字是 5。所以 –http-modifier1 5 表示“路由到 psgi 插件”。

虽然 uWSGI 有一个更“友好”的 internal routing system ,但使用 modifier 仍然是最快的方式,所以尽可能地使用他们。

使用一个完整的 web 服务器:nginx

提供的 http 路由器仅仅就是一个路由器(是的,难以置信)。你可以使用它作为负载均衡器或者代理, 但是如果你需要一个完整的 web 服务器(比如为了高性能地提供静态文件访问或者那些 web 服务器更适合的工作), 使用 uwsig http 路由器有风险(记住把 –plugins http,psgi 改成 –plugins psgi 如果你是模块化安装的话), 你应该把你的应用放在 nginx 后面。

为了和 nginx 通信,uWSGI 可以使用多种协议:http,uwsgi,fastcgi,scgi...

性能最高的是 uwsgi。Nginx 提供了开箱即用的 uwsgi 协议支持。

使用 uwsgi socket 运行你的 psgi 应用:

uwsgi --socket 127.0.0.1:3031 --psgi myapp.pl

然后在你的 nginx 配置中加一个 location 节:

location / {
    include uwsgi_params;
    uwsgi_pass 127.0.0.1:3031;
    uwsgi_modifier1 5;
}

重启你的 nginx 服务器,然后它就会启动请求到你的 uWSGI 实例之间的代理。

注意你不需要把你的 uWSGI 配置一个特殊的 modifier,nginx 将会使用 uwsgi_modifier1 5; 指令。

如果你的代理/web 服务器/路由器 使用 HTTP,你需要告诉 uWSGI 使用 http 协议(这与 –http 不同,后者 会自己 spawn 一个代理):

uwsgi --http-socket 127.0.0.1:3031 --http-socket-modifier1 5 --psgi myapp.pl

正如你看到的我们需要指定 modifier1,因为 http 协议不能附带这种信息。

添加并发

你可以通过多进程,多线程或者各种异步模式来给你的应用添加并发。

要 spawn 更多的进程,使用 –processes 选项

uwsgi --socket 127.0.0.1:3031 --psgi myapp.pl --processes 4

要使用更多的线程,使用 –threads

uwsgi --socket 127.0.0.1:3031 --psgi myapp.pl --threads 8

或者两者都用

uwsgi --socket 127.0.0.1:3031 --psgi myapp.pl --threads 8 --processes 4

在 perl 世界中一个非常常见的非堵塞/协程库就是 Coro::AnyEvent 。uWSGi 简单 包含 coroae 插件就可以使用它了。

要编译一个带有 coroae 支持的 uWSGI 二进制文件只需运行:

UWSGI_PROFILE=coroae make

或者

curl http://uwsgi.it/install | bash -s coroae /tmp/uwsgi

你将会得到一个带有 psgicoroae 插件的 uWSGI 二进制文件。

现在用 Coro::AnyEvent 模式来运行你的应用:

uwsgi --socket 127.0.0.1:3031 --psgi myapp.pl --coroae 1000 --processes 4

它会运行 4 个进程,每个进程可以管理 1000 个协程(或者 Coro 微线程)。

增加鲁棒性:主进程

非常推荐的做法是在生成环境中的应用全部都运行主进程。

它会持续地监控你的进程/线程,并且会像 The uWSGI Stats Server 一样将会添加更多有趣的特性。

要使用主进程只需要加上 –master 选项

uwsgi --socket 127.0.0.1:3031 --psgi myapp.pl --processes 4 --master

使用配置文件

uWSGI 提供了好几百个选项。通过命令行去处理它们是愚蠢的,所以尽量使用配置文件。 uWSGI 支持多种标准(xml, .ini, json, yaml...)。从一个标准变成另一个非常简单。 所有你在命令行中可以使用的选项只要去掉 -- 前缀就可以用在配置文件中。

[uwsgi]
socket = 127.0.0.1:3031
psgi = myapp.pl
processes = 4
master = true

或者 xml:

<uwsgi>
  <socket>127.0.0.1:3031</socket>
  <psgi>myapp.pl</psgi>
  <processes>4</processes>
  <master/>
</uwsgi>

要用配置文件来运行 uWSGI,只需要通过参数来指定它就可以了:

uwsgi yourconfig.ini

如果出于某种原因你的配置文件不能以正常的拓展名(.ini, .xml, .yml, .js)结尾, 你可以用下面这种方式来强制 uWSGI 使用指定的解析器:

uwsgi --ini yourconfig.foo
uwsgi --xml yourconfig.foo
uwsgi --yaml yourconfig.foo

等等

你甚至可以使用管道流式配置(使用 - 强制从标准输入读取):

perl myjsonconfig_generator.pl | uwsgi --json -

自动启动 uWSGI

如果你打算写一些 init.d 脚本来启动 uWSGI,坐下来冷静一下,然后检查你的系统是否 真的没有提供更好的(现代化)的方式。

每一个发行版会选择一个启动系统 (Upstart, Systemd...) 除此之外也许多 进程管理工具 (supervisord, god...) 。

uWSGI will integrate very well with all of them (we hope), but if you plan to deploy a big number of apps check the uWSGI Emperor uWSGI 与上面列出的那些工具都集成得很好(我们希望如此),但是如果你想部署大量应用的话,看 看 uWSGI 的 Emperor 。它是每个运维开发的梦想。

安全和可用性

永远 不要使用 root 来运行 uWSGI 实例。你可以用 uid 和 gid 选项来降低权限:

[uwsgi]
socket = 127.0.0.1:3031
uid = foo
gid = bar
chdir = path_toyour_app
psgi = myapp.pl
master = true
processes = 8

web 应用开发一个最常见的问题就是 “stuck requests”(卡住的请求)。你所有的线程/worker 都被卡住(被请求堵塞), 然后你的应用再也不能接受更多的请求。

为了避免这个问题你可以设置一个 harakiri 计时器。它是一个监视器(由主进程管理), 当进程被卡住的时间超过特定的秒数后就销毁这个进程。

[uwsgi]
socket = 127.0.0.1:3031
uid = foo
gid = bar
chdir = path_toyour_app
psgi = myapp.pl
master = true
processes = 8
harakiri = 30

上面的配置会将卡住超过 30 秒的 worker 销毁。慎重选择 harakiri 的值 !!!

另外,从 uWSGI 1.9 起,统计服务器会输出所有的请求变量,所以你可以(实时地)查看你的 实例在干什么(对于每个 worker,线程或者异步 core)。

打开 stats server 很简单:

[uwsgi]
socket = 127.0.0.1:3031
uid = foo
gid = bar
chdir = path_toyour_app
psgi = myapp.pl
master = true
processes = 8
harakiri = 30
stats = 127.0.0.1:5000

只需要把它绑定到一个地址(UNIX domain sockt 或者 TCP)然后(你也可以使用 telnet)连接它,然后就会 返回你的实例的一个 JSON 数据。

uwsgitop 应用(你可以在官方的 github 仓库中找到它)就是一个使用 stats server 的例子,它和 top 这种实时监控的工具类似(彩色的!!!)

Offloading

The uWSGI offloading subsystem 使得你可以在某些模式满足时释放你的 worker,并且把工作委托给一个纯 c 的线程。 这样例子比如有从文件系统传递静态文件,通过网络向客户端传输数据等等。

Offloading 非常复杂,但它的使用对用户来说是透明的。如果你想试试的话加上 --offload-threads <n> 选项, 这里的 <n> 是 spawn 的线程数(以 CPU 数目的线程数启动是一个不错的值)。

当 offload threads 被启用时,所有可以被优化的部分都可以自动被检测到。

那么现在...

有了这些很少的概念你就已经可以进入到生产中了,但是 uWSGI 是一个拥有上百个特性和配置的生态系统。 如果你想成为一个更好的系统管理员,继续阅读完整的文档吧。