本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1·引言
对nginx来说,负载均衡就是反向代理的目的之一,nginx有负载均衡就肯定就有反向代理,有反向代理不一定有负载均衡。
1.1·负载均衡
现在一般公司的系统都不会是一个服务器或者说是一个应用实例提供服务,往往是多个应用实例甚至上百个应用实例提供等同的服务。
通过技术可以实现将访问系统的请求按照某一种规则均匀的分配给系统的每个应用实例,并且部分实例异常,也不会引起整个系统不可用,提高系统的并发量,可靠性以及性能,这就是聚在均衡。
1.2·反向代理
中大型公司一般都是有内部网络,和互联网是隔绝的,有的系统是在内网给员工访问的,有的系统是暴露给互联网用户访问的
外网访问的系统可以选择分配一个互联网IP暴露在互联网访问,也可以统一走一个出口出去,也就是反向代理
反向代理接收来自互联网的访问请求,匹配规则之后,将请求转发给内部对应的系统,并将从内部系统得到的结果返回给请求放,在请求方看来,反向代理服务器就是一个提供服务的服务器,和真正的服务器没什么不同
反向代理
1.3·简单示意图
2·nginx的反向代理
单纯的实现反向代理是比较简单的,单纯的实现反向代理一般最多的情况就是将互联网的访问转发给内部应用,起一个中间保护和管理的作用(后端的内部应用有自己的负载均衡),像是在平安寿险就有专门的一个nginx的网关系统,负责转发外网请求给内部系统。
server {
listen 80;
server_name xx.xx.com.cn; // Nginx反向代理服务器对应的域名
location ^~ /serverA/ {
proxy_pass http://serverA.com.cn; // 内网后端系统的域名
index index.html index.htm;
}
}
复制代码
这样,访问xx.xx.com.cn/serverA/aa的时候就相当于访问serverA.com.cn/aa
3·nginx的负载均衡
实现负载均衡,是一定会有反向代理的操作的
Upstream 指令 用于 设置 一组 可以 在 proxy_ pass 和 fastcgi_ pass 指令 中 使用 的 代理 服务器, 默认 的 负载 均衡 方式 为 轮 询。 Upstream 模块 中的 Server 指令 用于 指定 后端 服务器 的 名称 和 参数, 服务器 的 名称 可以 是一 个 域名、 一个 IP 地址、 端 口号 或 UNIX Socket。
而在 server{...} 虚拟 主 机内, 可以 通过 proxy_ pass 和 fastcgi_ pass 指令 设置 进行 反向 代理 的 upstream 服务器 集群。
proxy_ set_ header 指令 用于 在 向 反向 代理 的 后端 Web 服务器 发起 请求 时 添加 指定 的 Header 头 信息。
当 后端 Web 服务器 上有 多个 基于 域名 的 虚拟 主机 时(有多个基于域名的server), 要 通过 添加 Header 头 信息 Host, 用于 指定 请求 的 域名, 这样 后端 Web 服务器 才能 识别 该 反向 代理 访问 请求 由 哪一个 虚拟 主机 来 处理。
upstream serverA{
server 192.168.0.21:80;
server 192.168.0.22:80;
}
upstream serverB{
server 192.168.0.23:80;
server 192.168.0.24:80;
}
server {
listen 80;
server_name xx.xx.com.cn; // Nginx反向代理服务器对应的域名
location ^~ /serverA/ {
proxy_pass http://serverA;
proxy_set_header Host xx.xx.com.cn;
}
}
server {
listen 80;
server_name yy.yy.com.cn; // Nginx反向代理服务器对应的域名
location ^~ /serverB/ {
proxy_pass http://serverB;
proxy_set_header Host yy.yy.com.cn;
}
}
复制代码
3.1·负载均衡·配置参数
3.1.1·upstream
语法: upstream name {...}
使用 环境: http
该 指令 用于 设置 一组 可以 在 proxy_ pass 和 fastcgi_ pass 指令 中 使用 的 代理 服务器, 默认 的 负载 均衡 方式 为 轮 询。
变量:
从 Nginx 0. 5. 18 版本 开始, 可以 支持 用 log_ format 指令 设置 日志 格式, 日志 格式 中 可以 使用 变量。
upstream 模块 拥有 以下 变量:
$ upstream_ addr: 处理 请求 的 upstream 服务器 地址。
$ upstream_ status: Upstream 服务器 的 应答 状态。
$ upstream_ response_ time :Upstream 服务器 响应 时间( 毫秒), 多个 响应 以 逗号 和 冒号 分割。
upstream_ http_HEADER: 任意 的 HTTP 协议 头 信息,
3.1.2·upstream中的server
语法: server name [parameters]
使用 环境: upstream
该 指令 用于 指定 后端 服务器 的 名称 和 参数。 服务器 的 名称 可以 是一 个 域名、 一个 IP 地址、 端 口号 或 UNIX Socket。
在 后端 服务器 名称 之后, 可以 跟 以下 参数:
weight= NUMBER—— 设置 服务器 的 权 重, 权 重 数值 越高, 被 分配 到 的 客户 端 请求 数 越多。 如果 没有 设置 权 重, 则为 默认 权 重 1。
max_ fails= NUMBER—— 在 参数 fail_ timeout 指定 的 时 间内 对 后端 服务器 请求 失败 的 次数, 如果 检测 到 后端 服务器 无法 连接 及 发生 服务器 错误( 404 错误 除外), 则 标记 为 失败。 如果 没有 设置, 则为 默认值 1。 设为 数值 0 将 关闭 这项 检查。
fail_ timeout= TIME—— 在 经历 参数 max_ fails 设置 的 失败(失败的定义见下方注意点)次数 后, 暂停 的 时间。
down—— 标记 服务器 为 永久 离 线 状态, 用于 ip_ hash 指令。
backup—— 仅仅在非backup服务器全部宕机或繁忙的时候才启用。
max_conns=1000——允许最大连接数
slow_start=30s——当节点恢复,不立即加入
service ——反向服务地址 加端口
resolve——定义域名解析 监测IP地址和域名之间的对应关系 在不重启Nginx服务器的时候 可以动态修改upstream的配置
特别需要注意的是,何为与服务端通讯失败是由upstream的使用方定义的(ngx_http_proxy_module、proxy_next_upstream、fastcgi_next_upstream和memcached_next_upstream)
以proxy_next_upstream为例:
与服务端建立连接、向服务端发送请求或者解析服务端响应头时,发生异常或超时将被认为是通讯失败
服务端返回的响应为空或不合法将被认为是通讯失败
如果配置了http_500,http_502,http_503,http_504和http_429,服务端返回这些状态码将被认为是通讯失败
服务端返回http_403和http_404永远不会被认为通讯失败
当upstream中的一台服务器响应失败时, Nginx会将请求转发给下一台服务器,直到所有的服务器都发送过该请求,如果此时依然无法获得成功的响应,客户端将收到最后一台服务器返回的响应结果
参考官网的例子:
resolver 10.0.0.1; #dns服务器,可以多个
upstream dynamic {
zone upstream_dynamic 64k;
server backend1.example.com weight=5;
server backend2.example.com:8080 max_fails=3 fail_timeout=5s slow_start=30s;
server 192.0.2.1 max_fails=3;
server backend3.example.com resolve;
server backend4.example.com service=http resolve;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
server {
location / {
proxy_pass http://dynamic;
health_check;
}
}
复制代码
3.2·负载均衡·开源版健康检查模块nginx_upstream_check_module
nginx_upstream_check_module模块开源,可以实现负载均衡的健康检查,需要在编译的时候加入
upstream serverB{
server 192.168.0.21:80;
server 192.168.0.22:80;
check interval=3000 rise=2 fall=5 timeout=1000; #每三秒检测一次,请求2此正常则标记为up,请求5此失败则标记为down,超时时间为1秒
check_keepalive_requests 1;
check_http_send "GET /test HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx; #后端返回200认为成功
}
复制代码
3.2.1·参数check
语法:check interval=milliseconds [fall=count] [rise=count] [timeout=milliseconds] [default_down=true | false]
[type=tcp | http | ssl_hello | mysql | ajp] [port=check_port]
默认值:check interval=30000 fall=5 rise=2 timeout=1000 default_down=true type=tcp
参数解释:
interval:向后端发送的健康检查的间隔时间
fall(fall_count): 连续失败次数达到fall_count,服务器被认为是down状态
rise(rise_count): 连续成功次数达到rise_count,服务器被认为是up状态
timeout: 健康检查请求超时时间
default_down: 设定初始时服务器的状态,如果是true,服务器默认是down状态,如果是false,服务器默认是up状态,默认值是true,也就是一开始服务器被认为不可用,要等健康检查请求达到一定成功次数以后才会被认为是健康的
type:健康检查请求协议类型,支持tcp,http,ssl_hello,mysql和ajp
port:健康检查请求发送端口,可以与后端服务器服务端口不同
3.2.2·参数check_keepalive_requests
语法:check_keepalive_requests request_num
默认值:1
解释:一个连接可发送的请求数,默认值为1,表示完成1次请求后即关闭连接
3.2.3·参数check_http_send
语法:check_http_send http_packet
默认值:"GET / HTTP/1.0\r\n\r\n"
解释:HTTP接口健康检查发送的请求内容,为了减少传输数据量,推荐采用HEAD方法
3.2.4·参数check_http_expect_alive
语法:check_http_expect_alive [http_2xx | http_3xx | http_4xx | http_5xx]
默认值:http_2xx | http_3xx
解释:HTTP接口健康检查成功状态码
3.3·负载均衡·商业版健康检查模块ngx_http_upstream_hc_module
ngx_http_upstream_hc_module功能十分强大,但是只有Nginx商业版才包含该模块
允许周期性的对服务器组中的服务器进行健康检查,前提条件是服务器组中的服务器必须使用共享内存模式(共享内存用来保存服务器组的配置信息以及运行时状态,Nginx的woker进程将共享该配置和状态),结合官网修改后示例如下
resolver 10.0.0.1;
upstream dynamic {
zone upstream_dynamic 64k; # 共享内存
server backend1.example.com weight=5;
server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
server 192.0.2.1 max_fails=3;
server backend3.example.com resolve;
server backend4.example.com service=http resolve;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
http{
server {
# hc可以通过自定义的校验规则判断服务器状态
location / {
proxy_pass http://dynamic;
health_check; #默认
health_check match=welcome; #使用下方自定义的股则
}
}
# 如果配置了多个条件,所有条件均满足服务器状态才被认为是正常的
# 响应状态码为200,且响应body中包含"Welcome to nginx!"服务器状态才被认为是正常的
# Nginx仅检查响应body中的前256k数据
match welcome {
status 200;
header Content-Type = text/html;
body ~ "Welcome to nginx!";
}
}
复制代码
3.4·负载均衡·算法
3.4.1·轮询(默认)
依次将请求分配到各个后台服务器中,默认的负载均衡方式。 适用于后台机器性能一致的情况。 挂掉的机器可以自动从服务列表中剔除。
upstream serverB{
server 192.168.0.21:80;
server 192.168.0.22:80;
}
复制代码
3.4.2·权重·weight(基于权重占比轮询)
根据权重来分发请求到不同的机器中,指定轮询几率,weight和访问比率成正比,用于已知后端服务器性能不均的情况。
upstream serverB{
server 192.168.0.21:80 weight=9;
server 192.168.0.22:80 weight=10;
}
复制代码
3.4.3·ip_hash(基于请求方的IP)
每个请求按访问IP的hash结果分配,同一个IP客户端固定访问一个后端服务器。可以保证来自同一ip的请求被打到固定的机器上,可以解决session问题。
upstream serverB{
ip_hash;
server 192.168.0.21:80;
server 192.168.0.22:80;
}
复制代码
3.4.4·url_hash(基于请求的url)
根据请求的url的hash值将请求分到不同的机器中,当后台服务器为缓存的时候效率高。
Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。
upstream serverB{
server 192.168.0.21:80;
server 192.168.0.22:80;
hash $request_uri;
hash_method crc32;
}
复制代码
3.4.5·least_conn(基于繁忙程度)
least_connected 方式可以更公平的将负载分配到多个机器上面。使用least_connected,nginx不会将请求分发到繁忙的机器上面,而且将新的请求分发到较清闲的机器上面。
upstream serverB{
least_conn;
server 192.168.0.21:80;
server 192.168.0.22:80;
}
复制代码
3.4.6·fair(基于性能)
比weight、ip_hash更智能的负载均衡算法,fair算法可以根据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身不支持fair,如果需要这种调度算法,则必须安装upsteram_fair模块。
upstream serverB{
fair;
server 192.168.0.21:80;
server 192.168.0.22:80;
}
3.4.7·sticky(基于cookie)
sticky是nginx的一个模块(需要编译的时候加入nginx-sticky-module),它是基于cookie的一种nginx的负载均衡解决方案,通过分发和识别cookie,来使同一个客户端的请求落在同一台服务器上,默认标识名为route:
1.客户端首次发起访问请求,nginx接收后,发现请求头没有cookie,则以轮询方式将请求分发给后端服务器。
2.后端服务器处理完请求,将响应数据返回给nginx。
3.此时nginx生成带route的cookie,返回给客户端。route的值与后端服务器对应,可能是明文,也可能是md5、sha1等Hash值
4.客户端接收请求,并保存带route的cookie。q
5.当客户端下一次发送请求时,会带上route,nginx根据接收到的cookie中的route值,转发给对应的后端服务器。
upstream serverB{
sticky;
server 192.168.0.21:80;
server 192.168.0.22:80;
}
复制代码