gunicorn + nginx:通过套接字或代理服务器?
Posted
技术标签:
【中文标题】gunicorn + nginx:通过套接字或代理服务器?【英文标题】:gunicorn + nginx: Server via socket or proxy? 【发布时间】:2013-11-23 19:48:09 【问题描述】:我见过两种使用 gunicorn 和 nginx 托管 django 应用程序的策略。
一种策略是在网络端口上运行 gunicorn。例如(来自http://goodcode.io/blog/django-nginx-gunicorn/):
location /
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 10;
proxy_read_timeout 10;
proxy_pass http://localhost:8000/;
另一种策略是在启动时将 gunicorn 绑定到 UNIX 套接字(例如 http://michal.karzynski.pl/blog/2013/06/09/django-nginx-gunicorn-virtualenv-supervisor/)
upstream hello_app_server
server unix:/tmp/gunicorn.sock fail_timeout=0;
...
location /
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename)
proxy_pass http://hello_app_server;
break;
认为哪种策略更好?任何 cmets 的正确方法?我倾向于使用套接字方法,因为我想象 TCP 会引入开销。我最关心的是我见过的实现示例之间在标头、连接超时等方面的差异。
【问题讨论】:
你能解释一下fail_timout=0
吗?
"fail_timeout=0 意味着我们总是重试上游,即使它未能返回良好的 HTTP 响应(以防 Unicorn master 核对单个 worker 超时)。"
The docs 说:如果组中只有一个服务器,则忽略max_fails、fail_timeout和slow_start参数,永远不会认为这样的服务器不可用。
【参考方案1】:
除了较小的 TCP/IP 开销外,没有太大区别。每个listen() 套接字都有一个连接队列,而accept() 只是从该队列中弹出一个连接。在 gunicorn 中,每个工作人员只是从该队列中弹出一个新连接,因为它不会改变。区别在于性能(套接字快一点)和可移植性(端口:IP 更灵活)。 Unix 域套接字将为您提供更好的性能,而连接到 localhost 的套接字为您提供更好的可移植性,如果您将服务器应用程序移动到不同的操作系统,您只需将 IP 地址从 localhost 更改为不同的主机名即可.
【讨论】:
在安全性(即暴露端口)方面有什么不同吗?还是因为ALLOWED_HOSTS
将有效域列入白名单,这无关紧要?
你不应该暴露端口,如果你的 WSGI 服务在端口 8000 上运行并且你的 nginx 在本地使用该端口的上游并且 nginx 在端口 80 上,你只需要暴露端口80. 所以不应该有任何安全问题,应该没有必要暴露 WSGI 端口。【参考方案2】:
会更喜欢 TCP/IP 上的套接字流量,因为不需要打开额外的端口。打开的端口越少,你的系统就越坚固
正如这里所说的“偏执” https://hynek.me/talks/python-deployments/
“具有限制性权限的 UNIX 文件套接字是你的朋友。你可以停止使用端口号”
【讨论】:
【参考方案3】:如果您的网络服务器和应用服务器(wsgi)都存在于同一台机器上,那么套接字流量将是一个简单的选择。但是,您将需要通过网络连接的网络端口,因为套接字不能在网络上工作,所以..
-
如果 webserver 和 appserver 位于同一台机器上 - GO SOCKET
如果 webserver 和 appserver 在网络上 - GO PORTS
【讨论】:
【参考方案4】:我知道我参加这个聚会迟到了,如果你想让它在带有 SELinux 强制的 Red Hat 风味 Linux 上工作,这可能会有用。
如果您尝试使用套接字,则会很麻烦。我放弃了。
如果您尝试通过任意 TCP 端口绑定 Gunicorn,它也会妨碍您。默认情况下(在 Centos 1708 上),SELinux 很乐意使用一部分端口:80,81,443,488,8008,8009,8443,9000
我选择了 8009,但显然你可以使用其他一些端口
semanage -a -t http_port_t -p tcp $PORTNUMBER
并查看端口列表
semanage port -l
【讨论】:
【参考方案5】:这是我通过 Unix 套接字测试 TCP 代理的结果:
设置: nginx + gunicorn + django 在 AWS 上的 4 个 m4.xlarge 节点上运行。 每个节点的设置都是统一的(来自同一图像)。
在大约 30 分钟的时间内发出 100 万次请求:
由于其中一台服务器上运行不相关的作业,一个实例的 CPU 使用率为 100%。其他 3 个是 70% CPU,每个代表实际应用程序负载。
TCP 与套接字几乎相同
发出 1000000 个请求的时间
TCP 代理是 27 分钟
unix 套接字需要 31 分钟。
在这个特定的设置中没有 unix socket 性能优势。
【讨论】:
以上是关于gunicorn + nginx:通过套接字或代理服务器?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Amazon EC2 上使用 Gunicorn 设置 Nginx 代理缓冲?
Django应用程序中的空REMOTE_ADDR值,当使用nginx作为反向代理与gunicorn