![使用 Varnish 和大量 RAM 优化繁忙的网站](https://linux22.com/image/596991/%E4%BD%BF%E7%94%A8%20Varnish%20%E5%92%8C%E5%A4%A7%E9%87%8F%20RAM%20%E4%BC%98%E5%8C%96%E7%B9%81%E5%BF%99%E7%9A%84%E7%BD%91%E7%AB%99.png)
[更新后更加简洁!]
我对针对大量流量的 Web 服务器进行优化还很陌生,但现在我正在尝试这个领域。
星期一,我们的网站服务器出现“slashdotted”现象——流量猛增(一小时内约有 85,000 名访客),尽管我们运行了 Varnish 和 nginx(它们工作正常),但 Apache 方面的情况确实很棘手,因为有些请求会生成一些动态内容。
服务器目前有 8GB RAM,很快将升级到 32GB,所以我确实需要 32GB 系统的配置帮助。当前运行的是 64 位 centos。
我已经研究了 varnish 和 nginx 设置,它们很好 - 合理的设置(静态内容由 nginx 直接提供,大量动态内容由 varnish 提供,如果它不在 varnish 中,则请求将传递给 apache。)
那么在 Apache 上,我们使用 MPM prefork 模块,每个 Apache 进程似乎都占用了大量的 RAM:
前三名:
S 48 20961 2965 0 75 0 187128 128307 ? ? 00:05:25 httpd
S 48 20959 2965 0 75 0 249788 143435 ? ? 00:05:55 httpd
S 48 18581 2965 0 75 0 314564 157747 ? ? 00:06:40 httpd
倒数第 3 名:
S 0 2965 1 0 78 0 15132 89017 stext ? 00:00:00 httpd
S 48 20947 2965 0 75 0 38492 93001 ? ? 00:00:00 httpd
S 48 20945 2965 0 75 0 43300 93897 ? ? 00:00:01 httpd
我不太确定,但我认为一个进程 = 一个客户端 = 一个人浏览器的一个连接。我想我的第一个问题是有人能证实这一点吗?是的,我们在同一台服务器上运行 php 和 zend 框架,MySQL 作为数据库后端。
当前配置(服务器当前有 8GB RAM):
MaxKeepAliveRequests 100
KeepAliveTimeout 2
<IfModule prefork.c>
StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit 200
MaxClients 200
MaxRequestsPerChild 500
</IfModule>
我目前的想法是,在这种配置下,Apache 理论上可以在最坏的情况下尝试使用大约 63GB 的内存。例如 315MB 进程 * 200 maxclients = 大量内存。我不完全确定它是否能这样工作,但如果有人也能证实这一点,那会很有帮助!
我想做的是获得一些关于我应该注意哪些事情的建议 - 我们希望服务器能够随时处理另一波请求并利用我们获得的所有新 RAM。如果我自己无法弄清楚,我将在另一个问题中讨论如何优化 MySQL,但这里是 conf,以防万一会有所不同:http://pastebin.com/GbJU7AxY
多多加油!约翰。
答案1
每天 85,000 名访客到底是什么意思?独立访客、HTTP 总点击量,还是其他什么?
只要请求可以从缓存中得到满足,Varnish 就应该能够每秒处理数千次点击,而且占用很少的 CPU 和内存。尤其是在使用 Slashdotted 时,因为大多数人会寻找完全相同的内容。但它确实需要微调。默认情况下,它相当保守,因为它对通过的内容了解不多。它根据看到的标头和简单的规则集做出决定。例如,默认情况下,Varnish 会缓存对象 2 分钟,但前提是没有饼干存在于请求中,并且对象的 TTL 大于 0,等等。检查默认 VCL(特别是接收函数和取值) 来确定默认逻辑,并确保您理解它。
因此,在您的域上设置单个 Google Analytics cookie 会导致所有请求传递到后端,即使 GA cookies 不是由您的后端服务器处理,而是由 Google 的 javascript 处理。WordPress 应用程序会设置各种 cookies,其中大多数仅适用于动态内容,这些 cookies 会在每次请求时由浏览器返回。如果您的页面包含 49 个静态资产和 1 个动态页面,则意味着这些静态资产都不会被缓存,因为请求包含您不关心的 cookie。只有动态请求上的 cookie 才能通过。这样的错误基本上会禁用 Varnish。此外,代码返回的各种缓存控制(和相关的)HTTP 标头也很重要。如果您的应用程序声称 Varnish 从后端检索的对象已过期,例如过去的 Expires 标头,Varnish 将不会缓存该对象。
换句话说,您需要调整应用程序以发出正确的标头,以便客户端(Varnish 和浏览器)可以缓存返回的内容。任何您无法在应用程序中更正的内容,您都可以在 Varnish 的 VCL 中覆盖。
例如,下面是我的代码,用于删除各种客户端跟踪 cookie,防止它们到达服务器。这属于vcl_recv
:
# Remove tracking cookies. The server doesn't need to see them.
if (req.http.Cookie) {
# Remove has_js and Google Analytics __* cookies.
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js|sifrFetch)=[^;]*", "");
# Remove a ";" prefix, if present.
set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
# Remove cookie header if empty
if (req.http.Cookie == "") {
remove req.http.Cookie;
}
}
类似地,我删除了某些路径的传入 cookie,以使这些请求可缓存:
if ( req.url ~ "^/cms/cms_files/(?:css|img|js)/" || #CMS1
req.url ~ "^/site_files/(?:css|img|imgc|js|swf|uploads|xml/.+\.xml$)" || #CMS1
req.url ~ "^/(?:images|stylesheets|javascripts|swf|site_files/js_libs|site/image|favicon\.ico$|robots\.txt$)" || #CMS2
( req.http.host ~ "(?:shop\.example\.com|www\.example\.nl)" && #Magento
req.url ~ "^/(?:404|js|media|skin|favicon\.ico$)" ) || #Magento
) {
unset req.http.cookie;
}
我在 vcl_fetch 中使用了类似的节,而unset beresp.http.cookie;
不是,以防止后端在我不想要的路径上设置任何 cookie。
你可以添加一些调试头提供有关 varnish 如何处理请求的信息。使用 Firebug 查看这些内容,您将对您的应用有更多了解。另一个很好的信息来源是清漆书。例如,参见:https://www.varnish-software.com/static/book/VCL_Basics.html
我们的大部分动态内容缓存了 60 秒,足以抵御流量冲击。如果您需要一些单独的内容,但页面上的大部分内容都是静态的,请查看 Varnish 的静电放电(edge-side-includes) 允许您为页面的不同部分指定不同的缓存 TTL。
现在您已将后端请求减少到最低限度,请优化这些请求。分析您的应用程序,查找并修复问题。
你说得对:
MaxClients x (maximum physical memory per Apache process) = (total memory Apache can use)
不过,这是物理内存,而不是您提到的虚拟内存。在顶部,水库列显示每个进程使用的物理内存。每个 Apache 进程都会增长到您的站点运行的最大脚本。将 MaxClients 限制为您的服务器可以处理的数量。接受您没有资源的请求是没有意义的。一旦您开始交换,您就输了。增加 Apache 预分叉的进程(服务器)数量,因为分叉是一项繁重的操作,您希望在它已经很忙时执行。ServerLimit 行是多余的。禁用 KeepAlive 或将其设置为 1-2 秒。
如果您提供许多静态资产,请考虑从 mod_php 切换到 PHP-FPM。这可让您的 Apache 进程保持轻量级。