如何使用 mod_wsgi 提高 Apache 的性能?
how to improve the performance of Apache with mod_wsgi?
使用 Apache/2.4.12(Unix) 和 mod_wsgi-4.4.11 并打击 apache/conf/extra:
的配置
//httpd-mpm.conf
<IfModule mpm_worker_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
//httpd-vhosts.conf
WSGIRestrictEmbedded On
<VirtualHost *:443>
ServerName form.xxx.com
WSGIScriptAlias / /usr/local/apache/services/form/form.wsgi
WSGIDaemonProcess paymentform user=test processes=10 threads=5 display-name=%{GROUP} maximum-requests=100
WSGIApplicationGroup %{RESOURCE}
WSGIProcessGroup form
DocumentRoot /usr/local/apache/services/form
SSLEngine On
//any certification files
<Directory /usr/local/apache/services/form>
Require all granted
</Directory>
</VirtualHost>
在此配置中,我使用Apache jmeter 进行测试。
GET : form.xxx.com //only return "index" string
Number of Threads(users):100
Ramp-up Period : 0
Loop count : 10
但结果是..
samples: 1000
Average: 3069
Min : 13
Max : 22426
Std.Dev: 6671.693614549157
Error %: 10.0%
Throughput : 24.1/sec
KB/sec : 10.06/sec
AvgBytes : 428.5
在测试过程中,在400~500个请求中提出连接被拒绝或连接超时并停止接收请求。服务器 cpu 或内存未满。
如何提高性能?
修复 mpm worker 配置?或修复 httpd-vhosts 中的 WSGI 配置?
我修改了下面的httpd-mpm.conf,没啥区别
<IfModule mpm_worker_module>
StartServers 10
ServerLimit 32
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 800
MaxConnectionsPerChild 0
</IfModule>
您的配置有很多错误。一个可能是剪切和粘贴错误。另一个是潜在的安全问题。而且会严重影响性能。
首先你有:
WSGIProcessGroup form
如果您确实需要,那么 Web 请求甚至不会到达 WSGI 应用程序并且应该 return 500 错误响应。如果它没有给出错误,那么您的请求将被委托给上面配置中甚至没有提到的 mod_wsgi 守护进程组。这一切都是因为 WSGIProcessGroup
的值与 WSGIDaemonProcess
指令指定的已定义守护进程组的名称不匹配。
你必须拥有的是:
WSGIProcessGroup paymentform
我怀疑您在将配置粘贴到问题中时只是搞砸了配置。
与授权相关的一个问题是您有:
WSGIApplicationGroup %{RESOURCE}
这是默认值。通常永远不需要明确设置它。如果只将一个 WSGI 应用程序委托给守护进程组,通常会使用的是:
WSGIApplicationGroup %{GLOBAL}
此特定值强制使用每个进程的主 Python 解释器上下文,这避免了某些第三方扩展模块在子解释器上下文中无法正常工作的问题。
第二个问题是潜在的安全问题。你有:
DocumentRoot /usr/local/apache/services/form
使用 WSGIScriptAlias
指令时,无需将 DocumentRoot
设置为 WSGI 脚本文件或应用程序源代码所在的父目录。
这样做的危险在于,如果 WSGIScriptAlias
被意外禁用,或更改为子 URL,则您的所有源代码都可以下载。
简而言之,让 DocumentRoot
默认为整个服务器的空默认目录,或者为 VirtualHost
创建一个空目录并将其设置为该目录。
最后一件事会极大地影响你的表现是使用 maximum-requests
选项到 WSGIDaemonProcess
。除非您了解其中的含义并有特定的临时需求,否则切勿在生产系统中使用 maximum-requests
。
将此值设置为较低的值,意味着守护进程将被终止并每 100 个请求重新启动。在与基准测试一样的大量请求下,您将不断重新启动应用程序进程。
这样做的结果会增加 CPU 负载和更慢的响应时间,由于一切都在不断重启,服务器超载,因此有可能积压到非常长的响应时间。
因此,您绝对应该做的第一件事就是删除 maximum-requests
,您应该会立即看到一些改善。
您还遇到了 Apache MPM 设置中进程重启的问题。它并不重要,因为这只会影响代理请求的 Apache 工作进程,但它也会导致额外的 CPU 使用,并且可能需要更多的工作进程。
我之前在:
中讲过MPM设置导致Apache进程流失的问题
你的基准测试的最后一个问题是你的测试,如果它只是 returning 是来自一些简单的 hello world 类型程序的 'index' 字符串,那么它与你的测试无关实际应用。
真实应用程序通常不会那么简单,由于模板渲染、数据库访问等原因,WSGI 应用程序内的时间会更多。这意味着真实应用程序的性能配置文件将完全不同并且更改配置服务器的方式。
换句话说,使用 hello world 程序进行测试会给您带来完全错误的想法,即您需要做什么才能正确配置服务器。您确实需要了解您的应用程序在正常流量负载下的真实性能概况并从那里开始工作。也就是说,把服务器锤死也是错误的,不现实的。
我最近在我的 blog site 上写了一篇关于人们使用的典型的 hello world 测试是多么错误的博客,并给出了一些特定测试的例子,这些例子展示了不同 WSGI 服务器和配置的性能如何可以显着提高不同的。这样做的目的是表明您不能将事情建立在一个简单的测试之上,您确实需要了解您的 WSGI 应用程序在做什么。
在所有这一切中,要真正真正了解正在发生的事情以及如何正确调整服务器,您需要使用内置于 WSGI 服务器的性能监控解决方案,以便深入了解不同方面它是如何工作的,因此需要调整哪些旋钮。博客文章也涵盖了这一点。
我遇到了与ash84描述的类似的问题,我使用jmeter测试性能,发现当jmeter线程数设置超过某个值(在我的例子中是50)时,错误%变为非零。
在我看了 Graham Dumpleton 的 talk 之后,我意识到它的发生主要是因为没有足够的备用 MPM 线程准备好为即将到来的 burst jmeter 请求提供服务。在这种情况下,一些 jmeter 请求一开始没有得到服务,即使 MPM 线程数后来赶上了。
简而言之,将 MinSpareThreads 设置为更大的值解决了我的问题,我将 jmeter 线程数从 50 提高到 100,并得到 0% 的错误。
MinSpareThreads 120
MaxSpareThreads 150
MaxRequestWorkers 200
WSGIDaemonProcess 进程数乘以 WSGIDaemonProcess 线程数不必大于 jmeter 线程数。但是您可能需要将它们设置为更高的值以确保 WSGIDaemonProcess 能够足够快地处理请求。
使用 Apache/2.4.12(Unix) 和 mod_wsgi-4.4.11 并打击 apache/conf/extra:
的配置//httpd-mpm.conf
<IfModule mpm_worker_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
//httpd-vhosts.conf
WSGIRestrictEmbedded On
<VirtualHost *:443>
ServerName form.xxx.com
WSGIScriptAlias / /usr/local/apache/services/form/form.wsgi
WSGIDaemonProcess paymentform user=test processes=10 threads=5 display-name=%{GROUP} maximum-requests=100
WSGIApplicationGroup %{RESOURCE}
WSGIProcessGroup form
DocumentRoot /usr/local/apache/services/form
SSLEngine On
//any certification files
<Directory /usr/local/apache/services/form>
Require all granted
</Directory>
</VirtualHost>
在此配置中,我使用Apache jmeter 进行测试。
GET : form.xxx.com //only return "index" string
Number of Threads(users):100
Ramp-up Period : 0
Loop count : 10
但结果是..
samples: 1000
Average: 3069
Min : 13
Max : 22426
Std.Dev: 6671.693614549157
Error %: 10.0%
Throughput : 24.1/sec
KB/sec : 10.06/sec
AvgBytes : 428.5
在测试过程中,在400~500个请求中提出连接被拒绝或连接超时并停止接收请求。服务器 cpu 或内存未满。
如何提高性能? 修复 mpm worker 配置?或修复 httpd-vhosts 中的 WSGI 配置?
我修改了下面的httpd-mpm.conf,没啥区别
<IfModule mpm_worker_module>
StartServers 10
ServerLimit 32
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 800
MaxConnectionsPerChild 0
</IfModule>
您的配置有很多错误。一个可能是剪切和粘贴错误。另一个是潜在的安全问题。而且会严重影响性能。
首先你有:
WSGIProcessGroup form
如果您确实需要,那么 Web 请求甚至不会到达 WSGI 应用程序并且应该 return 500 错误响应。如果它没有给出错误,那么您的请求将被委托给上面配置中甚至没有提到的 mod_wsgi 守护进程组。这一切都是因为 WSGIProcessGroup
的值与 WSGIDaemonProcess
指令指定的已定义守护进程组的名称不匹配。
你必须拥有的是:
WSGIProcessGroup paymentform
我怀疑您在将配置粘贴到问题中时只是搞砸了配置。
与授权相关的一个问题是您有:
WSGIApplicationGroup %{RESOURCE}
这是默认值。通常永远不需要明确设置它。如果只将一个 WSGI 应用程序委托给守护进程组,通常会使用的是:
WSGIApplicationGroup %{GLOBAL}
此特定值强制使用每个进程的主 Python 解释器上下文,这避免了某些第三方扩展模块在子解释器上下文中无法正常工作的问题。
第二个问题是潜在的安全问题。你有:
DocumentRoot /usr/local/apache/services/form
使用 WSGIScriptAlias
指令时,无需将 DocumentRoot
设置为 WSGI 脚本文件或应用程序源代码所在的父目录。
这样做的危险在于,如果 WSGIScriptAlias
被意外禁用,或更改为子 URL,则您的所有源代码都可以下载。
简而言之,让 DocumentRoot
默认为整个服务器的空默认目录,或者为 VirtualHost
创建一个空目录并将其设置为该目录。
最后一件事会极大地影响你的表现是使用 maximum-requests
选项到 WSGIDaemonProcess
。除非您了解其中的含义并有特定的临时需求,否则切勿在生产系统中使用 maximum-requests
。
将此值设置为较低的值,意味着守护进程将被终止并每 100 个请求重新启动。在与基准测试一样的大量请求下,您将不断重新启动应用程序进程。
这样做的结果会增加 CPU 负载和更慢的响应时间,由于一切都在不断重启,服务器超载,因此有可能积压到非常长的响应时间。
因此,您绝对应该做的第一件事就是删除 maximum-requests
,您应该会立即看到一些改善。
您还遇到了 Apache MPM 设置中进程重启的问题。它并不重要,因为这只会影响代理请求的 Apache 工作进程,但它也会导致额外的 CPU 使用,并且可能需要更多的工作进程。
我之前在:
中讲过MPM设置导致Apache进程流失的问题你的基准测试的最后一个问题是你的测试,如果它只是 returning 是来自一些简单的 hello world 类型程序的 'index' 字符串,那么它与你的测试无关实际应用。
真实应用程序通常不会那么简单,由于模板渲染、数据库访问等原因,WSGI 应用程序内的时间会更多。这意味着真实应用程序的性能配置文件将完全不同并且更改配置服务器的方式。
换句话说,使用 hello world 程序进行测试会给您带来完全错误的想法,即您需要做什么才能正确配置服务器。您确实需要了解您的应用程序在正常流量负载下的真实性能概况并从那里开始工作。也就是说,把服务器锤死也是错误的,不现实的。
我最近在我的 blog site 上写了一篇关于人们使用的典型的 hello world 测试是多么错误的博客,并给出了一些特定测试的例子,这些例子展示了不同 WSGI 服务器和配置的性能如何可以显着提高不同的。这样做的目的是表明您不能将事情建立在一个简单的测试之上,您确实需要了解您的 WSGI 应用程序在做什么。
在所有这一切中,要真正真正了解正在发生的事情以及如何正确调整服务器,您需要使用内置于 WSGI 服务器的性能监控解决方案,以便深入了解不同方面它是如何工作的,因此需要调整哪些旋钮。博客文章也涵盖了这一点。
我遇到了与ash84描述的类似的问题,我使用jmeter测试性能,发现当jmeter线程数设置超过某个值(在我的例子中是50)时,错误%变为非零。
在我看了 Graham Dumpleton 的 talk 之后,我意识到它的发生主要是因为没有足够的备用 MPM 线程准备好为即将到来的 burst jmeter 请求提供服务。在这种情况下,一些 jmeter 请求一开始没有得到服务,即使 MPM 线程数后来赶上了。
简而言之,将 MinSpareThreads 设置为更大的值解决了我的问题,我将 jmeter 线程数从 50 提高到 100,并得到 0% 的错误。
MinSpareThreads 120
MaxSpareThreads 150
MaxRequestWorkers 200
WSGIDaemonProcess 进程数乘以 WSGIDaemonProcess 线程数不必大于 jmeter 线程数。但是您可能需要将它们设置为更高的值以确保 WSGIDaemonProcess 能够足够快地处理请求。