你的应用代码应该始终在用户空间中运行。也就是说,它不可以在超级用户权限下运行。如果你按照十二要素应用的方法设计你的应用,那么可以在几乎没有任何权限的用户
下运行你的应用。对于没有文件且不属于特权组的用户,常见的名称是 nobody。不管怎
样,实际的建议是为每个应用守护进程创建一个单独的用户。这么做的原因是为了系统安
全。它可以限制恶意用户控制应用进程之后能够造成的损害。在 Linux 中,同一用户的进
程可以互相交互,所以在用户层面将不同的应用分离是很重要的。
使用 HTTP 反向代理
许多符合 WSGI 的 Python web 服务器自身就可以轻松处理 HTTP 流量,无需在其上面
添加任何其他的 Web 服务器。但将它们隐藏在反向代理(例如 Nginx)的后面也很常见,
其原因有很多,如下所示。
● 顶层 Web 服务器(例如 Nginx 和 Apache)通常可以更好地处理 TLS/SSL 终止。然
后 Python 应用可以只使用简单的 HTTP 协议(而不是 HTTPS),从而将安全通信
信道的复杂性和配置都留给反向代理。
● 非特权用户不能绑定较小的端口(在 0-1000 的范围内),但 HTTP 协议应该在
80 端口为用户服务,而 HTTPS 协议应该在 443 端口服务。为了实现这一点,
你必须用超级用户权限运行进程。通常来说,更安全的做法是让你的应用在较
大的端口或 Unix 域套接字上服务,并且用它作为由权限更高的用户运行的反向
代理的上游。
● 通常来说,Nginx 可以比 Python 代码更高效地提供静态资源(图像、JS、CSS 和
其他媒体)。如果你将 Nginx 配置为反向代理,那么只需要添加很少几行配置就可
以通过它来提供静态文件。
● 如果单一主机需要服务于来自不同域的多个应用,那么 Apache 或 Nginx 是不可或
缺的,用于为同一端口所服务的不同域创建虚拟主机。
● 反向代理可以通过添加额外的缓存层来提高性能,或者被配置为简单的负载均
衡器。
有些 Web 服务器建议在代理(例如 Nginx)之后运行。例如,gunicorn 是鲁棒性非
常好的基于 WSGI 的服务器,如果客户端速度也很快的话,它可以给出非常好的性能结果。
另一方面,它不能很好地处理较慢的客户端,所以很容易受到基于较慢客户端连接的拒绝
服务攻击。利用能够缓冲较慢客户端的代理服务器是解决这一问题的最佳方法。
优雅地重新加载进程
十二要素应用方法的第 9 条规则讨论的是进程易处理性(disposability),你应该通过快
速的启动时间和优雅终止将鲁棒性最大化。虽然快速的启动时间完全是不言自明的,但优雅终止需要一些额外的讨论。
对于 Web 应用而言,如果你以不优雅的方式终止服务器进程,那么它会立即退出,没
有时间来处理请求和对已连接客户端的响应回复。在最佳情况下,如果你使用了某种反向
代理,那么代理可能会向已连接的客户端回复某个通用的错误响应(例如“502 Bad
Gateway”),虽然这并不是通知用户你已经重启应用并部署了新版本的正确方法。
根据十二要素应用方法,Web 服务进程应该能够在接收到 Unix 的 SIGTERM 信号(例
如 kill -TERM )时优雅地退出。也就是说,服务器应该停止接受新的
连接,处理完所有等待请求,如果没有更多事情可做的话则退出并给出退出码。
显然,如果所有服务进程都退出或启动关闭程序,那么你再也不能处理新的请求。这
意味着你的服务将经历一次中断,所以你还需要执行一个额外的步骤——在旧的工作进程
优雅退出的同时启动能够接受新连接的新工作进程(workers)。各种符合 WSGI 的 Python
web 服务器实现都允许在没有任何停机的情况下优雅地重新加载服务。其中最流行的是
Gunicorn 和 uWSGI。
● 接收到 SIGHUP 信号(kill -HUP )后,Gunicorn 的主进程将
(使用新的代码和配置)启动新的工作进程并尝试让旧的工作进程优雅地终止。
● uWSGI 至少有 3 种独立的方案来进行优雅地重新加载。每种方案都过于复杂,很
难简要解释,但官方文档提供了所有可能选项的完整信息。
在今天看来,优雅地重新加载是部署 Web 应用的一项标准。Gunicorn 似乎具有最容易
使用的方法,但留给你的灵活性也最小。与之相反,在 uWSGI 中优雅地重新加载可以更好
地控制重新加载,但在自动化和设置方面需要更多的精力。另外,你在自动化部署过程中
如何处理优雅地重新加载也受到你所使用的管理工具及其配置方式的影响。例如在
Gunicorn 中,优雅地重新加载非常简单,如下所示:
kill -HUP
但如果你想通过分离每个版本的虚拟环境来正确地隔离项目发行版,并使用符号链接
来配置进程管理(正如前面 fabfile 例子所示),那么你很快将会注意到它不能按预期运
行。对于更复杂的部署,仍然没有开箱即用的可行的解决方案。你总是需要一点黑客技术,
有时还需要对底层系统实现细节有相当多的了解。
Python 高手编程系列二百五十六:应该在用户空间运行应用代码
最新推荐文章于 2024-09-07 22:54:47 发布