nginx的反向代理及缓存

基本概念

  • 在反向代理和使用到缓存功能的时候,还会启动有两个进程cache loader和cache manager

    • cache loader的作用:

    • 检查缓存存储中的缓存对象

    • 使用缓存元数据建立内存数据库

    • cache manager的作用:缓存的失效,过期检验以及清理

nginx的反向代理模块

  • Module ngx_http_proxy_module

  • 配置文语法格式

    location /uri {
    proxy_pass http://back_sercer:port/newuri
    }
  • 简单示例

    location / {
    proxy_pass       http://localhost:8000;
    proxy_set_header Host      $host;
    proxy_set_header X-Real-IP $remote_addr;
    }
    • proxy_pass:表示只要用户访问'/'下的所有请求都反向代理到此处指定的url“http://localhost:8000”下

    • proxy_set_header:表示代理服务器nginx向后端服务器发送请求报文时的首部信息

    • Host:$host是请求报文中Host首部的值,后端服务器有可能使用虚拟主机,而nginx进行代理时,在proxy_pass上指定的是后端服务器的ip地址,所以请求的时候,可能是请求到默认的虚拟主机,而不是用户真正请求的虚拟主机,所以要指定该首部值

    • X-Real-IP:$remote_addr表示客户端的ip地址,由于是通过nginx进行代理,所以nginx将请求报文发送给后端服务器的源地址是nginx的地址,所以后端服务器记录日志时,其中的客户端ip始终是nginx的地址,然而我们分析日志时想要得到的是客户端的ip地址,因此要在请求报文首部中包含客户端的ip地址,服务器端记录日志时是记录该地址
  • 示例1:

    • 在nginx服务器(192.168.182.130)上编辑配置文件nginx.conf,内容如下

      http {
      server {
        listen       80;
        server_name  localhost;
        location / {
            #root   html;
            proxy_pass http://192.168.182.132/;
            index  index.html index.htm;
        }
      }
      }
    • 在后端服务器上(192.168.182.132)上开启web服务并编辑默认页面

      [root@backserver ~]# service httpd start
      [root@backserver ~]# vim /var/www/html/index.html
      #内容如下:
      page on backserver
    • 客户端进行访问测试,使用浏览器或者curl命令

      ~]# curl http://192.168.182.130
      page on backserver
    • 在后端服务器上查看记录的日志信息,会发现记录的客户端ip地址是nginx的地址
      [root@backserver ~]# tail -1 /var/log/httpd/access_log
      192.168.182.130 - - [10/Jun/2018:11:00:58 +0800] "GET / HTTP/1.0" 200 19 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
  • 示例2:还可以对指定目录进行反向代理,其他目录的访问仍然访问nginx的web服务

    • 编辑配置文件nginx.conf

      http {
      server {
      listen       80;
      server_name  localhost;
      location / {
          root   html;
          index  index.html index.htm;
      }
      location /forum/ {
          proxy_pass http://192.168.182.132/bbs/;
      }
      }
      }
    • 后端服务器在/var/www/html/bbs/目录下编写访问页面

      [root@backserver ~]# cat /var/www/html/bbs/index.html
      page on bbs
    • 测试:

  • 示例3:在示例2中要注意的是,如果使用正则表达式匹配,那么proxy_pass后面写的url只能写到'/'

    http {
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        location ~*  \.(jpg|png|gif)$ {
            proxy_pass http://192.168.182.132;
            #注意ip地址后面不能添加任何路径,‘/’也不可以,不然就是语法错误,如果图片路径在后端服务器的默认发布目录的某个目录下,那么只能够客户端访问的时候补全路径
        }
      }
    }
  • 示例4:将例2中添加proxy_set_header

    • 编辑配置文件nginx.conf

      location /forum/ {
      
          proxy_pass http://192.168.182.132/bbs/;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
      }
    • 修改后端服务器中的日志记录格式,将原来记录访问ip的%h修改成%{X-Real-IP}i
      [root@backserver html]# vim /etc/httpd/conf/httpd.conf
      内容如下:
      LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
      [root@backserver html]# tail -1 /var/log/httpd/access_log
      192.168.182.1 - - [10/Jun/2018:18:12:36 +0800] "GET /bbs/ HTTP/1.0" 304 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
      #可以看到将客户端的ip记录下来了
  • proxy_http_version:指定http协议版本,客户端发送给nginx的请求和nginx代理给后端服务器的请求有可能都是长连接的,而在nginx上是有缓存的,所以在nginx发送给服务器端的请求并不需要使用长连接,我们可以通过指定协议版本为1.0使得不具有长连接

    Syntax:proxy_http_version 1.0 | 1.1;
    Default:proxy_http_version 1.0;
    Context:http, server, location
  • proxy_cache_path:定义缓存文件路径,nginx的缓存是键值存储的,在内存空间中找一个地方进行存储,存储的键是hash过的url,值是该url对应的资源文件路径,而不是资源本身的内容,内容是存储在本地磁盘上,在磁盘上分为一级子目录,二级子目录,三级子目录

    Syntax:proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
    Default:—
    Context:http
    • max_size=size:指定path路径下最大可以使用多少空间进行缓存

    • 使用示例:levels是指定子目录的级数和相对应的子目录的个数,使用冒号隔开第一个表示一级子目录名的字符数,第二个表示支持二级子目录名字符数,如果还有一个冒号隔开的数字,那就对应三级子目录名字符数,根据字符数可以计算出子目录的个数

      proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;
      #keys_zone=one:10m表示在内存空间中找一个10m大小的空间命名为one来存放缓存信息
    • 在磁盘上的文件路径表示示例
      /data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c
      #可以看到一级目录只使用一个字符表示,二级目录使用2个数字表示,后面的文件名是经过hash的文件名
  • proxy_cache:使用缓存功能,zone就是上面提到的keys_zone选项指定的zone的名字

    Syntax: proxy_cache zone | off;
    Default:
    proxy_cache off;
    Context:    http, server, location
  • proxy_cache_methods:只有客户端请求的方法是该处指定的方法时才进行缓存

    Syntax: proxy_cache_methods GET | HEAD | POST ...;
    Default:
    proxy_cache_methods GET HEAD;
    Context:    http, server, location
  • proxy_cache_min_uses:指定某个请求至少要响应多少次才缓存下来

    Syntax: proxy_cache_min_uses number;
    Default:
    proxy_cache_min_uses 1;
    Context:    http, server, location
  • proxy_cache_purge:用来管理缓存空间,当缓存还没有过期,但是后端服务器已经将内容进行了更新,使用该选项就可以将用户请求的内容从缓存中删除,从而实现到后端服务器取新内容

    Syntax: proxy_cache_purge string ...;
    Default:    —
    Context:    http, server, location
    • 示例
      proxy_cache_path /data/nginx/cache keys_zone=cache_zone:10m;
      map $request_method $purge_method {
      PURGE   1;
      default 0;
      }
      server {
      ...
      location / {
        proxy_pass http://backend;
        proxy_cache cache_zone;
        proxy_cache_key $uri;
        proxy_cache_purge $purge_method;
      }
      }
  • proxy_cache_revalidate:过期后重新校验,缓存的内容如果过期了并且没有被cache-manager删除,使用该选项表示会向后端服务器询问该内容是否发生了改变,如果没有改变就使用该缓存的内容,如果改变了就从后端服务器取新内容

    Syntax: proxy_cache_revalidate on | off;
    Default:
    proxy_cache_revalidate off;
    Context:    http, server, location
  • proxy_cache_use_stale:当缓存内容过期了或者发生了改变,就要到后端服务器上取新内容,但是无法与后端服务器建立连接,此选项指定了在什么情况下使用过期缓存

    Syntax: proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | off ...;
    #表示当后端响应为error,timeout(nginx连接后端服务器超时),invalid_header,http_500,http_502,...的时候使用过期缓存
    Default:
    proxy_cache_use_stale off;
    Context:    http, server, location
  • proxy_cache_valid:根据不同响应码自定义缓存时长

    Syntax: proxy_cache_valid [code ...] time;
    Default:    —
    Context:    http, server, location
    • 示例
      proxy_cache_valid 200 302 10m; #响应码为200和302的缓存10分钟
      proxy_cache_valid 301      1h; #响应码为301的缓存1小时
      proxy_cache_valid any      1m; #剩余其他的响应码都缓存为1分钟
  • 示例:

    • 编辑配置文件nginx.conf

      http {
      proxy_cache_path  /cache/nginx/  levels=1:1:1 keys_zone=cache_one:32m;
      }
      location /forum/ {
            proxy_cache cache_one; #在该location中使用缓存
            proxy_cache_valid 200 302 10m;
            proxy_cache_valid 301      1h;
            proxy_cache_valid any      1m;
            proxy_cache_use_stale  error timeout invalid_header http_500 http_502 http_503 http_504;
            proxy_pass http://192.168.182.132/bbs/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP  $remote_addr;
        }
    • 创建缓存目录

      [root@centos6 html]# mkdir -p  /cache/nginx
      [root@centos6 html]# chown -R nginx.nginx /cache/nginx
    • 重新加载配置文件

      [root@centos6 html]# /usr/local/nginx/sbin/nginx -s reload
    • 客户端访问后就会发现在缓存目录下有缓存内容
      
      [root@centos6 4]# ls
      d023d5f3c58dab7e7d48ef927f7124b6
      [root@centos6 4]# pwd
      /cache/nginx/6/b/4
      [root@centos6 4]# cat d023d5f3c58dab7e7d48ef927f7124b6