nginx 概述
nginx(engine x) 简介
Nginx(发音同“engine X”)是异步框架的网页服务器,也可以用作反向代理、负载平衡器和HTTP缓存。
正向代理
正向代理:局域网中的客户端不能直接访问 Internet, 则需要通过代理服务器来访问,这种代理服务就称为正向代理。Nginx 本身只支持 http 的正向代理,并通过 ngx_http_proxy_connect_module 模块支持 http、https 的正向代理
反向代理
反向代理:如果局域网向 Internet 提供资源服务,让 Internet 上的其他客户端来访问局域网内的资源,是他们必须通过一个代理服务器来进行访问内部资源,这种服务就称为反向代理;Nginx 通过 proxy 模块实现反向代理功能。
负载均衡
如果有多个处理相同业务的业务处理服务器,nginx 会按照一定的规则将请求分发到每一个业务处理服务器,保证每个请求都能够及时被处理和响应,这就是负载均衡
动静分离
动静分离将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问。这里我们将静态资源放到nginx中,动态资源转发到 Django 服务中。因此,动态资源转发到 Django 服务我们就使用到了前面讲到的反向代理了。
nginx 通过 location 对 url 进行匹配即可实现动静分离。
nginx 配置
nginx 配置概览
nginx 配置文件结构
... #全局块
events { #events块
...
}
http #http块
{
... #http全局块
server #server块
{
... #server全局块
location [PATTERN] #location块
{
...
}
location [PATTERN]
{
...
}
}
server
{
...
}
... #http全局块
}
- 全局块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。
- events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
- http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。
- server块:配置虚拟主机的相关参数,一个http中可以有多个server。
- location块:配置请求的路由,以及各种页面的处理情况。
基本配置及注释
########### 每个指令必须有分号结束。#################
#user administrator administrators; #配置用户或者组,默认为nobody nobody。
#worker_processes 2; #允许生成的进程数,默认为1
#pid /nginx/pid/nginx.pid; #指定nginx进程运行文件存放地址
error_log log/error.log debug; #制定日志路径,级别。这个设置可以放入全局块,http块,server块,级别以此为:debug|info|notice|warn|error|crit|alert|emerg
events {
accept_mutex on; #设置网路连接序列化,防止惊群现象发生,默认为on
multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off
#use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
worker_connections 1024; #最大连接数,默认为512
}
http {
include mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型,默认为text/plain
#access_log off; #取消服务日志
log_format myFormat '$remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #自定义格式
access_log log/access.log myFormat; #combined为日志格式的默认值
sendfile on; #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
sendfile_max_chunk 100k; #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
keepalive_timeout 65; #连接超时时间,默认为75s,可以在http,server,location块。
upstream mysvr {
server 127.0.0.1:7878;
server 192.168.10.121:3333 backup; #热备
}
error_page 404 https://www.baidu.com; #错误页
server {
keepalive_requests 120; #单连接请求上限次数。
listen 4545; #监听端口
server_name 127.0.0.1; #监听地址
location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
#root path; #根目录
#index vv.txt; #设置默认页
proxy_pass http://mysvr; #请求转向mysvr 定义的服务器列表
deny 127.0.0.1; #拒绝的ip
allow 172.18.5.54; #允许的ip
}
}
}
1、几个常见配置
$remote_addr
与$http_x_forwarded_for
用以记录客户端的ip地址$remote_user
:用来记录客户端用户名称$time_local
: 用来记录访问时间与时区$request
: 用来记录请求的url与http协议$status
: 用来记录请求状态;成功是200$body_bytes_sent
:记录发送给客户端文件主体内容大小$http_referer
:用来记录从那个页面链接访问过来的$http_user_agent
:记录客户端浏览器的相关信息
2、惊群现象:一个网路连接到来,多个睡眠的进程被同事叫醒,但只有一个进程能获得链接,这样会影响系统性能。
location 配置
location [= | ~ | ~* | ^~ |] uri {}
=
开头表示精确匹配^~
开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)~
开头表示区分大小写的正则匹配~*
开头表示不区分大小写的正则匹配!~
和!~*
分别为区分大小写不匹配及不区分大小写不匹配的正则/
通用匹配,任何请求都会匹配到。- 多个location配置的情况下匹配顺序为:
首先匹配=
,其次匹配^~
, 其次是按文件中顺序的正则匹配,最后是交给/
通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。
nginx proxy 的配置说明
-
上面的配置中,我们在 http 模块的配置下配置,当代理遇到状态码为404时,我们把404页面导向百度。
error_page 404 https://www.baidu.com; #错误页
然而这个配置,细心的朋友可以发现他并没有起作用。
如果我们想让他起作用,我们必须配合着下面的配置一起使用
proxy_intercept_errors on; #如果被代理服务器返回的状态码为400或者大于400,设置的error_page配置起作用。默认为off。
-
如果我们的代理只允许接受get,post请求方法的一种
proxy_method get; #支持客户端的请求方法。post/get;
-
设置支持的http协议版本
proxy_http_version 1.0; #Nginx服务器提供代理服务的http协议版本1.0, 1.1, 2.0,默认设置为1.0版本,
-
如果你的nginx服务器给2台web服务器做代理,负载均衡算法采用轮询,那么当你的一台机器web程序iis关闭,也就是说web不能访问,那么nginx服务器分发请求还是会给这台不能访问的web服务器,如果这里的响应连接时间过长,就会导致客户端的页面一直在等待响应,对用户来说体验就打打折扣,这里我们怎么避免这样的情况发生呢。
如果负载均衡中其中web2发生这样的情况,nginx首先会去web1请求,但是nginx在配置不当的情况下会继续分发请求道web2,然后等待web2响应,直到我们的响应时间超时,才会把请求重新分发给web1,这里的响应时间如果过长,用户等待的时间就会越长。
proxy_connect_timeout 1; #nginx服务器与被代理的服务器建立连接的超时时间,默认60秒 proxy_read_timeout 1; #nginx服务器向被代理服务器组发出read请求后,等待响应的超时间,默认为60秒。 proxy_send_timeout 1; #nginx服务器向被代理服务器组发出write请求后,等待响应的超时间,默认为60秒。 proxy_ignore_client_abort on; #客户端断网时,nginx服务器是否中断对被代理服务器的请求,默认为off。
-
如果使用upstream指令配置了一组服务器作为被代理服务器,服务器中的访问算法遵循配置的负载均衡规则,同时可以使用该指令配置在发生哪些异常情况时,将请求顺次交由下一组服务器处理。
proxy_next_upstream timeout; #反向代理upstream中设置的服务器组,出现故障时,被代理服务器返回的状态值。error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off
-
error:建立连接或向被代理的服务器发送请求或读取响应信息时服务器发生错误。
-
timeout:建立连接,想被代理服务器发送请求或读取响应信息时服务器发生超时。
-
invalid_header:被代理服务器返回的响应头异常。
-
off:无法将请求分发给被代理的服务器。
-
http_400,....:被代理服务器返回的状态码为400,500,502,等。
-
-
如果你想通过http获取客户的真实ip而不是获取代理服务器的ip地址,那么要做如下的设置。
proxy_set_header Host $host; #只要用户在浏览器中访问的域名绑定了 VIP VIP 下面有RS;则就用$host ;host是访问URL中的域名和端口 www.taobao.com:80 proxy_set_header X-Real-IP $remote_addr; #把源IP 【$remote_addr,建立HTTP连接header里面的信息】赋值给X-Real-IP;这样在代码中$X-Real-IP来获取源IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #在nginx 作为代理服务器时,设置的IP列表,会把经过的机器ip,代理机器ip都记录下来,用 【,】隔开;代码中用 echo $x-forwarded-for |awk -F, '{print $1}' 来作为源IP
-
下面是我的一个关于代理配置的配置文件部分,仅供参考。
include mime.types; #文件扩展名与文件类型映射表 default_type application/octet-stream; #默认文件类型,默认为text/plain #access_log off; #取消服务日志 log_format myFormat ' $remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #自定义格式 access_log log/access.log myFormat; #combined为日志格式的默认值 sendfile on; #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。 sendfile_max_chunk 100k; #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。 keepalive_timeout 65; #连接超时时间,默认为75s,可以在http,server,location块。 proxy_connect_timeout 1; #nginx服务器与被代理的服务器建立连接的超时时间,默认60秒 proxy_read_timeout 1; #nginx服务器想被代理服务器组发出read请求后,等待响应的超时间,默认为60秒。 proxy_send_timeout 1; #nginx服务器想被代理服务器组发出write请求后,等待响应的超时间,默认为60秒。 proxy_http_version 1.0 ; #Nginx服务器提供代理服务的http协议版本1.0,1.1,默认设置为1.0版本。 #proxy_method get; #支持客户端的请求方法。post/get; proxy_ignore_client_abort on; #客户端断网时,nginx服务器是否终端对被代理服务器的请求。默认为off。 proxy_ignore_headers "Expires" "Set-Cookie"; #Nginx服务器不处理设置的http相应投中的头域,这里空格隔开可以设置多个。 proxy_intercept_errors on; #如果被代理服务器返回的状态码为400或者大于400,设置的error_page配置起作用。默认为off。 proxy_headers_hash_max_size 1024; #存放http报文头的哈希表容量上限,默认为512个字符。 proxy_headers_hash_bucket_size 128; #nginx服务器申请存放http报文头的哈希表容量大小。默认为64个字符。 proxy_next_upstream timeout; #反向代理upstream中设置的服务器组,出现故障时,被代理服务器返回的状态值。error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off #proxy_ssl_session_reuse on; 默认为on,如果我们在错误日志中发现“SSL3_GET_FINSHED:digest check failed”的情况时,可以将该指令设置为off。
nginx 负载均衡5种策略
1、轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
upstream backserver {
server 192.168.0.14;
server 192.168.0.15;
}
2、weight
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的
情况。
upstream backserver {
server 192.168.0.14 weight=3;
server 192.168.0.15 weight=7;
}
权重越高,在被访问的概率越大,如上例,分别是30%,70%。
3、ip_hash
上述方式存在一个问题就是说,在负载均衡系统中,假如用户在某台服务器上登录了,那么该用户第二次请求的时候,因为我们是负载均衡系统,每次请求都会重新定位到服务器集群中的某一个,那么已经登录某一个服务器的用户再重新定位到另一个服务器,其登录信息将会丢失,这样显然是不妥的。
我们可以采用ip_hash指令解决这个问题,如果客户已经访问了某个服务器,当用户再次访问时,会将该请求通过哈希算法,自动定位到该服务器。
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
upstream backserver {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}
4、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backserver {
server server1;
server server2;
fair;
}
5、url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个(对应的)后端服务器,后端服务器为缓存时比较有效。
upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
在需要使用负载均衡的server中增加
proxy_pass http://backserver/;
upstream backserver{
ip_hash;
server 127.0.0.1:9090 down; #down 表示单前的server暂时不参与负载
server 127.0.0.1:8080 weight=2; #weight 默认为1,weight越大,负载的权重就越大
server 127.0.0.1:6060 max_fails=1 fail_timeout=30s;
server 127.0.0.1:7070 backup; #其它所有的非backup机器down或者忙的时候,请求backup机器
}
max_fails :允许请求失败的次数默认为1, 当超过最大次数时,返回 proxy_next_upstream 模块定义的错误fail_timeout : max_fails 次失败后,暂停的时间
backup 不能与 ip_hash 一起使用
nginx + keepalived 主备模式
准备工作
- 需要两台服务器 192.168.17.129 和 192.168.17.131
- 在这两台服务器上都安装 nginx 和 keepalived
安装 keepalived
分别在两台 nginx 服务器上安装 keepalived
yum install keepalived -y
rpm -q -a keepalived # 检查是否安装成功
安装成功后,keepalived 的配置文件存放在 /etc/keepalived/keepalived.conf
主 nginx 服务器的配置
-
nginx 的配置还是正常的 nginx 配置
-
主 nginx 服务器中的 keepalived 配置如下:
global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.92.128 smtp_connect_timeout 30 router_id LVS_DEVEL } vrrp_script chk_http_port { script "/usr/local/src/nginx_check.sh" interval 2 #(检测脚本执行的间隔) weight 2 } vrrp_instance VI_1 { state MASTER #备份服务器上将 MASTER 改为 BACKUP interface ens33 #网卡 virtual_router_id 51 #主、备机的virtual_router_id必须相同 priority 100 #主、备机取不同的优先级,主机值较大,备份机值较小 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.92.150 //VRRP H虚拟机地址 } }
-
在 /usr/local/src/ 下添加检测脚本 nginx_check.sh
#!/bin/bash A=`ps -C nginx -no-header |wc -1` if [ $A -eq 0 ];then /server/nginx/sbin/nginx sleep 2 if [ `ps -C nginx --no-header |wc -1` -eq 0 ];then killall keepalived fi fi
从 nginx 服务器的配置
-
nginx 的配置还是正常的 nginx 配置
-
从 nginx 服务器中的 keepalived 配置如下:
global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.92.128 smtp_connect_timeout 30 router_id LVS_DEVEL # LVS_DEVEL 是主机的名字,在etc/hosts文件中配置,可以自己随意起,也可以用IP替换 } vrrp_script chk_http_port { script "/usr/local/src/nginx_check.sh" interval 2 # 上面的脚本每隔2秒执行一次 weight 2 # 当脚本执行成功后该服务器增加2的权重(猜的) } vrrp_instance VI_1 { state BACKUP #备份服务器上将 MASTER 改为 BACKUP interface ens33 #虚拟IP绑定的网卡 virtual_router_id 51 #主、备机的virtual_router_id必须相同 priority 90 #主、备机取不同的优先级,主机值较大,备份机值较小 advert_int 1 #每隔1秒发送一次心跳检测服务器状态 authentication { #权限校验的方式 auth_type PASS auth_pass 1111 } virtual_ipaddress { # 可以绑定多个虚拟IP 192.168.92.150 //VRRP H虚拟机地址 } }
-
在 /usr/local/src/ 下添加检测脚本 nginx_check.sh(和主一样)
启动 nginx 和 keepalived
启动两台服务器的 nginx 和 keepalived
nginx # 已经启动的话,用 nginx -s reload
systemctl start keepalived.service
测试
- 在浏览器数据虚拟 IP 地址:192.168.92.150,进行访问
- 在 192.168.92.128 服务器上运行
nginx -s stop
然后再次重复第 1 步
参考: