博客 | NGINX

使用 NGINX 最大化 Python 性能,第 1 部分: Web 服务和缓存

NGINX-F5-horiz-black-type-RGB 的一部分
Floyd Smith 缩略图
弗洛伊德·史密斯
2016 年 3 月 31 日发布

简介——如何将 NGINX 与 Python 结合使用

Python 因其易于使用且有趣、使软件开发变得更容易以及运行时性能超过其他脚本语言而闻名。 (尽管 PHP 的最新版本 PHP 7 可能会与 Python 展开竞争。)

每个人都希望自己的网站和应用运行得更快。 此外,每个流量不断增长或流量急剧飙升的网站都容易出现性能问题和停机,而且这些问题和停机通常发生在最糟糕的时候,也就是最繁忙的时候。 此外,无论是流量稳步增长还是使用量急剧增加,几乎所有网站都会遭遇性能问题和停机。

这就是 NGINX 和 NGINX Plus 的作用所在。 他们通过三种不同方式提高网站性能:

  1. 作为 Web 服务器,NGINX 最初是为了解决C10K 问题而开发的,即轻松支持 10,000 个或更多的同时连接。 使用 NGINX 作为 Python 应用程序的 Web 服务器可以让您的网站运行得更快,即使在流量较低的情况下也是如此。 当您拥有数千名用户时,它几乎肯定会提供更高的性能、更少的崩溃和更少的停机时间。 您还可以在 NGINX Web 服务器上执行静态文件缓存或微缓存,但在单独的 NGINX 反向代理服务器上运行时,两者的效果都会更好(请参阅下一段)。
  2. 作为反向代理服务器- 您可以将 NGINX 作为反向代理服务器放置在当前应用服务器设置前面。 NGINX 面向 Web 并将请求传递至您的应用服务器。 这个“奇怪的技巧”可以使您的网站运行得更快,减少停机时间,消耗更少的服务器资源,并提高安全性。 您还可以在反向代理服务器上缓存静态文件(非常高效),添加动态内容的微缓存以减少应用本身的负载等等。
  3. 作为多个应用服务器的负载平衡器– 首先部署反向代理服务器。 然后通过并行运行多个应用服务器并使用 NGINX 或 NGINX Plus 在它们之间平衡流量负载来扩展。 通过这种部署,您可以根据流量需求轻松扩展网站的性能,提高可靠性和正常运行时间。 如果需要给定的用户会话保留在同一台服务器上,请配置负载平衡器以支持会话持久性

无论您将 NGINX 和 NGINX Plus 用作 Python 应用程序的 Web 服务器、反向代理服务器、负载均衡器还是同时用于这三个用途,它们都能带来优势。

在本系列文章的第一部分中,我们介绍了五条提高 Python 应用程序性能的技巧,包括使用 NGINX 和 NGINX Plus 作为 Web 服务器、如何实现静态文件的缓存以及应用生成文件的微缓存。 在第 2 部分中,我们将描述如何使用 NGINX 和 NGINX Plus 作为反向代理服务器以及多个应用服务器的负载均衡器。

技巧 1——查找 Python 性能瓶颈

在两种截然不同的条件下,Python应用的性能至关重要 —— 首先,每天有“合理”数量的用户;其次,在高负载下。 许多网站所有者很少担心轻负载下的性能,而以我们的拙见,他们应该为响应时间每十分之一秒的性能而担忧。 将响应时间缩短几毫秒是一项困难且吃力不讨好的工作,但它可以让用户更满意,业务成果更好。

然而,这篇博文和随附的第 2 部分重点关注的是每个人都担心的情况:网站繁忙时出现的性能问题,例如性能大幅下降和崩溃。 此外,许多黑客攻击模仿用户数量突然激增的影响,而提高网站性能通常也是应对攻击的重要步骤。

对于为每个用户分配一定量内存的系统(如 Apache HTTP Server),随着越来越多的用户加入,添加用户会导致物理内存超载。 服务器开始交换磁盘,性能下降,并随之出现性能不佳和崩溃。 正如这篇博客文章中所述,迁移到 NGINX 有助于解决此问题。

Python 特别容易出现与内存相关的性能问题,因为它通常比其他脚本语言使用更多的内存来完成其任务(因此执行速度更快)。 因此,在其他条件相同的情况下,与使用其他语言编写的应用程序相比,基于 Python 的应用程序在较少的用户负载下可能会“失败”。

