NGINX代理和缓存功能


正向代理和反向代理

正向代理

简单理解,正向代理能够代表客户去访问互联网,它和NAT不同的是,NAT是4层的代理,而正向代理是7层的代理,所以用7层的代理效率不如NAT,但是它有个好处,就是能分析报文的应用层数据,举个简单例子,我想要禁止HTTP请求报文中包含"taobao"字样的报文,用NAT是实现不到的,而用代理则可以通过分析报文内容实现。

反向代理

和正向代理刚刚相反,正向代理是代表客户去访问互联网的服务器,反向代理则代表服务器提供服务。例如,我的网站部署了一台反向代理供互联网访问,那么客户访问反向代理服务器时,再由反向代理服务器转达客户的请求报文给背后真正的服务器,而后端的服务器响应也是响应给反向代理服务器,最后由反向代理服务器响应给客户端。

对于NGINX,正向和反向代理都支持,但普遍我们都是使用NGINX的反向代理功能,NGINX的代理功能都是由ngx_http_proxy_module模块提供。
再官方文档中有对该模块的各种指令的详细说明。

ngx_http_proxy_module

该模块默认已经安装,模块主要功能就是把请求传递给另一台服务器。它有很多的指令
附上模块指令手册地址:
http://nginx.org/en/docs/http/ngx_http_proxy_module.html

主要指令介绍:

proxy_pass

Syntax: proxy_pass URL;
Default:    —
Context:    location, if in location, limit_except

这指令应该是该模块的核心指令之一了,从字面意思能理解是定义代理到哪台服务器或哪个upstream池中的。它的常见用法如下:

proxy_pass http://localhost:8000/uri/;

注意:proxy_pass后面的路径不带uri时,其会将location的uri传递给后端主机;
例如:

server {
    ...
    server_name www.ilinux.io;
    location /pam/ {
    proxy http://10.1.1.11:80   
    }
    ...
    }
                

此时,访问www.ilinux.io/pam/时,实际上访问http://10.1.1.11:80/pam/

proxy_pass后面的路径是一个uri时,其会将location的uri替换为proxy_pass的uri;
例如:

server {
    ...
    server_name www.ilinux.io;
    location /pam/ {
    proxy http://10.1.1.11:80:/blog/ #则后端收到的是:http://10.1.1.11:80:/blog/ ,location的被替换掉了
    }
    ...
    }

总之,location的只是URL的表示方式,一旦location被匹配了,则执行{}里的内容,而{}的内容才是真正有效的配置。如上面的例子:
访问http://www.ilinux.io/pam/,而实际上真正访问的是http://10.1.1.11:80:/blog/

还有,如果location定义其uri时使用了正则表达式的模式,或在if语句或limt_execept中使用proxy_pass指令,则proxy_pass之后必须不能使用uri; 用户请求时传递的uri将直接附加代理到的服务的之后;
http://HOSTNAME/uri/ --> http://host/uri/;
例如:

server {
    ...
    server_name www.ilinux.io;
    location ~* \.jpg$ {
    proxy_pass http://10.1.1.11;
    }
    ...
    }

以上例子就PASS_pass就不能使用URI,例如访问:www.ilinux.io/blog/a.jpg,则实际上访问http://10.1.1.11/blog/a.jpg

proxy_set_header

该指令是设定发往后端主机的请求报文的请求首部的值,当需要反代到后端服务器时,有2个值默认被修改:
1:proxy_set_header Host $proxy_host;
2:proxy_set_header Connection close;

Syntax: proxy_set_header field value;
Default:    
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Context:    http, server, location

例如我需要把真正发起请求的客户端,把它的IP包含进请求头部中,然后反代给后端,在后端记录日志时,记录真正的客户端IP,则可以使用该指令配置。
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
下面这条只是记录转发的IP,因为反代可能有多级,如果有多级的情况下,下面这条记录的仅仅是上次转发的IP

默认在后端服务器上记录的是代理服务器的请求:

[root@node1 html]# tail /var/log/nginx/access.log 
10.1.1.99 - - [26/Jun/2018:11:32:55 +0800] "GET /test.html HTTP/1.0" 200 26 "-" "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0" "-"

配置反代NGINX,在发送请求时添加一个X_forward字段

