一、缓冲

         在反向代理场景中,nginx有一系列指令可用于定义其工作特性,如缓冲区大小等,给这些指令设定一个合理的值,可以有效提升其性能。

        nginx在默认情况下在将其响应给客户端之前会尽可能地接收来upstream服务器的响应报文,它会将这些响应报文存暂存于本地并尽量一次性地响应给客户端。然而,在来自于客户端的请求或来自upsteam服务器的响应过多时,nginx会试图将之存储于本地磁盘中,这将大大降低nginx的性能。因此,在有着更多可用内存的场景中,应该将用于暂存这些报文的缓冲区调大至一个合理的值。

1、proxy_buffer_size size

         proxy_buffer_size 用来接受后端服务器 response 的第一部分,小的response header 通常位于这部分响应内容里边。默认proxy_buffer_size 被设置成 proxy_buffers 里一个buffer 的大小,当然可以设置更小些。

  ① 如果 proxy_buffers 关闭

        Nginx不会尝试获取到后端服务器所有响应数据之后才返回给客户端,Nginx 会尽快把数据传给客户端,在数据传完之前,Nginx 接收到的最大缓存大小不能超过 proxy_buffer_size 。

  ② 如果 proxy_buffers 打开

        Nginx将会尽可能的读取后端服务器的数据到buffer,直到proxy_buffers设置的所有buffer们被写满或者数据被读取完(EOF),此时Nginx开始向客户端传输数据,会同时传输这一整串buffer们。如果数据很大的话,Nginx会接收并把他们写入到temp_file里去,大小由proxy_max_temp_file_size 控制。「当数据没有完全读完的时候」,Nginx同时向客户端传送的buffer 大小 不能超过 proxy_busy_buffers_size 「此句可能理解有误」。



Syntax:proxy_buffer_size size;
Default:
proxy_buffer_size 4k|8k;
Context:httpserverlocation


2、proxy_buffering on|off

   启用缓冲upstream服务器的响应报文,否则,如果proxy_max_temp_file_size指令的值为0,来自upstream服务器的响应报文在接收到的那一刻将同步发送至客户端;一般情况下,启用proxy_buffering并将proxy_max_temp_file_size设定为0能够启用缓存响应报文的功能,并能够避免将其缓存至磁盘中;



Syntax:proxy_buffering on | off;
Default:
proxy_buffering on;
Context:httpserverlocation

proxy_buffering 开启的时候,proxy_buffers 和proxy_busy_buffers_size 才会起作用,无论proxy_buffering 是否开启,proxy_buffer_size 都起作用。



3、proxy_max_temp_file_size

Syntax:proxy_max_temp_file_size size;
Default:
proxy_max_temp_file_size 1024m;
Context:httpserverlocation


4、proxy_buffers

    用于缓冲来自upstream服务器个数和大小;


Syntax:proxy_buffers number size;
Default:
proxy_buffers 8 4k|8k;
Context:httpserverlocation



5、proxy_busy_buffers_size


Syntax:proxy_busy_buffers_size size;
Default:
proxy_busy_buffers_size 8k|16k;
Context:httpserverlocation



6、buffer工作原理

  1) 所有的proxy buffer参数是作用到每一个请求的。每一个请求会安按照参数的配置获得自己的buffer。proxy buffer不是global而是per request的。

  2) proxy_buffering 是为了开启response buffering of the proxied server,开启后proxy_buffers和proxy_busy_buffers_size参数才会起作用。

  3)无论proxy_buffering是否开启,proxy_buffer_size(main buffer)都是工作的,proxy_buffer_size所设置的buffer_size的作用是用来存储upstream端response的header。

  4) 在proxy_buffering 开启的情况下,Nginx将会尽可能的读取所有的upstream端传输的数据到buffer,直到proxy_buffers设置的所有buffer们 被写满或者数据被读取完(EOF)。此时nginx开始向客户端传输数据,会同时传输这一整串buffer们。同时如果response的内容很大的 话,Nginx会接收并把他们写入到temp_file里去。大小由proxy_max_temp_file_size控制。如果busy的buffer 传输完了会从temp_file里面接着读数据,直到传输完毕。

  5)一旦proxy_buffers设置的buffer被写入,直到buffer里面的数据被完整的传输完(传输到客户端),这个buffer将会一直处 在busy状态,我们不能对这个buffer进行任何别的操作。所有处在busy状态的buffer size加起来不能超过proxy_busy_buffers_size,所以proxy_busy_buffers_size是用来控制同时传输到客户 端的buffer数量的。