优化您的应用程序可能会有所帮助,但这通常不是解决流量相关的网站性能问题的最佳或最快的方法。 这篇博文以及随附的第 2 部分中介绍的步骤是解决流量相关性能问题的最佳和最快方法。 然后,在完成这里给出的步骤后,一定要回去改进您的应用程序,或者重写它以使用微服务架构

提示 2 - 选择单服务器或多服务器部署

小型网站在单台服务器上部署时运行良好。 大型网站需要多台服务器。 但如果你处于中间的灰色地带——或者你的网站正在从一个小网站发展成为一个大网站——你就需要做出一些有趣的选择。

如果您采用单服务器部署,当遇到流量高峰或总体流量快速增长时,您将面临巨大的风险。 您的可扩展性是有限的,可能的修复包括改进您的应用程序、将您的 Web 服务器切换到 NGINX、获取更大更快的服务器或将存储卸载到内容分发网络 (CDN)。 每个选项都需要花费时间去实现,需要花费成本,并且有在实现过程中引入错误或问题的风险。

此外,采用单服务器部署,您的网站根据定义就会有一个单点故障——并且许多可能导致您的网站离线的问题都没有快速或简单的解决方案。

NGINX 和 Python 协同工作,通过 NGINX 的 Web 服务、负载均衡和缓存功能提供高性能
“将 NGINX 置于应用服务器之前”

如果您在单服务器部署中将服务器切换到 NGINX,则可以自由选择 NGINX 开源和 NGINX Plus。 NGINX Plus 包括企业级支持和附加功能。 某些附加功能(例如实时活动监控)与单服务器部署相关,而其他功能(例如负载均衡会话持久性)在多服务器部署中使用 NGINX Plus 作为反向代理服务器时才会发挥作用。

从各方面因素来看,除非您确定您的网站在未来很长一段时间内都会保持较小的规模,并且停机时间不是一个主要的问题,否则单服务器部署还是有一定的风险。 多服务器部署几乎可以任意扩展——可以消除单点故障,并且性能可以根据您的选择而变化,同时能够快速增加容量。

提示 3 – 将您的 Web 服务器更改为 NGINX

在 Web 的早期,“Apache”这个名称是“Web 服务器”的同义词。 但是 NGINX 是在 21 世纪初开发出来的,并且正在稳步提升其受欢迎程度;它已经是世界上 1,000、10,000、100,000 和 [ngx_snippet name='proportion-top-sites'] 的排名第一的 Web 服务器

NGINX 的开发是为了解决C10K 问题——即在给定的内存预算内处理超过 10,000 个同时连接。 其他 Web 服务器需要为每个连接分配一块内存,因此当数千个用户同时想要访问某个网站时,它们就会耗尽物理内存,导致速度变慢甚至崩溃。 NGINX 单独处理每个请求,并优雅地扩展到更多用户。 (它也非常适合其他用途,正如我们将在下面描述的。)

下面是 NGINX 架构的高级概述。

使用 NGINX 功能进行 Web 服务、负载均衡和缓存的 Python 配置指导架构
NGINX 架构,摘自《开源applications架构》第二卷

在图中,Python应用服务器适合后端的应用服务器块,并显示由 FastCGI 访问。NGINX 不“知道”如何运行 Python,因此它需要一个网关来访问运行 Python 的环境。 FastCGI 是 PHP、Python 和其他语言广泛使用的接口。

然而,Python 和 NGINX 之间通信的更流行的选择是 Web 服务器网关接口 (WSGI)。 WSGI 在多线程和多进程环境中工作,因此它可以很好地扩展到本博文中提到的所有部署选项。

如果您将 NGINX 用作 Web 服务器,则涉及以下步骤,可以获得很多支持:

此代码片段展示了如何配置 NGINX 以与 uWSGI 一起使用——在本例中,项目使用 Python 框架 Django:

http { # ...
上游 django {
服务器 127.0.0.1:29000;
}

服务器 {
监听 80;
服务器名称 myapp.example.com;

根 /var/www/myapp/html;

位置 / {
索引 index.html;
}

位置 /static/ {
别名 /var/django/projects/myapp/static/;
}

位置 /main {
包括 /etc/nginx/uwsgi_params;
uwsgi_pass django;

uwsgi_param 主机 $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
}
}
}

技巧 4 - 实现静态文件缓存

静态内容的缓存涉及在应用服务器以外的位置保存不经常更改的文件的副本(这可能意味着每隔几个小时或从不更改)。 静态内容的典型示例是作为网页一部分显示的 JPEG 图像。

静态文件缓存是增强应用性能的常用方法,它实际上发生在几个层面:

  • 在用户的浏览器中
  • 互联网提供商的多个层级——从公司内部网络到互联网服务提供商 (ISP)
  • 在 Web 服务器上,我们将在此处进行描述

