如何在 VPS 上使用 Nginx 设置 FastCGI 缓存

预告片


Nginx 包括一个 FastCGI 模块,该模块具有从 PHP 后端提供的动态内容缓存指令. 设置此设置消除了需要额外的页面缓存解决方案,如反向代理(想想 Varnish)或应用程序特定的插件。

在您的 VPS 上启用 FastCGI 缓存


本文假定您已在您的 dropplet 上设置并配置了 Nginx with PHP

1nano /etc/nginx/sites-enabled/vhost

server { } 指令之外的文件顶部添加以下行:

1fastcgi_cache_path /etc/nginx/cache levels=1:2 keys_zone=MYAPP:100m inactive=60m;
2fastcgi_cache_key "$scheme$request_method$host$request_uri";

fastcgi_cache_path指令规定了缓存(/etc/nginx/cache)的位置,其大小(100m),内存区域名称(MYAPP),子目录级别和 _inactive` 计时器。

位置可能在硬盘上的任何地方;然而,大小必须小于您的滴子的RAM + Swap否则你会收到一个错误,上面写着不能分配内存

fastcgi_cache_key指令规定了缓存文件名将如何进行缓存。

接下来,移动将 PHP 请求传递到 php5-fpm 的位置指令。

1fastcgi_cache MYAPP;
2fastcgi_cache_valid 200 60m;

fastcgi_cache指令是指我们在fastcgi_cache_path指令中指定的内存区域名称,并在该区域存储缓存。

默认情况下, Nginx 会将缓存对象存储在以下任何标题中所指定的时间: **X-Accel-Expires/Expires/Cache-Control。

fastcgi_cache_valid指令用于指定默认的缓存寿命,如果这些标题不存在。在我们上面输入的声明中,只有具有状态代码200的响应被缓存。

** 进行配置测试**

1service nginx configtest

重新加载 Nginx 如果一切正常

1service nginx reload

完整的vhost文件将看起来像这样:

 1fastcgi_cache_path /etc/nginx/cache levels=1:2 keys_zone=MYAPP:100m inactive=60m;
 2fastcgi_cache_key "$scheme$request_method$host$request_uri";
 3
 4server {
 5    listen 80;
 6
 7	root /usr/share/nginx/html;
 8	index index.php index.html index.htm;
 9
10	server_name example.com;
11
12	location / {
13	    try_files $uri $uri/ /index.html;
14    }
15
16	location ~ \.php$ {
17	    try_files $uri =404;
18	    fastcgi_pass unix:/var/run/php5-fpm.sock;
19	    fastcgi_index index.php;
20	    include fastcgi_params;
21	    fastcgi_cache MYAPP;
22	    fastcgi_cache_valid 200 60m;
23    }
24}

接下来我们将进行测试,看看缓存是否有效。

在您的 VPS 上测试 FastCGI 缓存


创建一个 PHP 文件,输出一个 UNIX 时间戳。

1/usr/share/nginx/html/time.php

插入

1<?php
2echo time();
3?>

请使用 curl或您的 Web 浏览器多次请求此文件。

1root@droplet:~# curl http://localhost/time.php;echo
21382986152
3root@droplet:~# curl http://localhost/time.php;echo
41382986152
5root@droplet:~# curl http://localhost/time.php;echo
61382986152

如果缓存正常工作,您应该在所有请求上看到相同的时刻标记,因为答案已缓存。

对缓存位置进行 recursive 列表,以查找此请求的缓存。

 1root@droplet:~# ls -lR /etc/nginx/cache/
 2/etc/nginx/cache/:
 3total 0
 4drwx------ 3 www-data www-data 60 Oct 28 18:53 e
 5
 6/etc/nginx/cache/e:
 7total 0
 8drwx------ 2 www-data www-data 60 Oct 28 18:53 18
 9
10/etc/nginx/cache/e/18:
11total 4
12-rw------- 1 www-data www-data 117 Oct 28 18:53 b777c8adab3ec92cd43756226caf618e

命名公约将在净化部分中解释。

我们还可以让 Nginx 将X-Cache标题添加到响应中,表示是否错过了缓存或被击中。

在服务器 { } 指令上添加以下内容:

1add_header X-Cache $upstream_cache_status;

重新加载 Nginx 服务,并使用 curl 进行单词请求,以查看新标题。

 1root@droplet:~# curl -v http://localhost/time.php
 2* About to connect() to localhost port 80 (#0)
 3*   Trying 127.0.0.1...
 4* connected
 5* Connected to localhost (127.0.0.1) port 80 (#0)
 6> GET /time.php HTTP/1.1
 7> User-Agent: curl/7.26.0
 8> Host: localhost
 9> Accept: */*
10>
11* HTTP 1.1 or later with persistent connection, pipelining supported
12< HTTP/1.1 200 OK
13< Server: nginx
14< Date: Tue, 29 Oct 2013 11:24:04 GMT
15< Content-Type: text/html
16< Transfer-Encoding: chunked
17< Connection: keep-alive
18< X-Cache: HIT
19<
20* Connection #0 to host localhost left intact
211383045828* Closing connection #0

设置缓存例外


某些动态内容,如需要身份验证的页面,不应缓存,此类内容可以根据服务器变量,如request_uri,request_methodhttp_cookie,排除缓存。

以下是必须在 server{ } 环境中使用的示例配置。

 1#Cache everything by default
 2set $no_cache 0;
 3
 4#Don't cache POST requests
 5if ($request_method = POST)
 6{
 7    set $no_cache 1;
 8}
 9
10#Don't cache if the URL contains a query string
11if ($query_string != "")
12{
13    set $no_cache 1;
14}
15
16#Don't cache the following URLs
17if ($request_uri ~* "/(administrator/|login.php)")
18{
19    set $no_cache 1;
20}
21
22#Don't cache if there is a cookie called PHPSESSID
23if ($http_cookie = "PHPSESSID")
24{
25    set $no_cache 1;
26}

若要将$no_cache变量应用于相应的指令,请将下列行放入 location ~.php$ { }

1fastcgi_cache_bypass $no_cache;
2fastcgi_no_cache $no_cache;

fasctcgi_cache_bypass指令忽略了与我们之前设定的条件相关的请求的现有缓存。

清除隐藏


缓存命名公约基于我们为fastcgi_cache_key指令设置的变量。

1fastcgi_cache_key "$scheme$request_method$host$request_uri";

根据这些变量,当我们要求http://localhost/time.php时,以下将是实际值:

1fastcgi_cache_key "httpGETlocalhost/time.php";

通过 MD5 哈希传输此字符串将产生以下字符串:

1b777c8adab3ec92cd43756226caf618e

这将形成缓存的文件名作为我们输入的子目录级别=1:2.因此,目录的第一个级别将被命名为 1字符从这个MD5字符串的最后一个,这是 e;第二个级别将有最后一个 2字符之后的第一个级别即 18

1/etc/nginx/cache/e/18/b777c8adab3ec92cd43756226caf618e

基于此缓存命名格式,您可以在您最喜欢的语言中开发一个清除脚本. 对于本教程,我将提供一个简单的PHP脚本,该脚本清除 __POST__ed URL的缓存。

「/usr/share/nginx/html/purge.php」

  • 插入 *
 1<?php
 2$cache_path = '/etc/nginx/cache/';
 3$url = parse_url($_POST['url']);
 4if(!$url)
 5{
 6    echo 'Invalid URL entered';
 7    die();
 8}
 9$scheme = $url['scheme'];
10$host = $url['host'];
11$requesturi = $url['path'];
12$hash = md5($scheme.'GET'.$host.$requesturi);
13var_dump(unlink($cache_path . substr($hash, -1) . '/' . substr($hash,-3,2) . '/' . $hash));
14?>

向此文件发送一个 POST 请求,其中包含要清除的 URL。

1curl -d 'url=http://www.example.com/time.php' http://localhost/purge.php

脚本将输出 truefalse 取决于是否已清除缓存,请确保将此脚本排除在缓存中,并限制访问。

發表 由:

Published At
Categories with 技术
comments powered by Disqus