Nginx入门(四)Nginx 配置缓存服务器
Nginx入门(四)Nginx 配置缓存服务器
终于进入了该系列的最后一章。本章主要聊一下Nginx 缓存。 如果能好好利用Nginx 缓存绝对可以帮你提升网站性能。
Nginx对客户已经访问过的内容在Nginx服务器本地建立副本,这样在一段时间内再次访问该数据,就不需要通过Nginx服务器再次向后端服务器发出请求,所以能够减少Nginx服务器与后端服务器之间的网络流量,减轻网络拥塞,同时还能减小数据传输延迟,提高用户访问速度。同时,当后端服务器宕机时,Nginx服务器上的副本资源还能够回应相关的用户请求,这样能够提高后端服务器的鲁棒性。
本文将通过介绍Nginx缓存配置和一个简单的例子两部分,手把手让你掌握nginx配置缓存。
基本配置
通过该官网链接。大家可以了解配置说明。
proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
set $upstream http://ip:port
location / {
proxy_cache my_cache;
proxy_pass $upstream;
}
}
对上面的配置做一个简单介绍:
/path/to/cache #本地路径,用来设置Nginx缓存资源的存放地址
levels #默认所有缓存文件都放在同一个/path/to/cache下,但是会影响缓存的性能,因此通常会在/path/to/cache下面建立子目录用来分别存放不同的文件。假设levels=1:2,Nginx为将要缓存的资源生成的key为f4cd0fbc769e94925ec5540b6a4136d0,那么key的最后一位0,以及倒数第2-3位6d作为两级的子目录,也就是该资源最终会被缓存到/path/to/cache/0/6d目录中
key_zone #在共享内存中设置一块存储区域来存放缓存的key和metadata(类似使用次数),这样nginx可以快速判断一个request是否命中或者未命中缓存,1m可以存储8000个key,10m可以存储80000个key
max_size #最大cache空间,如果不指定,会使用掉所有disk space,当达到配额后,会删除最少使用的cache文件#
inactive #未被访问文件在缓存中保留时间,本配置中如果60分钟未被访问则不论状态是否为expired,缓存控制程序会删掉文件。inactive默认是10分钟。需要注意的是,inactive和expired配置项的含义是不同的,expired只是缓存过期,但不会被删除,inactive是删除指定时间内未被访问的缓存文件
use_temp_path #如果为off,则nginx会将缓存文件直接写入指定的cache文件中,而不是使用temp_path存储,official建议为off,避免文件在不同文件系统中不必要的拷贝
proxy_cache #启用proxy cache,并指定key_zone。另外,如果proxy_cache off表示关闭掉缓存。
一个简单的例子
下面分别配置源服务器和缓存服务器两步介绍
源服务器(Origin Server)是拥有真正的静态文件或动态生成的HTML的服务器。他们有两个责任:
- 请求时提供动态和静态内容
- 通过HTTP缓存头决定如何缓存文件(和潜在的动态内容)
缓存服务器(通常)是“前端”;它从客户端收到初始HTTP请求。然后它会处理请求本身(如果它具有所请求资源的新缓存副本),或者将请求传递给Origin Server来实现。
如果请求发送到Origin Server,则由Cache Server读取源服务器的响应头,以确定响应是缓存还是简单传递。
缓存服务器的职责:
- 确定HTTP请求是否接受缓存响应,并且判断在缓存中是否有新内容响应
- 如果请求不应被缓存,或者缓存的内容已经过期,则向源服务器发送HTTP请求
- 从缓存或者源服务器正确发送HTTP 响应给客户端
配置源服务器
在mac电脑上安装好Nginx之后在/usr/local/etc/nginx
目录下的nginx.conf文件加上如下配置。mac 上安装过程可以参考我的第一篇文章。
具体配置可以通过该链接下载,下载完成后放在/usr/local/etc/nginx
目录下面,为了方便测试大家可以在/usr/local/etc/nginx
新建css目录,找一个style.css放进去
打开nginx.conf可以看到如下配置
# cache.appcache, your document html and data
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
expires -1;
# access_log logs/static.log; # I don't usually include a static log
}
# CSS and Javascript
location ~* \.(?:css|js)$ {
root /usr/local/etc/nginx/;
expires 1y;
access_log off;
add_header Cache-Control "public";
}
首先解释一下location
中的expires
。expires
对应 http请求头中Cache-Control中的max-age
。expires 1y;
表示缓存一年。
第一个location配置表示以.html结尾的文件不会被缓存。 我们可以看到响应如下:
$ curl -X GET -I localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 19 Nov 2017 12:33:40 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 11 Jul 2017 13:24:27 GMT
Connection: keep-alive
ETag: "5964d18b-264"
Expires: Sun, 19 Nov 2017 12:33:39 GMT
Cache-Control: no-cache
Accept-Ranges: bytes
请注意,Expires与Date
相同,表示该请求立即到期,即告诉客户端不要缓存。 响应还返回头信息Cache-Control:no-cache
来表明不缓存响应内容。 遵循第一个location
配置。
现在请求css文件。
$ curl -X GET -I localhost:8080/css/style.css
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 19 Nov 2017 12:33:45 GMT
Content-Type: text/css
Content-Length: 5505
Last-Modified: Sun, 14 Feb 2016 14:09:20 GMT
Connection: keep-alive
ETag: "56c08a90-1581"
Expires: Mon, 19 Nov 2018 12:33:45 GMT
Cache-Control: max-age=31536000
Cache-Control: public
Accept-Ranges: bytes
我们可以看到这个css文件在当前日期的1年后过期! 缓存规则的设置max-age
(过期时间)大约为1年(以秒为单位),并允许公共缓存。 这也遵循了第二个location
规则。
至此,源服务器设置好了。
配置缓存服务器
源服务器已经设置完毕,但是我们需要在源服务器前面放置一个缓存服务器。 在我们的场景中,缓存服务器将作为Web服务器来接收请求。 如果缓存服务器不能直接从缓存里命中文件,则它会将HTTP请求传递给源服务器。
在配置缓存服务器之前,我们可以先看一下反向代理的“标准”设置。以下设置尚未配置任何缓存,它只是实现将请求代理到源服务器的功能:
具体配置可以通过该链接下载
server {
# Note that it's listening on port 8082
listen 8082 default_server;
root /var/www/;
index index.html index.htm;
server_name testcache.baidu.com;
charset utf-8;
location / {
# include proxy_params;
proxy_pass http://127.0.0.1:8080;
}
}
如果我们在缓存服务器上发出请求,就像直接发送请求到源服务器一样。 这是因为缓存服务器当前没有缓存:它只是将请求传递给源服务器:
请求结果如下
$ curl -X GET -I 127.0.0.1:8082/css/style.css
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 19 Nov 2017 13:06:55 GMT
Content-Type: text/css
Content-Length: 5505
Connection: keep-alive
Last-Modified: Sun, 14 Feb 2016 14:09:20 GMT
ETag: "56c08a90-1581"
Expires: Mon, 19 Nov 2018 13:06:55 GMT
Cache-Control: max-age=31536000
Cache-Control: public
Accept-Ranges: bytes
现在,我们添加必要的指令,实现从源服务器中获取Nginx缓存响应。 我们在上面定义的配置中,增加额外的缓存指令:
# Note that these are defined outside of the server block,
# altho they don't necessarily need to be
proxy_cache_path /tmp/nginx levels=1:2 keys_zone=my_zone:10m inactive=60m;
proxy_cache_key "$scheme$request_method$host$request_uri";
server {
# Note that it's listening on port 8082
listen 8082 default_server;
root /var/www/;
index index.html index.htm;
server_name testcache.baidu.com;
charset utf-8;
location / {
proxy_cache my_zone;
add_header X-Proxy-Cache $upstream_cache_status;
# include proxy_params;
proxy_pass http://127.0.0.1:8080;
}
}
上面有些配置在前面的第一节已经介绍过了,下面对没有解释过的条目进行说明。
proxy_cache_key
这是用来区分缓存文件的key。 默认值为$scheme$proxy_host$uri$is_args$args
,但是我们可以根据需要进行更改。
proxy_cache_key也可以设置为类似"$host$request_uri $cookie_user"
(带引号)这样的形式,也可以包括cookies信息。
Cookie确实会影响缓存,所以请谨慎设置! 如果Cookie被并入缓存密钥,您可能会意外地Nginx为每个独立cookie(每个站点访问者)都创建了重复缓存的文件。
这意味着将Cookie并入key确实会降低缓存的有效性。 针对每个用户的缓存,是私有缓存(Web浏览器)的目的,而不是我们正在构建的“公共”缓存服务器的目的。 但是,在某种情景下确实需要引入Cookie,那么proxy_cache_key的这个选项就很有用了。
我们还添加了一个有用的header(头信息)来通知我们资源是否从缓存提供。这可以通过add_header X-Proxy-Cache $ upstream_cache_status
指令完成。 这将设置一个名为X-Proxy-Cache
的响应头,值为HIT
,MISS
或 BYPASS
。
首次获取CSS文件
curl -X GET -I 127.0.0.1:8082/css/style.css
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 19 Nov 2017 13:19:02 GMT
Content-Type: text/css
Content-Length: 5505
Connection: keep-alive
Last-Modified: Sun, 14 Feb 2016 14:09:20 GMT
ETag: "56c08a90-1581"
Expires: Mon, 19 Nov 2018 13:19:02 GMT
Cache-Control: max-age=31536000
Cache-Control: public
X-Proxy-Cache: MISS
Accept-Ranges: bytes
因为之前没有请求过该文件,所以这里返回的cache状态为MISS。缓存服务器需要向源服务器请求资源。
再试一次:
curl -X GET -I 127.0.0.1:8082/css/style.css
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 19 Nov 2017 13:19:07 GMT
Content-Type: text/css
Content-Length: 5505
Connection: keep-alive
Last-Modified: Sun, 14 Feb 2016 14:09:20 GMT
ETag: "56c08a90-1581"
Expires: Mon, 19 Nov 2018 13:19:02 GMT
Cache-Control: max-age=31536000
Cache-Control: public
X-Proxy-Cache: HIT
Accept-Ranges: bytes
对比两个请求可以发现,两个请求的时间间隔差了5秒。我们可以通过X-Proxy-Cache
头信息看到缓存状态是HIT
。
Expires
头信息保持不变,因为Nginx只是从缓存中返回资源。 但是当缓存服务器返回到源服务器获取新文件时,那些头信息将会更新。
安装现在的设置,Nginx将忽略客户端的Cache-Control请求头。 但是,有些Web客户端不想使用缓存项目,我们希望缓存服务器能够支持这种要求。
例如,使用浏览器打开网页时,按住SHIFT,同时单击重新加载按钮,这时浏览器将发送一个Cache-Control: no-cache
。 这要求缓存服务器不提供资源的缓存版本。 但目前我们的设置会将之忽略
为了在请求时适当地绕过缓存,我们可以在location块中将proxy_cache_bypass $http_cache_control
指令添加到缓存服务器中:
curl -X GET -I -H "Cache-Control:no-cache" 127.0.0.1:8082/css/style.css
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 19 Nov 2017 14:25:40 GMT
Content-Type: text/css
Content-Length: 5505
Connection: keep-alive
Last-Modified: Sun, 14 Feb 2016 14:09:20 GMT
ETag: "56c08a90-1581"
Expires: Mon, 19 Nov 2018 14:25:40 GMT
Cache-Control: max-age=31536000
Cache-Control: public
X-Proxy-Cache: BYPASS
Accept-Ranges: bytes
可以看到X-Proxy-Cache: BYPASS
。说明直接透传到了源服务器。
proxy_cache_bypass
指令告知Nginx遵守HTTP请求中的Cache-Control请求头。
小结:
缓存可以大幅提升代理性能,不过配置缓存的时候需要注意以下几点。
首先,任何用户相关的数据不应该被缓存,否则可能导致一个用户的信息被另一个用户看到。当然如果你的网站是纯静态的,那就没有问题。
如果你的网站包含一些动态元素,则这点就需要留意。你如何处理这些元素的缓存,取决于应用处理后端进程的方式。对于私人信息,可以根据情况将Cache-Control header设置为no-cache、no-store或private:
- no-cache:请求应先到后端检查是否有变更,然后才返回给客户端。适用于动态的、重- 要的内容。对于每个请求,检查其ETag哈希元数据header,只有在后端返回了完全一致的哈希值的情况下才把缓存区内容返回给客户端。
- no-store:完全不在缓存区保存本内容。对于私人数据而言这是最安全的,这意味着每次都要从后端获取。
- private:不使用共享缓存。这意味着用户的浏览器可以缓存该数据,但代理服务器不可以。
- public:公开数据,可以随意缓存。
有一个max-age header可以控制此类缓存的保存时间,默认以秒计算。
正确的配置这些header,可以在确保私人信息安全、动态信息实时的前提下,还能享受到缓存的好处。
本文主要参考下面两篇英文原文
感谢阅读,这篇是Ngnix系列的最后一篇了,虽然nginx要学的东西还有很多,但是我觉得程序员能掌握好这四篇文章里的东西就足够应付平时的配置需求了(没必要看那本《深入理解Nginx》)。还有什么问题欢迎大家一起讨论交流。