二、缓存

        nginx做为反向代理时,能够将来自upstream的响应缓存至本地磁盘(也可以缓存在缓存服务器中,如memcached),并在后续的客户端请求同样内容时直接从本地构造响应报文。

1、proxy_cache

Syntax:proxy_cache zone | off;
Default:
proxy_cache off;
Context:httpserverlocation

   定义一个用于缓存的共享内存区域(内存中存储的是哈希表,缓存还是存储在磁盘上,只是为了快速检索),其可被多个地方调用;

缓存将遵从upstream服务器的响应报文首部中关于缓存的设定:

    如 "Expires""Cache-Control:no-cache" "Cache-Control:max-age=XXX""private""no-store" 等,但nginx在缓存时不会考虑响应报文的"Vary"首部。为了确保私有信息不被缓存,所有关于用户的私有信息可以upstream上通过"no-cache" or "max-age=0"来实现,也可在nginx设定proxy_cache_key必须包含用户特有数据如$cookie_xxx的方式实现,但最后这种方式在公共缓存上使用可能会有风险。因此,

在响应报文中含有以下首部或指定标志的报文将不会被缓存:

Set-Cookie

Cache-Control containing "no-cache","no-store","private",or  a  "max-age"  with a non-numeric or  0 value,Expires  with a time in the past (Expires 指定一个过去的时间)

X-Accel-Expires:0


2、proxy_cache_path

Syntax:proxy_cache_path path [levels=levels] [use_temp_path=on|offkeys_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
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;

    proxy_cache_path定义一个用于保存缓存响应报文的目录,及一个保存缓存对象的键(就是proxy_cache 定义的zone)及响应元数据的共享内存区域(keys_zone=name:size)

其可选参数有:

levels:

    每级子目录名称的长度,有效值为1或2,每级之间使用冒号分隔,最多为3级;

例如:levels=1:1:2  

      表示缓存目录是3层结构(最多只能有3层),1级目录名是1个16进制的字符(那1级目录就有16个),2级目录名1个字符并且有16个,3层目录名2个字符并且有256个

inactive:

     非活动缓存项从缓存中剔除之前的最大缓存时长;

max_size:

     缓存空间大小的上限(磁盘中的文件),当需要缓存的对象超出此空间限定时,缓存管理器将基于LRU算法对其进行清理;

loader_files:

     缓存加载器(cache_loader)的每次工作过程最多为多少个文件加载元数据;

loader_sleep:

     缓存加载器的每次迭代工作之后的睡眠时长;

loader_threashold:

     缓存加载器的最大睡眠时长;

例如:  

proxy_cache_path  /data/nginx/cache/one    levels=1      keys_zone=one:10m;
proxy_cache_path  /data/nginx/cache/two    levels=2:2    keys_zone=two:100m;
proxy_cache_path  /data/nginx/cache/three  levels=1:1:2  keys_zone=three:1000m;


3、proxy_cache_min_uses

     某响应报文被缓存之前至少应该被请求的次数;

Syntax:proxy_cache_min_uses number;
Default:
proxy_cache_min_uses 1;
Context:httpserverlocation


4、proxy_cache_use_stale

    在无法联系到upstream服务器时的哪种情形下(errortimeouthttp_500)nginx使用本地缓存的过期的缓存对象直接响应客户端请求;

Syntax:proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 |http_503 | http_504 | http_403 | http_404 | off ...;
Default:
proxy_cache_use_stale off;
Context:httpserverlocation


5、proxy_cache_methods

      为哪些请求方法启用缓存功能;


Syntax:proxy_cache_methods GET | HEAD | POST ...;
Default:
proxy_cache_methods GET HEAD;
Context:httpserverlocation


6、proxy_cache_bypassstring

    设定在哪种情形下,nginx将不从缓存中取数据;

Syntax:proxy_cache_bypass string ...;
Default:
Context:httpserverlocation

例如:

proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass $http_pragma $http_authorization;


7、proxy_cache_valid

    用于为不同的响应码设定不同时长的有效缓存时长,

Syntax:proxy_cache_valid [code ...] time;
Default:
Context:httpserverlocation

Sets caching time for different response codes. For example, the following directives

proxy_cache_valid 200 302 10m;
proxy_cache_valid 404      1m;

set 10 minutes of caching for responses with codes 200 and 302 and 1 minute for responses with code 404.

If only caching time is specified

proxy_cache_valid 5m;

then only 200, 301, and 302 responses are cached.

In addition, the any parameter can be specified to cache any responses:

proxy_cache_valid 200 302 10m;
proxy_cache_valid 301      1h;
proxy_cache_valid any      1m;


8、其它不常用的指令

   proxy_cache_key     # 很少用

Syntax:proxy_cache_key string;
Default:
proxy_cache_key $scheme$proxy_host$request_uri;
Context:httpserverlocation

Defines a key for caching, for example

proxy_cache_key "$host$request_uri $cookie_user";

    设定在存储及检索缓存时用于的字符串,可以使用变量为其值,但使用不当时有可能会为同一个内容缓存多次;另外,将用户私有信息用于键可以避免将用户的私有信息返回给其它用户;


   proxy_cache_lock     # 很少用

    用此项,可在缓存未命令中阻止多个相同的请求同时发往upstream,其生效范围为worker级别;


  proxy_cache_lock_timeout     # 很少用

    proxy_cache_lock功能的锁定时长;


proxy_cache_path 的使用

  1)先在主配置文件的http段定义proxy_cache_path

        proxy_cache_path  /cache/nginx/   levels=1:1  keys_zone=mycache(名字):32m(大小);   

                                                                                                                       # 只能在http段中定义

                    缓存路径(属主,属组要是nginx 1级子目录的字符个数:2级子目录的字符个数

 2)在server和location段中调用

          proxy_cache  mycache(缓存目录名);