[root@nginx_proxy ~]# vim /etc/nginx/conf.d/proxy.conf
server {
        listen 80;
        server_name www.ilinux.io;

        location / {
        proxy_pass http://10.1.1.11;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

}

然后配置后端服务器的日志格式
在默认情况下,main格式的日志已经把x_forward_for字段的内容包含上去了,只要在请求报文带上,再查看日志时就能看出

在客户端中测试,并在后端服务器上查看日志。

[root@node1 ~]# tail /var/log/nginx/access.log 

10.1.1.99 - - [26/Jun/2018:14:52:38 +0800] "GET /test.html HTTP/1.0" 200 26 "-" "curl/7.59.0" "192.168.30.148"

值得注意的是,像上面的例子我定义的字段为X-Forwarded-For,想要正常调用应该写成X_Forwarded_For 不知为何。。

proxy_hide_header

Syntax: proxy_hide_header field;
Default:    —
Context:    http, server, location

默认情况下,nginx不会传递标题字段“日期”、“服务器”、“X-Pad”和“X-Accel”。从一个代理服务器的响应到一个客户端。proxyhideheader指令设置了一些不会被传递的字段。相反,如果需要允许字段的传递,可以使用proxypassheader指令。

proxy_connect_timeout和proxy_read_timeout

Syntax: proxy_connect_timeout time;
Default:    
proxy_connect_timeout 60s;
Context:    http, server, location

反向代理面对服务侧的超时时间。发起方是proxy方,即等待握手成功的时间,3次握手。
而proxy_read_timeout则定义代理服务器和后端服务器的某一次传输完成以后,多久超时。例如设置为60s后,数据传输完成以后,60s内没有再次传输数据,则关闭连接。

proxy_send_timeout

Syntax: proxy_send_timeout time;
Default:    
proxy_send_timeout 60s;
Context:    http, server, location

设置一个超时,以便将请求发送到后端服务器。超时只设置在两个连续的写操作之间,而不是整个请求的传输,如果超过指定时间没收到后端服务器的数据,则断开连接,例如,proxy跟后端服务器正在传输数据,突然后端因为某原因挂了,proxy会一直在等,直到超过这个时间,才断开连接。

缓存

ngx_http_proxy自带了缓存功能,能对以下几种资源进行缓存:静态资源、日志、打开文件、动态资源。
NGinx的缓存功能的缺陷,摘自骏马金龙博客http://www.cnblogs.com/f-ck-need-u/p/7684732.html#2-nginx-

nginx的缓存功能主要用于缓存体积较小的页面资源,当数据较大时很容易出现瓶颈。在页面资源的缓存功能上,它属于业余玩家。而squid是科班出身,功能最全面,可以缓存大量数据,但架构太老,性能一般。varnish则是此类缓存的新贵,架构较新,内存管理完全交由操作系统内核,性能是squid的几倍之强,但缓存的内容不足squid

proxy_cache_path

定义可用于proxy功能的缓存路径,nginx的缓存一部分保存在内存上,一部分则保存在磁盘上,在磁盘上保存的缓存的URI名称和内容,所以,需要定义缓存保存的本地路径,在磁盘上保存的并不是缓存URI的名字,它的名字被哈希计算后作为CacheKEY,保存在内存的一张哈希表中,哈希表在内存中也有自己的名字,如果需要启用该缓存,则调用这个哈希表名字。

例如我在location / {}中使用了缓存,则请求匹配以后,它首先把请求的URL进行哈希计算,然后对比内存的中的哈希表,如果能在哈希表中找到,就根据该哈希的最右部分设定去指定目录下找该缓存。如果没有则

定义的相关指令主要有3个:proxy_cache_path、proxy_cache、proxy_cache_valid。要使用缓存,这3个指令都是需要配置的

proxy_cache_path

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

其中,proxy_cache_path path [levels=levels] keys_zone=name:size [max_size=size]一般都是需要配置项
path:定义缓存路径
levels:定义缓存的目录级别,同一也是目录的字符数量,最大3级目录,使用16进制命令,例如levels 2:2:2,定义了3级目录,每个目录为2个字符
keys_zone:定义缓存标识名称和内存中缓存的最大空间。name部分必须唯一,在后面会引用name来表示使用该缓存方法。
max_size:定义磁盘中缓存目录的最大空间。即path定义的文件最大空间

例如:

proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;

定义/data/nginx/cache为缓存的路径,2级目录结构,key_zone名字为one,大小为10M
/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c

proxy_cache

Syntax: proxy_cache zone | off;
Default:    
proxy_cache off;
Context:    http, server, location

指明要调用的缓存,或关闭缓存机制;

proxy_cache_valid

根据状态码来指定缓存有效期

proxy_cache_valid 200 302 1h;
proxy_cache_valid 404 1m;
proxy_cache_valid any 5m;

简单的缓存实验

在开始之前我先使用ab工具压测一下,我请求的资源是一个1M的图片资源


[root@localhost ~]# ab -n 2000 -c 200 http://www.ilinux.io/test.jpg



Server Software:        nginx/1.12.2
Server Hostname:        www.ilinux.io
Server Port:            80

Document Path:          /test.jpg
Document Length:        1244535 bytes

Concurrency Level:      200
Time taken for tests:   56.357 seconds
Complete requests:      2000
Failed requests:        0
Total transferred:      2489552000 bytes
HTML transferred:       2489070000 bytes
Requests per second:    35.49 [#/sec] (mean)


...


Requests per second: 没开启缓存时,每秒处理35个请求。

先在http上下文定义缓存路径

[root@nginx_proxy ~]# vim /etc/nginx/nginx.conf
http {


proxy_cache_path /data/web/nginx/cache levels=1:2 keys_zone=cache_one:10m max_size=1g;

 }

创建缓存目录与配置权限

[root@nginx_proxy ~]# mkdir /data/web/nginx/cache -pv
[root@nginx_proxy ~]# chown -R nginx:nginx /data

www.ilinux.io虚拟主机的location启用该缓存

server {
        listen 80;
        server_name www.ilinux.io;

        location / {
        proxy_pass http://10.1.1.11;
        proxy_cache cache_one;
        proxy_cache_valid any 5m;
        }

}

测试。

使用客户端访问资源后查看缓存情况

[root@localhost ~]# curl http://www.ilinux.io/test.jpg

[root@nginx_proxy cache]# ls
7

在proxy中已经存在把资源缓存下来了。

最后使用ab压测一下

[root@localhost ~]# curl http://www.ilinux.io/test.jpg
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
[root@localhost ~]# ab -n 2000 -c 200 http://www.ilinux.io/test.jpg

Server Software:        nginx/1.12.2
Server Hostname:        www.ilinux.io
Server Port:            80

Document Path:          /test.jpg
Document Length:        1244535 bytes

Concurrency Level:      200
Time taken for tests:   26.773 seconds
Complete requests:      2000
Failed requests:        0
Total transferred:      2489552000 bytes
HTML transferred:       2489070000 bytes
Requests per second:    74.70 [#/sec] (mean)


能看到开启了缓存之后,每秒处理请求为74.7个,和没开启缓存相比,性能提高了一倍。

其他的缓存指令

proxy_cache_key

Syntax: proxy_cache_key string;
Default:    
proxy_cache_key $scheme$proxy_host$request_uri;
Context:    http, server, location

定义缓存的键,简单来讲就是以什么做键,默认是以:schemeproxy_host$request_uri;定义的层级越高,越难命中,但是越准确。
例如我只把request_uri做键可以这样做:

[root@nginx_proxy cache]# vim /etc/nginx/conf.d/proxy.conf 
server {
        listen 80;
        server_name www.ilinux.io;

        location / {
        proxy_pass http://10.1.1.11;
        proxy_cache cache_one;
        proxy_cache_valid any 5m;
        proxy_cache_key $request_uri; 
        }

}

这样,如果有请求时候,则只使用request_uri的哈希来匹配,这样的有点后遗症,例如有2台虚拟主机,有相同的资源名称,则该URI的缓存就适用用2台虚拟主机了,这样会出现缓存不准确的情况。有利弊

可以通过查看缓存来查看该缓存键值,例如:

[root@nginx_proxy cache]# cat c/97/5804fd1475122d946b51ef022d2cb97c                                2"5b31b1c3-1a"
KEY: /test.html
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Tue, 26 Jun 2018 09:26:58 GMT
Content-Type: text/html
Content-Length: 26
Last-Modified: Tue, 26 Jun 2018 03:23:47 GMT
Connection: close
ETag: "5b31b1c3-1a"
Accept-Ranges: bytes

KEY:后跟的就是键,用于匹配缓存的是否命中的依据

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 ...;
Default:    proxy_cache_use_stale 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
This directive appeared in version 0.7.59.

默认情况下GET和HEAD方法会缓存内容,可以使用该指令来增加其他方法,但一般情况下不修改。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容