关于Nginx的使用(详解)
服务配置与说明
nginx默认配置预览图
配置参数详解
server:
用于定义服务,http中可以有多个server块listen:
指定服务器侦听请求的IP地址和端口,如果省略地址,服务器将侦听所有地址,如果省略端口,
则使用标准端口server_name:
服务名称,用于配置域名location:
用于配置映射路径uri对应的配置,一个server中可以有多个location, location后面跟一个uri,
可以是一个正则表达式, / 表示匹配任意路径, 当客户端访问的路径满足这个uri时就会执行location块里面
的代码root:
根路径,当访问http://localhost/test.html,“/test.html”会匹配到”/”uri, 找到root为/usr/local
/var/www/html,用户访问的资源物理地址=root + uri = /usr/local/var/www/html + /test.html=/usr/
local/var/www/html/test.htmlindex:
设置首页,当只访问server_name时后面不跟任何路径是不走root直接走index指令的;如果访问
路径中没有指定具体的文件,则返回index设置的资源,如果访问http://localhost/html/ 则默认返回
index.html
location uri正则表达式
- . :匹配除换行符以外的任意字符
- ? :重复0次或1次
- :重复1次或更多次
- :重复0次或更多次
- \d :匹配数字
- ^ :匹配字符串的开始
- $ :匹配字符串的结束
- {n} :重复n次
- {n,} :重复n次或更多次
- [c] :匹配单个字符c
- [a-z] :匹配a-z小写字母的任意一个
- (a|b|c) : 属线表示匹配任意一种情况,每种情况使用竖线分隔,一般使用小括号括括住,匹配符合a字符 或是b字符 或是c字符的字符串
- \ 反斜杠:用于转义特殊字符
- 小括号()之间匹配的内容,可以在后面通过$1来引用,$2表示的是前面第二个()里的内容。
- 正则里面容易让人困惑的是\转义特殊字符。
实现代理与动静分离
代理静态文件
在没有域名加持的情况下,怎么代理静态文件?
set $doc_root /usr/local/var/www; 通过set属性来设置变量
http {
server {
listen 80;
server_name localhost;
set $doc_root /usr/local/var/www;
# 默认location
location / {
root /usr/local/var/www/html;
index index.html index.htm;
}
location ^~ /images/ {
root $doc_root;
}
location ~* \.(gif|jpg|jpeg|png|bmp|ico|swf|css|js)$ {
root $doc_root/img;
}
}
}
静态文件映射
静态服务器location的映射一般有两种方式:
- 使用路径,如 /images/ 一般图片都会放在某个图片目录下,
- 使用后缀,如 .jpg、.png 等后缀匹配模式
访问http://localhost/test.jpg 会映射到 $doc_root/img
访问http://localhost/images/test.jpg 当同一个路径满足多个location时,优先匹配优先级高的location,由于^~ 的优先级大于 ~, 所以会走/images/对应的location
常用的location路径映射:
= 完全匹配,^~ 前缀匹配,如果匹配成功则不再匹配其他location,~ 正则区分大小写 ,~* 正则不区分大小写
/***/ 常规字符串路径 匹配,/ 通用匹配,任何请求都会匹配
location优先级
当一个路径匹配多个location时究竟哪个location能匹配到时有优先级顺序的,而优先级的顺序于location值的表达式类型有关,和在配置文件中的先后顺序无关。相同类型的表达式,字符串长的会优先匹配。
- 等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项,停止搜索。
- ^~类型表达式,不属于正则表达式。一旦匹配成功,则不再查找其他匹配项,停止搜索。
- 正则表达式类型(~ ~*)的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个。
- 常规字符串匹配类型。按前缀匹配。
- / 通用匹配,如果没有匹配到,就匹配通用的
优先级搜索问题:不同类型的location映射决定是否继续向下搜索
- =类型、^~类型:一旦匹配上就停止搜索了,不会再匹配其他location了
- 正则表达式类型(~ ~*),常规字符串匹配类型/xxx/ : 匹配到之后,还会继续搜索其他其它location,直到找到优先级最高的,或者找到第一种情况而停止搜索
location优先级从高到底:
(location =) > (location 完整路径) > (location ^~ 路径) > (location,* 正则顺序) > (location 部分起始路径) > (/)
location = / {
# 精确匹配/,主机名后面不能带任何字符串 /
[ configuration A ]
}
location / {
# 匹配所有以 / 开头的请求。
# 但是如果有更长的同类型的表达式,则选择更长的表达式。
# 如果有正则表达式可以匹配,则优先匹配正则表达式。
[ configuration B ]
}
location /documents/ {
# 匹配所有以 /documents/ 开头的请求,匹配符合以后,还要继续往下搜索。
# 但是如果有更长的同类型的表达式,则选择更长的表达式。
# 如果有正则表达式可以匹配,则优先匹配正则表达式。
[ configuration C ]
}
location ^~ /images/ {
# 匹配所有以 /images/ 开头的表达式,如果匹配成功,则停止匹配查找,停止搜索。
# 所以,即便有符合的正则表达式location,也不会被使用
[ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
# 匹配所有以 gif jpg jpeg结尾的请求。
# 但是 以 /images/开头的请求,将使用 Configuration D,D具有更高的优先级
[ configuration E ]
}
反向代理
简介
反向代理应该是Nginx使用最多的功能了,反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
简单来说就是真实的服务器不能直接被外部网络访问,所以需要一台代理服务器,而代理服务器能被外部网络访问的同时又跟真实服务器在同一个网络环境,当然也可能是同一台服务器,端口不同而已。
反向代理通过proxy_pass指令来实现。
通过监听80端口来代理到内部服务8081
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://localhost:8081;
proxy_set_header Host $host:$server_port;
# 设置用户ip地址
proxy_set_header X-Forwarded-For $remote_addr;
# 当请求服务器出错去寻找其他服务器
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
}
}
proxy_set_header参数
- $http_host 与 $proxy_host
当Host设置为$http_host时,则不改变请求头的值,所以当要转发到bbb.example.com的时候,请求头还是aaa.example.com的Host信息,就会有问题;
当Host设置为$proxy_host时,则会重新设置请求头为bbb.example.com的Host信息。
- 转发附带参数
属性rewrite
下面例子(.*)是将所有参数传给$1,转发时/$1会拼接在http://bbb.example.com后面。
location ~ ^/api/([0-9]+)(\.[0-9]+)*/client/ {
rewrite /(.*)$ /$1 break;
proxy_pass http://bbb.example.com;
proxy_set_header Host $proxy_host;
}
proxy_next_upstream重试机制
proxy_next_upstream用于指定在什么情况下Nginx会将请求转移到其他服务器上。
其默认值是proxy_next_upstream error timeout,即发生网络错误以及超时,才会重试其他服务器。
默认情况下服务返回500状态码是不会重试的,如果想在响应500状态码时也进行重试,可以配置 proxy_next_upstream error timeout http_500;
- non_idempotent 属性
通常情况下,如果请求使用非等幂方法(POST、LOCK、PATCH),请求失败后不会再到其他服务器进行重试。加上non_idempotent选项后,即使是非幂等请求类型(例如POST请求),发生错误后也会重试。
- 什么是幂等方法
如果使用该方法对多个相同请求的服务器的预期效果与对单个这样的请求的效果相同,则该请求方法被认为是“幂等”的。
在做业务开发是如何理解幂等性,举个最简单的例子:GET方法一般用于获取数据,如果获取的是数据库数据,对应的是SELECT语句。同样的SELECT语句执行一次还是多次,都不会影响数据。而POST一般对应INSERT,如果执行多次后,可能会造成数据重复插入的问题。所以不要使用GET方法做一些INSERT操作
生产环境中为什么不建议加上non_idempotent选项?因为无论是发生500错误还是timeout,服务器上的业务可能都已经执行过了,而重试会导致非幂等方法重复执行,从而导致业务问题,例如一个请求会创建了多个订单,或者收到多条短信的问题。
负载均衡
简介
负载均衡也是Nginx常用的一个功能,负载均衡其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
简单而言就是当有2台或以上服务器时,根据规则随机的将请求分发到指定的服务器上处理,负载均衡配置一般都需要同时配置反向代理,通过反向代理跳转到负载均衡。而Nginx目前支持自带3种负载均衡策略,还有2种常用的第三方策略。
RR(round robin :轮询 默认)
每个请求按时间顺序逐一分配到不同的后端服务器,也就是说第一次请求分配到第一台服务器上,第二次请求分配到第二台服务器上,如果只有两台服务器,第三次请求继续分配到第一台上,这样循环轮询下去,也就是服务器接收请求的比例是 1:1, 如果后端服务器down掉,能自动剔除。轮询是默认配置,不需要太多的配置
upstream web_servers {
server localhost:8081;
server localhost:8082;
}
权重
指定轮询几率,weight和访问比率成正比, 也就是服务器接收请求的比例就是各自配置的weight的比例,用于后端服务器性能不均的情况,比如服务器性能差点就少接收点请求,服务器性能好点就多处理点请求。
upstream test {
server localhost:8081 weight=1;
server localhost:8082 weight=3;
server localhost:8083 weight=4 backup;
}
ip_hash
上面的2种方式都有一个问题,那就是下一个请求来的时候请求可能分发到另外一个服务器,当我们的程序不是无状态的时候(采用了session保存数据),这时候就有一个很大的很问题了,比如把登录信息保存到了session中,那么跳转到另外一台服务器的时候就需要重新登录了,所以很多时候我们需要一个客户只访问一个服务器,那么就需要用iphash了,iphash的每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
upstream test {
ip_hash;
server localhost:8080;
server localhost:8081;
}
fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。这个配置是为了更快的给用户响应
upstream backend {
fair;
server localhost:8080;
server localhost:8081;
}
url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法
upstream backend {
hash $request_uri;
hash_method crc32;
server localhost:8080;
server localhost:8081;
}