使用示例:

http {
    proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=STATIC:10m inactive=24h max_size=1g;
    server {
       add_header X-Via $server_addr;    
       add_header X-Cache $upstream_cache_status;
       
        location / {
            proxy_pass          http://www.magedu.com;
            proxy_set_header       Host $host;
            proxy_cache          STATIC;
            proxy_cache_valid       200 1d;
            proxy_cache_valid          301 302 10m;
            proxy_cache_valid         any 1m;
            proxy_cache_use_stale  error timeout invalid_header updating
                                     http_500 http_502 http_503 http_504;
        }
    }
}


proxy_cache_purge  

    缓存修剪方法,被请求的缓存将被删除,

Syntax:proxy_cache_purge string ...;
Default:
Context:httpserverlocation

This directive appeared in version 1.5.7.

 

Example configuration:

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

    本地缓存过期后重新效验

Syntax:proxy_cache_revalidate on | off;
Default:
proxy_cache_revalidate off;
Context:httpserverlocation

This directive appeared in version 1.5.7.

Enables revalidation of expired cache items using conditional requests with the “If-Modified-Since” and “If-None-Match” header fields.


三、upstream模块中常用的变量

     主要用于自定义响应首部中的值

$upstream_addr

    响应请求的后端服务器的ip 


$upstream_cache_status

 keeps the status of accessing a response cache (0.8.3). The status can be either “MISS”, “BYPASS”, “EXPIRED”, “STALE”, “UPDATING”, “REVALIDATED”, or “HIT”.

自定义响应首部:

     add_header  X-Via  $server_addr;      

                        在响应报文中添加自定义首部;向客户端说明经过的代理服务器的ip

          add_header  X-Cache $upstream_cache_status;     # 前提当前要启用缓存咯

                         查看是否缓存命中


实例:

   proxy_cache_path /etc/nginx/cache levels=1:2 keys_zone=one:126m; 

   proxy_cache one;
   proxy_cache_valid any 1m;
  
   add_header X-Via $server_addr;
   add_header X-cache $upstream_cache_status;

server {
    root /www/c.net;
    server_name www.c.net;
  
    location / {
        proxy_pass http://192.168.10.5/;
          } 
    
   location ~* \.php$|status|ping {
            root /data/htdocs2;
            fastcgi_pass   192.168.10.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
            include        fastcgi_params;
                 }
      }

测试:

wKiom1jHdKrSbTzNAACHjc1WH_I366.png



四、一个完整配置例

user                  nobody nobody;
worker_processes                  4;
worker_rlimit_nofile              51200;

error_log                         logs/error.log  notice;

pid                               /var/run/nginx.pid;

events {
  use                             epoll;
  worker_connections              51200;
}

http {
  server_tokens                   off;          
  include                         mime.types;
  proxy_redirect                off;
  proxy_set_header              Host   $host;  
  proxy_set_header              X-Real-IP $remote_addr;
  proxy_set_header              X-Forwarded-For $proxy_add_x_forwarded_for; 
  client_max_body_size          20m;   # 客户端包体单个大小最大为20m
  client_body_buffer_size       256k;  # 内存中缓存的大小
  proxy_connect_timeout         90;    # 连接后端服务器超时时间
  proxy_send_timeout            90;    # 后端服务器发送响应报文超时时间
  proxy_read_timeout            90;    # 读取...
  proxy_buffer_size             128k;
  proxy_buffers                 4 64k;
  proxy_busy_buffers_size       128k;
  proxy_temp_file_write_size    128k;

  default_type                    application/octet-stream;
  charset                         utf-8;
  
  client_body_temp_path           /var/tmp/client_body_temp 1 2;
  proxy_temp_path                 /var/tmp/proxy_temp 1 2;
  fastcgi_temp_path               /var/tmp/fastcgi_temp 1 2;
  uwsgi_temp_path                 /var/tmp/uwsgi_temp 1 2;
  scgi_temp_path                  /var/tmp/scgi_temp 1 2;

  ignore_invalid_headers          on;
  server_names_hash_max_size      256;   
  server_names_hash_bucket_size   64;
  client_header_buffer_size       8k;
  large_client_header_buffers     4 32k;
  connection_pool_size            256;
  request_pool_size               64k;

  output_buffers                  2 128k;
  postpone_output                 1460;

  client_header_timeout           1m;
  client_body_timeout             3m;
  send_timeout                    3m;


  log_format main                 '$server_addr $remote_addr [$time_local] $msec+$connection '
                                  '"$request" $status $connection $request_time $body_bytes_sent "$http_referer" '
                                  '"$http_user_agent" "$http_x_forwarded_for"';

  open_log_file_cache               max=1000 inactive=20s min_uses=1 valid=1m;

  access_log                      logs/access.log      main;
  log_not_found                   on;


  sendfile                        on;
  tcp_nodelay                     on;
  tcp_nopush                      off;

  reset_timedout_connection       on;
  keepalive_timeout               105;
  keepalive_requests              100;


  gzip                            on;
  gzip_http_version               1.1;
  gzip_vary                       on;
  gzip_proxied                    any;
  gzip_min_length                 1024;
  gzip_comp_level                 6;
  gzip_buffers                    16 8k;
  gzip_proxied                    expired no-cache no-store private auth no_last_modified no_etag;
  gzip_types                      text/plain application/x-javascript text/css application/xml application/json;
  gzip_disable                    "MSIE [1-6]\.(?!.*SV1)";


  upstream tomcat8080 {
    ip_hash;

    server                        172.16.100.103:8080 weight=1 max_fails=2;
    server                        172.16.100.104:8080 weight=1 max_fails=2;
    server                        172.16.100.105:8080 weight=1 max_fails=2;
  }

  server {
    listen                        80;
    server_name                   www.magedu.com;
    # config_apps_begin
    root                          /data/webapps/htdocs;
    access_log                    /var/logs/webapp.access.log     main;
    error_log                     /var/logs/webapp.error.log      notice;

    location / {
    
      location ~* ^.*/favicon.ico$ {
        root                      /data/webapps;
        expires                   180d;
        break;
      }
    
      if ( !-f $request_filename ) {
        proxy_pass                http://tomcat8080;
        break;
      }
    }

    error_page                    500 502 503 504  /50x.html;
      location = /50x.html {
      root                        html;
    }
  }

  server {
    listen                        8088;
    server_name                   nginx_status;

      location / {
          access_log                  off;
          deny                        all;
          return                      503;
      }

      location /status {
          stub_status                 on;
          access_log                  off;
          allow                       127.0.0.1;
          allow                       172.16.100.71;
          deny                        all;
      }
  }

}