Nginx代理负载均衡及详细配置

1.Nginx正向代理和反向代理

有很多同学都分不清正向代理和反向代理,下面我尽量用通俗易懂的文字指出二者的区别。首先需要明白代理的意思,代理是指受委托代表当事人从事某种活动。正向代理就是平时说的代理(比如Shadowsocks就是正向代理),是指Nginx代理服务器受客户端委托代理客户端,转发请求,并将从服务端获得的响应返回给客户端;反向代理是指Nginx代理服务器受服务端的委托代理服务端,作为集群的web节点,反向代理一般和负载均衡配合使用。一言以蔽之:正向代理,代理端代理的是客户端;反向代理,代理端代理的是服务端。见下图:

nginx代理

nginx做反向代理时根据不同的配置策略,可以进行不同的转发,比如图片结尾的走文件服务器,动态页面走web服务器,而且可以判断被分发的服务器的状态,如果存在异常将转发给其它服务器。

2.负载均衡

负载均衡的实现必须依赖于反向代理,Nginx的负载均衡策略有两种:内置策略和扩展策略。
内置策略:

  • 轮询:将请求依次轮询发给每个服务器。
  • 最少连接:将请求发送给持有最少活动链接的服务器。
  • IP哈希:通过哈希函数决定请求发送给哪个服务器。
  • 权重:服务器的权重越高,处理请求的概率越大。
    负载均衡

3.Nginx的配置文件

nginx.conf是nginx的配置文件,上面提到的代理和负载均衡都需要在配置文件中进行配置,#在配置文件中是注释掉的,不会起作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...              #全局块
events { #events块
...
}
http #http块
{
... #http全局块
server #server块
{
... #server全局块
location [PATTERN] #location块
{
...
}
location [PATTERN]
{
...
}
}
server
{
...
}
... #http全局块
}

  • 全局块:一般配置影响nginx全局的指令。一般配置用户组,日志存放路径,pid存放路径和worker_connections;
  • events块:配置nginx服务器与用户的网络连接。
  • http块:可以嵌套多个server块,配置代理服务器,日志
  • server块:可以嵌套多个location块,配置代理服务器的相关参数。
  • location块:配置请求路由和处理请求的页面或服务器。

    3.1 配置正向代理

    现在前后端分离已经越来越流行,那么前端开发时可以在本地配置一个nginx正向代理服务器,来代理前端的请求,将其转发至后台服务器中。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    ########### 每个指令必须以分号结束。#################
    #user nobody; #配置用户或者组,默认为nobody nobody。
    #worker_processes 1; #允许生成的进程数,默认为1,设置的话一般设置成跟cpu数量相等
    #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; #事件驱动模型,仅用于linux2.6以上内核,可以大大提高nginx的性能
    worker_connections 1024; #最大连接数
    # 并发总数=worker_processes*worker_connections;
    }

    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块。
    keepalive_timeout 65; #连接超时时间
    tcp_nodelay on;

    #开启gzip压缩
    gzip on;
    gzip_disable "MSIE [1-6].";

    #设定请求缓冲
    client_header_buffer_size 128k;
    large_client_header_buffers 4 128k;

    #设定虚拟主机配置
    server {
    #侦听1000端口(可以随意设定成你想要的未占用的端口)
    listen 1000;
    #定义使用 localhost访问(设定成你本地的IP地址或localhost)
    server_name localhost;

    #定义服务器的默认网站根目录位置
    root html;

    #设定本虚拟主机的访问日志
    access_log logs/nginx.access.log main;

    #默认请求
    location / {
    index index.html index.htm; #定义首页索引文件的名称
    }

    # 定义错误提示页面
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }

    #静态文件,nginx自己处理
    location ~ ^/(images|javascript|js|css|flash|media|static)/ {
    #过期30天,静态文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
    expires 30d;
    }

    location ~* \.(html|js|css|png|jpg|jpeg|gif|ttf)$ {
    proxy_pass http://127.0.0.1:63342; #访问http://localhost:1000/项目名/以html,js,css等结尾的文件请求均会被转发至http://127.0.0.1:63342;服务器中
    }

    location ~* \.*$ {
    proxy_pass http://192.168.27.100:8180; #访问http://localhost:1000/项目名/任意路径的请求均会被转发至http://192.168.27.100:8180服务器中
    }

    #禁止访问 .ht结尾的文件
    location ~ /.ht {
    deny all;
    }
    }
    }

