nginx常用模块了解及使用
nginx常用模块介绍及使用
对客户端进行限制相关配置-预防攻击
一般是下面的需求:
秒杀、抢购并发限制
防止攻击
limit_req_zone
用来限制单位时间内的请求数,即速率限制,采用的漏桶算法
nginx限制请求数 limit_req_zone
语法: limit_req_zone $variable zone=name:size rate=rate;
默认值: none
配置段: http
例子:limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
Zone=one 表示设置了名为“one”,大小为10兆字节
rate=10r/s 的意思是允许1秒钟不超过10个请求
使用$binary_remote_addr变量,可以将每条状态记录的大小减少到64个字节,这样1M的内存可以保存大约1万6千个64字节的记录。
如果限制域的存储空间耗尽了,对于后续所有请求,服务器都会返回 503 (Service Temporarily Unavailable)错误。
速度可以设置为每秒处理请求数和每分钟处理请求数,其值必须是整数,所以如果你需要指定每秒处理少于1个的请求,2秒处理一个请求,可以使用 “30r/m”。
可选参数:
rate=10r/s 的意思是允许1秒钟不超过10个请求
burst=5 允许超过频率限制的请求数不多于5个,假设1、2、3、4秒请求为每秒9个,那么第5秒内请求15个是允许的,反之,如果第一秒内请求15个,会将5个请求放到第二秒,第二秒内超过10的请求直接503,类似多秒内平均速率限制。
nodelay 超过的请求不被延迟处理,设置后15个请求在1秒内处理。
关于漏桶算法
漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率.示意图如下:
可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)
IP访问控制模块 ( http_access_module)
用来对特定IP的进行访问控制
默认是允许所有ip访问,若部分允许需定义 deny all
allow
语法: allow address | CIDR | unix: | all;
默认值: —
区块: http, server, location, limit_except
允许某个ip或者一个ip段访问
deny
语法: deny address | CIDR | unix: | all;
默认值: —
区块: http, server, location, limit_except
allow、deny实例
location / {
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 47.98.147.49;
deny all;
}
比如可以限制某些目录下的某些文件的访问,具体可以自己组合
禁止访问所有目录下的 sql|log|txt|jar|sh|py
后缀的文件,
location ~.*\.(sql|log|txt|jar|war|sh|py|php) {
deny all;
}
案例:IP黑白名单设置
连接限制跟请求限制,会对所有的ip进行限制,我们不希望自己的测试的ip,或者搜索引擎蜘蛛受到限制
ngx_http_geo_module
模块创建变量,并根据客户端IP地址对变量赋值
语法: | geo [variable { ... } |
---|---|
默认值: | — |
上下文: | http |
语法: | map string $variable { ... } |
---|---|
默认值: | — |
上下文: | http |
map 指令是由 ngx_http_map_module 模块提供的,默认情况下安装 nginx 都会安装该模块。
map 的主要作用是创建自定义变量,通过使用 nginx 的内置变量,去匹配某些特定规则,如果匹配成功则设置某个值给自定义变量。 而这个自定义变量又可以作于他用。
类似编程语言的switch case
map $http_user_agent $mobile { #这个含义就是 当$http_user_agent 值 = "~Opera Mini" 那么我们就将 $mobile值设置为 1 否则就设置为 0
default 0;
"~Opera Mini" 1;
}
请求失败的结果
ab -n20 -c10 http://127.0.0.1/
rewrite模块(ngx_http_rewrite_module)
rewrite
的主要功能是实现URL地址的重定向。Nginx
的rewrite
功能需要PCRE软件的支持,即通过perl兼容正则表达式语句进行规则匹配的。默认参数编译nginx
就会支持rewrite
的模块,但是也必须要PCRE的支持。
使用场景:
1、可以调整用户浏览的URL,看起来更规范,合乎开发及产品人员的需求。
2、为了让搜索引擎搜录网站内容及用户体验更好,企业会将动态URL地址伪装成静态地址提供服务。
3、网址换新域名后,让旧的访问跳转到新的域名上。例如,访问京东的360buy.com会跳转到jd.com
4、根据特殊变量、目录、客户端的信息进行URL调整等
if指令
语法:if(condition){…}
区块:server,location
该指令用于检查一个条件是否符合,如果条件符合,则执行大括号内的语句。if指令不支持嵌套,不支持多个条件&&和||处理。
其中,condition中可以包含的判断标识如下
~为区分大小写匹配
~*为不区分大小写匹配
-f和!-f用来判断是否存在文件
-d和!-d用来判断是否存在目录
-e和!-e用来判断是否存在文件或目录
-x和!-x用来判断文件是否可执行
if ($http_user_agent~*(mobile|nokia|iphone|ipad|android|samsung|htc|blackberry)) {
rewrite ^(.*) http://peter.23673.com$1 permanent;
}
return指令
语法:return code [text]
return code URL;
return URL;
区块:server,location,if
该指令用于结束规则的执行并返回状态吗给客户端。
状态码包括:
204(No Content)、400(Bad Request)、402(Payment Required)、403(Forbidden)
404(Not Found)、405(Method Not Allowed)、406(Not Acceptable)、
408(Request Timeout)、410(Gone)、411(Length Required)、
413(Request Entity Too Large)、416(Requested Range Not Satisfiable)、
500(Internal Server Error)、501(Not Implemented)、502(Bad Gateway)、
503(Service Unavailable)和504(Gateway Timeout)。
例如,示例,如果访问的URL以.sh .bash 结尾,返回状态码403
location ~ .*\.(sh|bash)?$
{
return 403;
}
Rewrite语法
语法:rewrite regex replacement [flag];
默认值:—
上下文:server, location, if
rewrite是实现URL重写的关键指令,根据regex(正则表达式)部分内容,重定向到replacement,结尾是flag标记。
正则:perl兼容正则表达式语句进行规则匹配
替代内容:将正则匹配的内容替换成replacement
flag标记:rewrite支持的flag标记
last标记说明:
last #本条规则匹配完成后,继续向下匹配新的location URI规则
结束当前的请求处理,用替换后的URI重新匹配location;
可理解为重写(rewrite)后,发起了一个新请求,进入server模块,匹配locaton;
如果重新匹配循环的次数超过10次,nginx会返回500错误;
break #本条规则匹配完成即终止,不再匹配后面的任何规则
结束当前的请求处理,使用当前资源,不在执行location里余下的语句
redirect #返回302临时重定向,浏览器地址会显示跳转后的URL地址
permanent #返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
案例:Nginx 重写 url实现伪静态
商品页面
goods-3.html ---->goods.php?id=3
# 栏目页面
/ecshop/category-2-b1.html -> /ecshop/category.php?id=3&brand=1
nginx防盗链实现
语法: valid_referers none | blocked | server_names | string ...;
默认值: —
上下文: server, location
“Referer”请求头为指定值时,内嵌变量$invalid_referer被设置为空字符串, 否则这个变量会被置成“1”。查找匹配时不区分大小写。
该指令的参数可以为下面的内容:
none
缺少“Referer”请求头;
blocked
“Referer” 请求头存在,但是它的值被防火墙或者代理服务器删除; 这些值都不以“http://” 或者 “https://”字符串作为开头;
server_names
“Referer” 请求头包含某个虚拟主机名;
防止别人直接从你网站引用图片等链接,消耗了你的资源和网络流量,那么我们的 就可以设置防盗链策略下面的方法是直接给予404的错误提示,或者是显示一个图片
location ~* ^.+\.(jpg|gif|png|swf|flv|wma|wmv|asf|mp3|mmf|zip|rar)$ {
valid_referers none blocked www.23673.com 23673.com;
if ($invalid_referer) {
#return 302 http://nginx.23673.com/img/nolink.jpg;
return 404;
break;
}
nginx内置变量说明
Nginx
同 Apache
和 Lighttpd
等其他 Web
服务器的配置记法不太相同,Nginx
的配置文件使用语法的就是一门微型的编程语言。可以类似写程序一般编写配置文件,可操作性很大。既然是编程语言,一般也就少不了“变量”这种东西。
所有的 Nginx
变量在 Nginx
配置文件中引用时都须带上 $ 前缀在 Nginx
配置中,变量只能存放一种类型的值,有且也只存在一种类型,那就是字符串类型
使用 set 配置指令对变量 $a 进行了赋值操作
set $hello "hello world"
;
Nginx
变量一旦创建,其变量名的可见范围就是整个 Nginx
配置,甚至可以跨越不同虚拟主机的 server
配置块
Nginx
变量名的可见范围虽然是整个配置,但每个请求都有所有变量的独立副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰
Nginx
内置变量
内置变量存放在 ngx_http_core_module
模块中
参数名称 | 注释 |
---|---|
$arg_PARAMETER HTTP | 请求中某个参数的值,如/index.php?site=www.ttlsa.com,可以用$arg_site取得www.ttlsa.com这个值. |
$args HTTP | 请求中的完整参数。例如,在请求/index.php?width=400&height=200 中,$args表示字符串width=400&height=200. |
$binary_remote_addr | 二进制格式的客户端地址。例如:\x0A\xE0B\x0E |
$body_bytes_sent | 表示在向客户端发送的http响应中,包体部分的字节数 |
$content_length | 表示客户端请求头部中的Content-Length 字段 |
$content_type | 表示客户端请求头部中的Content-Type 字段 |
$cookie_COOKIE | 表示在客户端请求头部中的cookie 字段 |
$document_root | 表示当前请求所使用的root 配置项的值 |
$uri | 表示当前请求的URI,不带任何参数 |
uri | 含义相同 |
$request_uri | 表示客户端发来的原始请求URI,带完整的参数。document_uri未必是用户的原始请求,在内部重定向后可能是重定向后的URI,而$request_uri 永远不会改变,始终是客户端的原始URI. |
$host | 表示客户端请求头部中的Host字段。如果Host字段不存在,则以实际处理的server(虚拟主机)名称代替。如果Host字段中带有端口,如IP:PORT,那么host 是全小写的。这些特性与http_HEADER中的http_host不同,http_host只取出Host头部对应的值。 |
$hostname | 表示 Nginx所在机器的名称,与 gethostbyname调用返回的值相同 |
$http_HEADER | 表示当前 HTTP请求中相应头部的值。HEADER名称全小写。例如,示请求中 Host头部对应的值 用 $http_host表 |
$sent_http_HEADER | 表示返回客户端的 HTTP响应中相应头部的值。HEADER名称全小写。例如,用 $sent_ http_content_type表示响应中 Content-Type头部对应的值 |
$is_args | 表示请求中的 URI是否带参数,如果带参数,$is_args值为 ?,如果不带参数,则是空字符串 |
$limit_rate | 表示当前连接的限速是多少,0表示无限速 |
$nginx_version | 表示当前 Nginx的版本号 |
$query_string | 请求 URI中的参数,与 query_string是只读的不会改变 |
$remote_addr | 表示客户端的地址 |
$remote_port | 表示客户端连接使用的端口 |
$remote_user | 表示使用 Auth Basic Module时定义的用户名 |
$request_filename | 表示用户请求中的 URI经过 root或 alias转换后的文件路径 |
$request_body | 表示 HTTP请求中的包体,该参数只在 proxy_pass或 fastcgi_pass中有意义 |
$request_body_file | 表示 HTTP请求中的包体存储的临时文件名 |
$request_completion | 当请求已经全部完成时,其值为 “ok”。若没有完成,就要返回客户端,则其值为空字符串;或者在断点续传等情况下使用 HTTP range访问的并不是文件的最后一块,那么其值也是空字符串。 |
$request_method | 表示 HTTP请求的方法名,如 GET、PUT、POST等 |
$scheme 表示 HTTP scheme, | 如在请求 https://nginx.com/中表示 https |
$server_addr | 表示服务器地址 |
$server_name | 表示服务器名称 |
$server_port | 表示服务器端口 |
$server_protocol | 表示服务器向客户端发送响应的协议,如 HTTP/1.1或 HTTP/1.0 |
nginx缓存机制
什么是缓存?
Web缓存是可以自动保存常见文档副本的HTTP 设备。当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地设备而不是服务器中提取这个文档。
为什么使用缓存?
缓存减少了冗余的数据传输,节约了网络费用
缓存缓解了网络瓶颈的问题,对于带宽的要求
缓存降低了对原始服务器的要求,降低服务器压力
缓存加速了页面的展示
缓存的分类:
缓存分为服务端侧(比如 Nginx,redis,memcached)和客户端侧(比如 web browser)。
服务端缓存又分为 代理服务器缓存 和 反向代理服务器缓存(也叫网关缓存,比如 Nginx反向代理就可以设置缓存)
客户端侧缓存一般指的是浏览器缓存、app缓存等等,目的就是加速各种静态资源的访问,降低服务器压力。
简单看看浏览器的缓存规则:
第一次访问某个网站
第二次访问某个网站
我们发现多了一些字段关于这些字段的详细介绍下面会讲
HTTP 缓存控制头介绍
HTTP 中最基本的缓存机制,涉及到的 HTTP 头字段,包括 Cache-Control, Last-Modified, If-Modified-Since, Etag, If-None-Match
等
Last-Modified/If-Modified-Since
Last-Modified
:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since
:当资源过期时(使用Cache-Control标识的max-age),发现资源具有 Last-Modified
声明,则再次向web服务器请求时带上头 If-Modified-Since
,表示请求时间。web服务器收到请求后发现有头 If-Modified-Since
则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应 HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的 cache
。
当我们按下f5刷新的时候,我们看看浏览器发送的请求头:
此处发送时有一个 If-Modified-Since
请求头,其值就是上次请求响应的
Last-Modified
响应状态码为304
Ctrl+f5强制刷新
如果你想强制从服务器获取最新的内容,不去对比,那么就可以强制刷新
Pragma行是为了兼容HTTP1.0
,作用与Cache-Control: no-cache
是一样的
Etag/If-None-Match
Etag
:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。
If-None-Match
:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头 If-None-Match
(Etag的值)。web服务器收到请求后发现有头If-None-Match
则与被请求资源的相应校验串进行比对,决定返回200或304。
Etag
是啥:
Last-Modified
标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified
却改变了,导致文件没法使用缓存
有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified
与ETag
是可以一起使用的,服务器会优先验证ETag
,一致的情况下,才会继续比对Last-Modified
,最后才决定是否返回304。
如下所示:
浏览器第一次请求,无缓存状态
浏览器第二次请求
Nginx web缓存设置
nginx
提供了 expires、etag、if-modified-since
指令来进行浏览器缓存控制。
expires
假设我们使用nginx
作为静态资源服务器,此时可以使用expires
进行缓存控制。
location /img {
alias /export/img/;
expires 10s;
}
expires 30s;#30秒
expires 30m;#30分钟
expires 2h;#2个小时
expires 30d;#30天
nginx代理模块(ngx_http_proxy_module)
Proxy
模块,用于把请求后抛给服务器节点或 upstream
服务器池
常用配置,具体看手册
请求头传递
proxy_redirect off ;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 50m;
client_body_buffer_size 256k;
proxy_connect_timeout 30;
proxy_send_timeout 30;
proxy_read_timeout 60;
proxy_buffer_size 256k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
proxy_max_temp_file_size 128m;
proxy_pass http://nginx.23673.com;
缓存细节
NGINX仅仅默认缓存GET和HEAD客户端请求,在响应头部中 Cache-Control
被配置为 Private,No-Cache,No-Store
或者 Set-Cookie
,NGINX
不会进行缓存。
如果你不想源服务器控制是否缓存,也可以在 nginx
当中配置忽略利用 roxy_ignore_headers Cache-Control
指令实现
下面的指令允许多种请求类型缓存
proxy_cache_methods GET HEAD POST
;
缓存设置优化
proxy_cache_min_uses
设置响应被缓存的最小请求次数。
当缓存不断被填满时,这项设置便十分有用,因为这确保了只有那些被经常访问的内容才会被添加到缓存中。该项默认值为1。
proxy_cache_lock
开启此功能时,对于相同的请求,同时只允许一个请求发往后端。
只有这些请求中的第一个被允许发送至服务器。其他请求在第一个请求得到满意结果之后在缓存中得到文件。如果不启用 proxy_cache_lock
,则所有在缓存中找不到文件的请求都会直接与源服务器通信。
不缓存的条件
有时候,我们也不想所有的请求都被缓存,我们可以指定某些请求不被缓存,比如带有后台后缀的,可以通过一些条件判断决定是否缓存。
语法: proxy_cache_bypass string ...;
默认值: —
上下文: http, server, location
定义nginx不从缓存取响应的条件。如果至少一个字符串条件非空而且非“0”,nginx就不会从缓存中去取响应,而是请求源服务器
比如后台模块是不允许缓存的,就可以设置不缓存
清除缓存
某些时候我们如果不想等待缓存的过期,想要主动清除缓存,可以采用第三方的缓存清除模块清除缓存 nginx_ngx_cache_purge
第三方地址 https://www.nginx.com/resources/wiki/modules/
Purge 模块下载地址 http://labs.frickle.com/nginx_ngx_cache_purge/
可以利用平滑升级的方式安装
proxy_cache_purge
syntax: proxy_cache_purge zone_name key
default: none
context: location
注意:要在proxy_cache 指令 下方
proxy_cache_purge tmp-test $uri;
tmp-test:指定的key_zone
$uri:指定的生成key的参数
比如:匹配url当中包含了purge关键字的就清除
缓存 xxx.com/cache/shop/?a=1
清除 xxxx.com/purge/shop/?a=1
半自动平滑升级
所谓半自动,其实就是在最后迁移的时候使用源码自带的升级命令:make upgrade 来自动完成
1、需要下载对应的需要加载的第三方的扩展,或者是需要附加设置的参数 (注意:之前的配置参数要保留)
--add_module=PATH 添加第三方扩展
2、执行make不要执行make install
3、重命名 nginx 旧版本二进制文件,即 sbin 目录下的 nginx(期间 nginx 并不会停止服务)
4、然后拷贝一份新编译的二进制文件到安装目录
5、在源码目录执行 make upgrade 开始升级:
nginx负载均衡
当我们的应用单例不能支撑用户请求时,此时就需要扩容,从一台服务器扩容到两台、几十台、几百台,我们需要一个入口,将客户端请求均衡分布在后台的多个服务器上。
负载均衡在服务端开发中算是一个比较重要的特性,nginx
提供的负载均衡可以实现上游服务器的负载均衡、故障转移、失败重试、容错、健康检查,当某些上游服务器出现问题时,可以将请求转到其它的上游服务器从而保障高可用。
第一步我们需要给nginx
配置上游服务器,即负载均衡到真实的处理业务的服务器
通过在http
指令下配置upstream
即可。
语法: upstream name { ... }
默认值: —
上下文: http
例子:
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
}
server {
location / {
proxy_pass http://backend;
}
}
upstream 指令当中包含server指令
语法: server address [parameters];
默认值: —
上下文: upstream
可以定义下面的参数:
weight=number 设定服务器的权重,默认是1,权重越大被访问机会越大,要根据机器的配置情况来配置
max_fails=number 设定Nginx与服务器通信的尝试失败的次数。在fail_timeout参数定义的时间段内,如果失败的次数达到此值,Nginx就认为服务器不可用。在下一个fail_timeout时间段,服务器不会再被尝试。 失败的尝试次数默认是1。
可以通过指令proxy_next_upstream 和memcached_next_upstream来配置什么是失败的尝试。 默认配置时,http_404状态不被认为是失败的尝试。
fail_timeout=time
统计失败尝试次数的时间段。在这段时间中,服务器失败次数达到指定的尝试次数,服务器就被认为不可用。默认情况下,该超时时间是10秒。
backup
标记为备用服务器。当主服务器不可用以后,请求会被传给这些服务器,配置这个指令可以实现故障转移。
down
标记服务器永久不可用,可以跟ip_hash指令一起使用。
当访问Nginx时,会将请求反向代理到backend配置的upstream server。
负载均衡的方法
nginx
支持以下负载均衡机制:
1、轮询
默认轮训方式
每一个来自网络中的请求,轮流分配给内部的服务器,从1到N然后重新开始。此种负载均衡算法适合服务器组内部的服务器都具有相同的配置并且平均服务请求相对均衡的情况。
2、加权轮询
通过weight
参数控制权重
根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能够接受相应权值数的服务请求。例如:服务器A的权值被设计成1,B的权值是3,C的权值是6,则服务器A、B、C将分别接受到10%、30%、60%的服务请求。此种均衡算法能确保高性能的服务器得到更多的使用率,避免低性能的服务器负载过重。
3、IP Hash
在upstream
当中配置ip_hash
;
这种方式通过生成请求源IP的哈希值,并通过这个哈希值来找到正确的真实服务器。这意味着对于同一主机来说他对应的服务器总是相同。使用这种方式,你不需要保存任何源IP。
将客户端会话"沾住"或者"持久化",以便总是能选择特定服务器,那么可以使用ip-hash
负载均衡机制。
使用ip-hash
时,客户端IP地址作为hash key
使用,用来决策选择服务器集群中的哪个服务器来处理这个客户端的请求。这个方法保证从同一个客户端发起的请求总是定向到同一台服务器,除非服务器不可用。
4、最少连接数
在upstream
当中配置least_conn
实现最少连接数
客户端的每一次请求服务在服务器停留的时间可能会有较大的差异,随着工作时间加长,如果采用简单的轮循或随机均衡算法,每一台服务器上的连接进程可能会产生极大的不同,并没有达到真正的负载均衡。最少连接数均衡算法对内部中需负载的每一台服务器都有一个数据记录,记录当前该服务器正在处理的连接数量,当有新的服务连接请求时,将把当前请求分配给连接数最少的服务器,使均衡更加符合实际情况,负载更加均衡。
失败重试
通过配置上游服务器max_fails
和 fail_timeout
,指定每个上游服务器,当fail_timeout
时间内失败了max_fails
次请求,则认为该上游服务器不可用/不存活,然后这段时间将不会访问这台上游服务器,fail_timeout
时间后会再次进行重试。
max_fails=2
fail_timeout=30s
这2个一起搭配使用,表示:当失败2次的时候,就停止使30秒