总结几个nginx的日常使用场景
Nginx是一款轻量级的Web服务器、反向代理服务器,由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用。很多时候,在开发、测试环境下,我们都得自己去配置Nginx,其实就是去配置nginx.conf来实现我们想要的功能。
一、反向代理
反向代理应该是Nginx使用最多的功能了,反向代理是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部的服务器上,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
简单来说就是真实的服务器不直接暴露给外部网络访问,而是使用一台代理服务器,代理服务器能被外部网络访问的同时又跟真实服务器在同一个网络,可以进行数据交互。当然也可能是同一台服务器端口不同而已。
反向代理通过proxy_pass指令来实现,配置起来特别方便。
启动一个Java Web项目,端口号为8080
server {
listen 81;#访问端口
server_name localhost;#此处必须是用户浏览器内输入的IP或域名
location / {
proxy_pass http://localhost:8080;
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;
}
}
当我们访问localhost:81的时候,就相当于访问 localhost:8080了
二、负载均衡
负载均衡也是Nginx使用比较多的一个功能,负载均衡其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
简单来说就是当有2台或2台以上服务器时,根据规则随机的将请求分发到指定的服务器上处理,负载均衡配置一般都需要同时配置反向代理,通过反向代理跳转到负载均衡。而Nginx目前支持自带3种负载均衡策略,还有2种常用的第三方策略。
负载均衡通过upstream指令来实现。
1. RR(round robin :轮询 默认)
每个请求按时间顺序逐一分配到不同的后端服务器,也就是说第一次请求分配到第一台服务器上,第二次请求分配到第二台服务器上,如果只有两台服务器,第三次请求继续分配到第一台上,这样循环轮询下去,也就是服务器接收请求的比例是 1:1:1, 如果服务器down掉,能自动切换。轮询是默认配置,不需要太多的配置
同一个项目分别使用8081/8082/8083端口启动项目
upstream web_servers {
server 192.168.0.101:8081;
server 192.168.0.101:8082;
server 192.168.0.101:8083;
}
server {
listen 81;
server_name localhost;
#access_log logs/host.access.log main;
location / {
proxy_pass http://web_servers;
# 必须指定Header Host
proxy_set_header Host $host:$server_port;
}
}
访问地址仍然可以获得响应 http://localhost:81/workflow/listpage,这种方式是轮询的,可以在不同端口项目中看日志进行验证
2. 权重
指定轮询几率,weight和访问比率成正比, 也就是服务器接收请求的比例就是各自配置的weight的比例,用于后端服务器性能不均的情况,比如服务器性能差点就少接收点请求,服务器性能好点就多处理点请求。
upstream web_servers {
server 192.168.0.101:8081 weight=2;
server 192.168.0.101:8082 weight=3;
server 192.168.0.101:8083 weight=4 backup;
}
上面配置是5次请求有2次被分配到8081上,其他3次分配到8082上,可以看出权重越高,在被访问的概率越大。
backup是指热备,只有当8081和8082都宕机的情况下才走8083
3. ip_hash
上面的2种方式都有一个问题,那就是下一个请求来的时候请求可能分发到另外一个服务器,当我们的程序不是无状态的时候(采用了session保存数据),这时候就有一个很大的很问题了,比如把登录信息保存到了session中,那么跳转到另外一台服务器的时候就需要重新登录了,这样肯定是不行的,那么怎么解决这个问题呢。
我们可以采用ip_hash指令解决这个问题,如果客户已经访问了某个服务器,当用户再次访问时,会将该请求通过哈希算法,自动定位到该服务器。
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
配置如下:
upstream web_servers {
ip_hash;
server 192.168.0.101:8081;
server 192.168.0.101:8082;
server 192.168.0.101:8083;
}
4. fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream web_servers {
server 192.168.0.101:8081;
server 192.168.0.101:8082;
server 192.168.0.101:8083;
fair;
}
5、url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
upstream web_servers {
server 192.168.0.101:8081;
server 192.168.0.101:8082;
server 192.168.0.101:8083;
hash $request_uri;
hash_method crc32; #hash算法
}
三、HTTP服务器
Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器,如果一个网站只是静态页面的话,那么就可以通过这种方式来实现部署。
-
首先在文档根目录/usr/local/var/www下创建html目录, 然后在html中放一个index1.html;
-
配置nginx.conf中的server
user sange staff;
http {
server {
listen 81;
server_name localhost;
client_max_body_size 1024M;
# 默认location
location / {
root /usr/local/var/www/html;
index index.html index.htm;
}
}
}
- 访问测试
http://localhost:81/ 指向/usr/local/var/www/index.html, index.html是安装nginx自带的html
http://localhost:81/index1.html 指向/usr/local/var/www/html/index1.html
- 指令简介
server:用于定义服务,http中可以有多个server块
listen:指定服务器侦听请求的IP地址和端口,如果省略地址,服务器将侦听所有地址,如果省略端口,则使用标准端口
server_name:服务名称,用于配置域名
location:用于配置映射路径uri对应的配置,一个server中可以有多个location, location后面跟一个uri,可以是一个正则表达式, / 表示匹配任意路径, 当客户端访问的路径满足这个uri时就会执行location块里面的代码
root:根路径,当访问http://localhost:81/index1.html,“/index1.html”会匹配到”/”uri, 找到root为/usr/local/var/www/html,用户访问的资源物理地址=root + uri = /usr/local/var/www/html + /test.html=/usr/local/var/www/html/test.html
index:设置首页,当只访问server_name时后面不跟任何路径是不走root直接走index指令的;如果访问路径中没有指定具体的文件,则返回index设置的资源,如果访问http://localhost:81/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表示的是前面第二个()里的内容。正则里面容易让人困惑的是\转义特殊字符。
四、静态资源服务器
在实际项目开发中经常会用到静态资源功能,通常会提供一个上传的功能,其他应用如果需要静态资源就从该静态服务器中获取。
在/usr/local/var/www 下分别创建images和img目录,分别在每个目录下放一张test.jpg
http {
server {
listen 81;
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;
}
}
}
自定义变量使用set指令,语法 set 变量名值;引用使用变量名值;引用使用变量名; 这里自定义了doc_root变量。
静态服务器location的映射一般有两种方式:
使用路径,如 /images/ 一般图片都会放在某个图片目录下,
使用后缀,如 .jpg、.png 等后缀匹配模式
访问http://localhost:81/test.jpg 会映射到 $doc_root/img
访问http://localhost:81/images/test.jpg 当同一个路径满足多个location时,优先匹配优先级高的location,由于^~ 的优先级大于 ~, 所以会走/images/对应的location
常见的location路径映射路径有以下几种:
= 进行普通字符精确匹配。也就是完全匹配。
^~ 前缀匹配。如果匹配成功,则不再匹配其他location。
~ 表示执行一个正则匹配,区分大小写
~* 表示执行一个正则匹配,不区分大小写
/xxx/ 常规字符串路径匹配
/ 通用匹配,任何请求都会匹配到
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 ]
}
location /images/ {
# 字符匹配到 /images/,还会继续往下搜索
[ configuration F ]
}
location = /test.htm {
root /usr/local/var/www/htm;
index index.htm;
}
注意:location的优先级与location配置的位置无关
五、常用指令
- return指令
返回http状态码 和 可选的第二个参数可以是重定向的URL
location /permanently/moved/url {
return 301 http://www.example.com/moved/here;
}
- rewrite指令
重写URI请求 rewrite,通过使用rewrite指令在请求处理期间多次修改请求URI,该指令具有一个可选参数和两个必需参数。
第一个(必需)参数是请求URI必须匹配的正则表达式。
第二个参数是用于替换匹配URI的URI。
可选的第三个参数是可以停止进一步重写指令的处理或发送重定向(代码301或302)的标志
location /users/ {
rewrite ^/users/(.*)$ /show?user=$1 break;
}
- error_page指令
error_page指令可以配置Nginx返回自定义页面以及错误代码,替换响应中的其他错误代码,或将浏览器重定向到其他URI。如下error_page指令指定要返回404页面错误代码的页面
error_page 404 /404.html;
- 日志
访问日志:需要开启压缩 gzip on; 否则不生成日志文件,打开log_format、access_log注释
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /usr/local/etc/nginx/logs/host.access.log main;
gzip on;
- deny 指令
# 禁止访问某个目录
location ~* \.(txt|doc)${
root $doc_root;
deny all;
}
- 内置变量
nginx的配置文件中可以使用的内置变量以$开始,部分预定义的变量的值是可以改变的。
$host #请求头的值,以下顺序获得:请求行中的host、请求头中的Host、配置文件中匹配到的server_name
$remote_addr #客户端ip地址
$remote_port #客户端端口
$remote_user #基本身份验证随附的用户名
$http_cookie #Cookie请求头的值
$http_user_agent #用户代理
$cookie_name #Cookie中名为name的值
$http_referer #Http-Referer请求头的值
$cookie_name #名为name的cookie
$protocol #与客户端通信的协议: TCP或UDP(1.11.4)
$hostname #运行nginx的服务器主机名
$server_name #接受请求的服务器主机名
$body_bytes_sent #发送给客户端的字节数
$connection_requests #通过连接发出的当前请求数
$limit_rate #用于设置响应的速度限制
$time_local #通用日志格式的本地时间
$status #响应状态返回码
$request_time #请求处理时间
$proxy_add_x_fowarded_for #在客户端传递来的X-Forwarded-For请求头后面追加$remote_addr(用逗号分隔) 如果客户端没有传递X-Forwarded-For请求头,那么该变量等于$remote_addr
$msec #以毫秒为单位的当前时间
$scheme #请求模式,http或https
$nginx_version #Nginx版本
$pid #工作进程的PID
$arg_name #请求行中的参数,$arg_a=1,$arg_b=2,若无参数则为空字符串
$is_args #请求行中是否包含参数,若包含,则$is_args=?,否则为空字符串
$args #请求行中的全部参数,$args=a=1&b=2,若无参数则为空字符串
$request #完整的原始的请求行,GET /nginx/varindex?a=1&b=2 HTTP/1.1
$request_method #请求方法,如GET、POST
$request_uri #完整的原始请求URI,访问的URL除去域名(或IP)和port,如/nginx/varindex?a=1&b=2
$document_uri/$uri #请求规范化以后的URI,可能与$request_uri不同,值可能随请求的处理过程而改变
$server_protocol #请求的协议版本,如HTTP/1.0
- 其他常用指令
上面整理的都是nginx.config 中使用的一些配置,在实际使用中其实经常会用到一下命令,比如每次修改配置文件后需要重启 等等,整理如下
nginx -s reopen #重启Nginx
nginx -s reload #重新加载Nginx配置文件,然后以优雅的方式重启Nginx
nginx -s stop #强制停止Nginx服务
nginx -s quit #优雅地停止Nginx服务(即处理完所有请求后再停止服务)
nginx -t #检测配置文件是否有语法错误,然后退出
nginx -?,-h #打开帮助信息
nginx -v #显示版本信息并退出
nginx -V #显示版本和配置选项信息,然后退出
nginx -t #检测配置文件是否有语法错误,然后退出
nginx -T #检测配置文件是否有语法错误,转储并退出
nginx -q #在检测配置文件期间屏蔽非错误信息
nginx -p prefix #设置前缀路径(默认是:/usr/share/nginx/)
nginx -c filename #设置配置文件(默认是:/etc/nginx/nginx.conf)
nginx -g directives #设置配置文件外的全局指令
killall nginx #杀死所有nginx进程
以上是对nginx的一些简单整理,为了看起来方便简洁文件中多余的注释内容全部删除了,然而在实际使用过程中可能会将各种功能组合使用,原理都是相同的,大家在使用的时候还是要因地制宜灵活使用。