我们最常配置的地方是location里面的代理服务器地址,这里要注意的是,1要把拦截小范围请求的放在前面,把拦截大范围请求的配置放在后面,因为像这里:location ~ .$ 拦截以结尾的请求(即所有请求),如果它放在前面了,那么请求再也走不到location ~ .(html|js|css|png|jpg|jpeg|gif|ttf)$这个配置里面了(在前面已经被拦截到了)。2.还是要注意检查结尾,我之前踩过一个坑,nginx配置文件是直接拷过来的,当时配置的location ~* .do$,此意为拦截以.do结尾的请求(java中可以配置),但我真正的请求是以.action结尾的,所以不会被拦截到,亦即不会被转发至后台服务器中,导致每次请求均是404。

3.2 配置负载均衡

配置负载均衡时Nginx充当的是反向代理服务器,当请求进来时,根据相应的负载策略,将请求分发至不同的处理器进行处理,配置步骤如下:

3.2.1 添加节点

在http块下,添加upstream节点。

1
2
3
4
upstream mytest { 
server 192.168.1.1:8081;
server 192.168.1.2:8082;
}

mytest可以改成任何你喜欢的变量,

3.2.2 配置路径

将server块下的location节点中的proxy_pass配置为:http:// + upstream名称,即“
http://mytest”。

1
2
3
4
5
location / { 
root html;
index index.html index.htm;
proxy_pass http://mytest;
}

现在负载均衡初步完成了。upstream按照轮询(默认)方式进行负载,每个请求按时间顺序逐一分配到不同的后端服务器(比如第一个请求进来就交给第一个服务器处理,第二个请求进来就交给第二个服务器处理),如果后端服务器down掉,能自动剔除。虽然这种方式简便、成本低廉。但缺点是:可靠性低和负载分配不均衡(比如明明一台服务器性能很强他处理的请求跟低配的服务器一样,那肯定是资源的浪费,要让”年轻力壮”的比”老弱病残”的处理更多的请求)。适用于图片服务器集群和纯静态页面服务器集群。所以除此之外,upstream还有其它的负载策略,分别如下:

3.2.3 weight(权重)

指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。如下所示,192.168.1.2:8082的访问比率要比192.168.1.1:8081的访问比率高一倍。

1
2
3
4
upstream mytest{ 
server 192.168.1.1:8081 weight=5;
server 192.168.1.2:8082 weight=10;
}

3.2.4 ip_hash(按访问IP进行哈希计算)

每个请求按访问IP的hash结果分配,这样每个访客固定访问一个后端服务器,同时也解决了session的问题。

1
2
3
4
5
upstream mytest{ 
ip_hash;
server 192.168.1.1:8081;
server 192.168.1.2:8082;
}

3.2.5 fair(第三方)

按后端服务器的响应时间来分配请求,响应时间短的优先分配。与weight分配策略类似。

1
2
3
4
5
upstream mytest{ 
server 192.168.1.1:8081;
server 192.168.1.2:8082;
fair;
}

3.2.6 url_hash(第三方)

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。注意:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法。

1
2
3
4
5
6
upstream mytest{ 
server 192.168.1.1:8081;
server 192.168.1.2:8082;
hash $request_uri;
hash_method crc32;
}

上面是常用的几种负载均衡策略及配置,其实upstream还可以为每个服务器设置状态值,这些状态值的含义分别如下:

  • down :落下(宕机),表示当前的server暂时不参与负载。
  • weight :权重,默认为1。weight越大,负载的权重就越大。
  • max_fails :最大失败次数,允许请求失败的次数默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误.
  • fail_timeout :失败超时时间,max_fails次失败后,暂停的时间。
  • backup:备份,其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。
    1
    2
    3
    4
    5
    6
    7
    upstream mytest{ #定义负载均衡设备的Ip及设备状态 
    ip_hash;
    server 192.168.1.1:9090 down;
    server 192.168.1.1:8080 weight=2;
    server 192.168.1.1:6060;
    server 192.168.1.1:7070 backup;
    }

以上简单介绍了nginx的应用,基本可以满足平时的开发需要,以后如果有哪些补充再进行追加。

刘俊重 wechat
欢迎关注我的微信公众号
坚持原创技术分享