nginx搭建静态缓存服务器

669 阅读4分钟

静态加速是CDN很主要的一个功能,静态缓存可以大大减少原站服务器的访问压力,提高用户的下载速度并且降低下载延迟。

编译

nginx的第三方模块ngx_cache_purge提供了静态缓存的功能,nginx使用1.18.0版本,编译如下:

git clone https://github.com/FRiCKLE/ngx_cache_purge
cd /worker/opensourcecode/nginx-1.18.0
./configure --add-module=/home/wanghao/worker/opensourcecode/nginx_module/ngx_cache_purge/ --with-debug
make -j 8 && make install

nginx配置文件

user  root;
worker_processes  4;

error_log  logs/debug.log  debug;   # 编译中开启了debug,这里可以输出debug日志了

events {
    worker_connections  1024;
}

worker_rlimit_core 10g;
working_directory /usr/local/nginx/logs;

http {
    #include       mime.types;
    #default_type  application/octet-stream;
    
    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
	
    # 静态缓存功能必要的配置
	proxy_temp_path /data/nginx_cache/proxy_temp;
	proxy_cache_path /data/nginx_cache/proxy_cache levels=1:2 keys_zone=cache_one:50m inactive=1d max_size=1g;
	proxy_connect_timeout 5;
	proxy_read_timeout 60;
	proxy_send_timeout 5;
	proxy_buffer_size 16k;
	proxy_buffers 4 64k;
	proxy_busy_buffers_size 128k;
	proxy_temp_file_write_size 128k;
	proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_404;
    
    upstream originserver
    {
        server 127.0.0.1:8080;  # 利用8080端口来模拟原站
    }
    
    server {
	    client_max_body_size 4G;
	    listen 80;
	    root /data;
		
		location ~ \.(gif|jpg|png|htm|html|css|js|flv|ico|swf)(.*) {
             proxy_pass http://originserver;         #如果没有缓存则通过proxy_pass转向请求
             proxy_redirect off;
             proxy_set_header Host $host;
             proxy_cache cache_one;
             proxy_cache_valid 200 302 1h; 		#对不同的HTTP状态码设置不同的缓存时间,h小时,d天数
             proxy_cache_valid 301 1d;
             proxy_cache_valid any 1m;
             expires 30d;
			 add_header host "nginx_proxy";
       }
	   
	   #purge插件缓存清理
	   location ~ /purge(/.*) {
		   allow              127.0.0.1;        #能够清除缓存的服务器IP地址
		   deny               all;
		   proxy_cache_purge  cache_one $1$is_args$args;
		}

    }
    
	server {
	    client_max_body_size 4G;
	    listen 127.0.0.1:8080;  # 原站服务器
	    root /data;
		
		location ~ \.(gif|jpg|png|htm|html|css|js|flv|ico|swf)(.*) {
    		autoindex on;
    		autoindex_exact_size on;
    		autoindex_localtime on;
            add_header host "originserver";
    	}	
    }
}

静态缓存功能的配置项说明,可以参考 blog.csdn.net/zhangjunli/…

使用curl进行测试

因为原站和nginx缓存服务器都部署再同一台设备上,缓存服务器访问原站是通过127.0.0.1的IP访问的,在测试的时候,你很难知道数据是从原站下载的还是从nginx代理服务器下载的。所以再测试时先对访问127.0.0.1(lo)本地环回口设置200ms的延迟。

tc qdisc add dev lo  root netem delay 200ms

此处也可以仅仅对lo口的8080端口设置延迟,但是,没查到如何设置。测试完成后记得要删除tc设置的规则

tc qdisc del dev lo root netem

第一次测试:

# time curl -L -v -H "Connection:close" "http://192.168.116.130:80/333.png" -o 333.png
*   Trying 192.168.116.130...
* TCP_NODELAY set
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.116.130 (192.168.116.130) port 80 (#0)
> GET /333.png HTTP/1.1
> Host: 192.168.116.130
> User-Agent: curl/7.58.0
> Accept: */*
> Connection:close
>
< HTTP/1.1 200 OK
< Server: nginx/1.18.0
< Date: Fri, 04 Sep 2020 12:33:28 GMT
< Content-Type: text/plain
< Content-Length: 1038692
< Connection: close
< Last-Modified: Sun, 16 Aug 2020 03:01:36 GMT
< ETag: "5f38a190-fd964"
< host: originserver
< Expires: Sun, 04 Oct 2020 12:33:28 GMT
< Cache-Control: max-age=2592000
< host: nginx_proxy
< Accept-Ranges: bytes
<
  0 1014k    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0{ [15754 bytes data]
100 1014k  100 1014k    0     0   359k      0  0:00:02  0:00:02 --:--:--  359k
* Closing connection 0

real    0m2.845s  # 可以看到花费的时间是2.8秒,很长了
user    0m0.000s
sys     0m0.063s

第一次测试real 0m2.845s 耗时约2.8秒

同步可以看到nginx的debug日志输出 connect to 127.0.0.1:8080,可以得知是代理服务器进行了回源。

2020/09/04 05:24:53 [debug] 15549#0: *2 connect to 127.0.0.1:8080, fd:17 #3
2020/09/04 05:24:53 [debug] 15549#0: accept on 127.0.0.1:8080, ready: 0

与此同时可以看到 /data/nginx_cache/proxy_cache 目录下

root@ubuntu:/data/nginx_cache/proxy_cache# find ./
./
./2
./2/71
./2/71/e6c8034119c0b548126eb2ddcfdef712

第二次测试:

# time curl -L -v -H "Connection:close" "http://192.168.116.130:80/333.png" -o 333.png
*   Trying 192.168.116.130...
* TCP_NODELAY set
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.116.130 (192.168.116.130) port 80 (#0)
> GET /333.png HTTP/1.1
> Host: 192.168.116.130
> User-Agent: curl/7.58.0
> Accept: */*
> Connection:close
>
< HTTP/1.1 200 OK
< Server: nginx/1.18.0
< Date: Fri, 04 Sep 2020 12:40:06 GMT
< Content-Type: text/plain
< Content-Length: 1038692
< Connection: close
< Last-Modified: Sun, 16 Aug 2020 03:01:36 GMT
< ETag: "5f38a190-fd964"
< host: originserver
< Expires: Sun, 04 Oct 2020 12:40:06 GMT
< Cache-Control: max-age=2592000
< host: nginx_proxy
< Accept-Ranges: bytes
<
{ [17236 bytes data]
100 1014k  100 1014k    0     0  45.0M      0 --:--:-- --:--:-- --:--:-- 47.1M
* Closing connection 0

real    0m0.049s  # 可以看到时间大大的减少了
user    0m0.016s
sys     0m0.016s

第二次测试可以看到 real 0m0.049s 耗时大大减少了

学习借鉴

1. nginx缓存目录的创建规则

源文件名字是333.png,缓存文件名字是e6c8034119c0b548126eb2ddcfdef712
在nginx.conf中levels=1:2配置的是2级的目录, 则真实的目录如下:

# find ./
./
./2
./2/71
./2/71/e6c8034119c0b548126eb2ddcfdef712

再仔细看目录是可以看到第一级目录取了最后一个字符,有16种情况,第二级目录取了最后两个字符,有255中情况。
这种根据取hash值的不同位置来创建目录的方法很常用,也很方便。知道原文件名字和哈希算法,就可以拼凑出路径来。

TODO

1. nginx缓存的文件比原始文件大一些

-rw-rw-rw- 1 root root 1038692 Sep  4 20:40 333.png
-rw------- 1 root root 1039322 Sep  4 05:33 ./2/71/e6c8034119c0b548126eb2ddcfdef712

该例子中静态缓存的文件比原始文件大了630个字节,测试了一些其他不同的图片文件,大约都是630字节左右。
通过Beyond Compare功能对比后,发现静态缓存文件是在原文件的头部插入了630个字节,应该是一些缓存文件的信息,后续需要需要阅读源码才能得出这个630个字节的详细信息

2. nginx缓存文件名字的生成规则

源文件名字是333.png,缓存文件名字是e6c8034119c0b548126eb2ddcfdef712,需要阅读源码看下生成文件名的规则。