在 Web 服务器上实现静态文件缓存有两个好处:

  • 更快地交付给用户——NGINX针对静态文件缓存进行了优化,并且执行静态内容请求的速度比应用服务器快得多。
  • 减少应用服务器上的负载——应用服务器甚至看不到对缓存静态文件的请求,因为 Web 服务器可以满足这些请求。

静态文件缓存在单服务器实现下工作得很好,但是底层硬件仍然由 Web 服务器和应用服务器共享。 如果 Web 服务器的硬件忙于检索缓存文件(即使非常高效),这些硬件资源也无法供应应用使用,从而可能在一定程度上降低其速度。

为了支持浏览器缓存,请为静态文件正确设置 HTTP 标头。 考虑 HTTP Cache-Control标头(特别是其max-age设置)、 Expires标头和Entity标签。 有关该主题的详细介绍,请参阅 NGINX Plus 管理指南中的使用 NGINX 和 NGINX Plus 作为带有 uWSGI 和 Django 的application网关

以下代码配置 NGINX 来缓存静态文件,包括 JPEG 文件、GIF、PNG 文件、MP4 视频文件、Powerpoint 文件等等。 将www.example.com替换为您的 Web 服务器的 URL。

server { # 用您的 Web 服务器 URL 替换“www.example.com”
server_name www.example.com;
root /var/www/example.com/htdocs;
index index.php;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;

location / {
try_files $uri $uri/ /index.php?$args;
}

location ~ .php$ {
try_files $uri =404;
include fastcgi_params;
# 用您的 Python 服务器的套接字或地址和端口替换
fastcgi_pass unix:/var/run/php5-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
} 

位置 ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg
|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid
|midi|wav|bmp|rtf)$ {
expires max;
log_not_found off;
access_log off;
}
}

提示 5 - 实现微缓存

微缓存为提高运行 Python、PHP 和其他语言的应用服务器的性能提供了巨大的机会。 出于缓存目的,网页有三种类型:

  • 静态文件——这些文件可以被缓存,如技巧 4中所述。
  • application生成的非个性化页面——缓存这些页面通常没有意义,因为它们需要保持最新。 一个例子是向未登录的电子商务用户提供页面(参见下一点)——可用的产品、推荐的类似产品等可能会不断变化,因此提供全新的页面非常重要。 然而,如果另一个用户出现,比如说十分之一秒后,向他们显示与前一个用户相同的页面可能就足够了。
  • application生成的个性化页面——这些页面无法被缓存,因为它们是特定于用户的,并且同一个用户不太可能两次看到同一个个性化页面。 一个例子是已登录用户的电子商务页面;同一页面不能显示给其他用户。
使用 NGINX 进行微缓存
静态文件和非个性化应用生成的文件可以被缓存

微缓存对于上面描述的第二种页面类型(应用生成的非个性化页面)很有用。 “微”是指短暂的时间范围。 当您的网站每秒生成几次相同的页面时,将其缓存一秒钟可能不会对页面的新鲜度造成太大影响。 然而,这个短暂的缓存期可以极大地减轻应用服务器的负载,尤其是在流量高峰期间。 它不会在缓存超时期间生成 10、20 或 100 个页面(内容相同),而是只生成一次给定页面,然后该页面被缓存并从缓存中提供给许多用户。

效果相当神奇。 一个服务器在每秒处理几十个请求时会很慢,但在处理一个请求时就会变得非常快。 (当然,还有任何个性化页面。) 我们自己的 Owen Garrett 发表了一篇博客文章,详细阐述了微缓存的好处,并提供了配置代码。 核心的变化是设置一个超时时间为一秒的代理缓存,只需要几行配置代码。

proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;server {
proxy_cache 缓存;
proxy_cache_valid 200 1s;
# ...
}

有关更多示例配置,请参阅 Tyler Hicks‑Wright 关于Python 和 uWSGI 与 NGINX 的博客。

结论

在第一部分中,我们讨论了提高单服务器 Python 实现性能的解决方案,以及缓存,它们可以部署在单服务器实现上,也可以在反向代理服务器或单独的缓存服务器上运行。 (缓存在单独的服务器上效果更好。) 下一部分,第 2 部分,介绍需要两台或更多台服务器的性能解决方案。

如果您想探索NGINX Plus为您的应用提供的高级功能,例如支持、实时活动监控和动态重新配置,请立即开始30 天免费试用联系我们讨论您的用例


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”