nginx第七篇:Nginx集群(负载均衡)、集群介绍、构建集群、nginx默认分发算法、nginx基于请求头的分发算法

一、集群介绍

1、传统web访问模型

(1)传统web访问模型完成一次请求的步骤

1)用户发起请求

2)服务器接受请求

3)服务器处理请求(压力最大)

4)服务器响应请求

(2)传统模型缺点

单点故障;

单台服务器资源有限(客户端则是无限的);

单台服务器处理耗时长(客户等待时间过长);

(3)传统模型优化——单点故障解决方案

  • 优化方案一:部署一台备份服务器,宕机直接切换 该方案可以有效解决服务器故障导致的单点故障,但且服务器利用率低、成本高,切换不及时,且无法解决服务器业务压力问题。

  • 优化方案二:部署多台服务器,根据DNS的轮询解析机制去实现用户分发 优势是用户处理速度得到了提升,但是当其中一台故障,dns并不会知道它故障了,依然将请求分给这个服务器,导致一部分用户访问不了业务。

 

2、并行处理解决方案

1)DNS轮询解析方案

2)多机阵列——集群模式

  图中,前面两台服务器负责接受请求和分发请求,它自己并不处理请求,将请求分发给后面的业务服务器来处理。业务服务器处理完请求后,将请求发还给分发器,再由分发器将请求发送给客户,因此分发器还承担了响应请求的任务。   

由此可见之前传统模型中服务器端需要承担的服务器接收请求和响应请求都交给分发器处理了,而业务压力最大的处理请求则交给业务服务器完成。   

分发器和dns虽然都是进行了分发的工作,但不同点在于分发器是自己部署的服务器,而DNS都是使用的运营商的,因此可以调整分发器的逻辑判断规则。

3、集群

  • 计算机集群简称集群,是一种计算机系统, 它通过一组松散集成的计算机软件或硬件连接起来高度紧密地协作完成计算工作。在某种意义上,他们可以被看作是一台计算机。 (百度解释)

  • 将多个物理机器组成一个逻辑计算机,实现负载均衡和容错。

组成要素:   

1)VIP: 给分发器的一个虚拟IP(Virtual IP Address)  

2)分发器:nginx   

3)数据服务器:web服务器

4、Nginx集群原理

  在Nginx集群中Nginx扮演的角色是:分发器。   

任务:接受请求、分发请求、响应请求。   

功能模块:     

1)ngx_http_upstream_module:基于应用层(七层)分发模块     

2)ngx_stream_core_module:基于传输层(四层)分发模块(1.9开始提供该功能)

(1)Nginx集群的实质

    Nginx集群其实是:虚拟主机+反向代理+upstream分发模块组成的。   

         虚拟主机:负责接受和响应请求。   

         反向代理:带领用户去数据服务器拿数据。   

         upstream:告诉nginx去哪个数据服务器拿数据。

(2)数据走向(请求处理流程)

  1)虚拟主机接受用户请求   

       2)虚拟主机去找反向代理(问反向代理去哪拿数据)   

       3)反向代理让去找upstream   

       4)upstream告诉一个数据服务器IP   

       5)Nginx去找数据服务器,并发起用户的请求   

       6)数据服务器接受请求并处理请求   

       7)数据服务器响应请求给Nginx   

       8)Nginx响应请求给用户

二、使用Nginx分发器构建一个WEB集群

1、环境准备

  实验机 : Vmware 虚拟机 1核1G   

       网卡:桥接   

       系统:centos7.5   

      防火墙:关闭   

      Selinux:关闭   

      网段:192.168.199.0/24   

      准备四台实验机:都安装nginx服务,两台当作分发器,两台当作web服务器。

主机名IP角色
Master 192.168.199.226 主分发器
Backup 192.168.199.227 备分发器
Web01 192.168.199.228 数据服务器1
Web02 192.168.199.229 数据服务器2

2、配置web业务机器

(1)nginx安装脚本

下载nginx包

wget http://nginx.org/download/nginx-1.15.5.tar.gz -P /usr/local

在web01和web02安装nginx

在master安装nginx

(2)配置web服务器操作测试

在web01写入

echo web01 > /usr/local/nginx/html/index.html    # 写入页面

  

在web02写入

echo web02 > /usr/local/nginx/html/index.html    # 写入页面

  

在master主分发器测试,可以打开web业务服务器

[root@master ~]# elinks http://192.168.199.228 -dump
   web1
[root@master ~]# elinks http://192.168.199.229 -dump
   web02
[root@master ~]# 

  

3、配置分发器(轮询方式分发)

upstream语法

upstream name {...},而且只能配置在http中

 

设置主分发器master的配置文件

 

[root@master ~]# cd /usr/local/nginx
# 清除空行和注释项
[root@master nginx]# sed -i '/#/d' ./conf/nginx.conf
[root@master nginx]# sed -i '/^$/d' ./conf/nginx.conf
​
[root@master nginx]# vi ./conf/nginx.conf
# 配置nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream web{    # 名为web的反向代理群组
        server 192.168.199.228;
        server 192.168.199.229;
    }
    server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass http://web;   # 去找反向代理
     include proxy_params;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

  

手动创建proxy_params文件,文件中存放代理的请求头相关参数

#包含语法参数,将一个配置文件添加到当前虚拟主机生效,这个文件要手动创建
#这个proxy_params文件创建在/usr/local/nginx/conf底下
nclude proxy_params;

  

也可以写绝对路径

include /usr/local/nginx/conf/proxy_params;

 

touch /usr/local/nginx/conf/proxy_params 写入信息

[root@master conf]# vi proxy_params 
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;

proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 4 128k; 
~                                                                            
"proxy_params" 10L, 274C written
[root@master conf]# ls
fastcgi.conf            mime.types          scgi_params.default
fastcgi.conf.default    mime.types.default  uwsgi_params
fastcgi_params          nginx.conf          uwsgi_params.default
fastcgi_params.default  nginx.conf.default  win-utf
koi-utf                 proxy_params
koi-win                 scgi_params

  

 

 

重启master主分发器

[root@master nginx]# killall nginx
[root@master nginx]# ./sbin/nginx 
[root@master nginx]# lsof -i :80
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   2808   root    6u  IPv4  80432      0t0  TCP *:http (LISTEN)
nginx   2809 nobody    6u  IPv4  80432      0t0  TCP *:http (LISTEN)
[root@master nginx]# 
​

  

4、集群分发测试(默认轮询)

 客户端访问分发器地址,默认按照轮询的方式来进行分发。

在web02访问主分发器

[root@web02 nginx]# elinks http://192.168.199.226 -dump
   web1
[root@web02 nginx]# elinks http://192.168.199.226 -dump
   web02
[root@web02 nginx]# elinks http://192.168.199.226 -dump
   web1
[root@web02 nginx]# elinks http://192.168.199.226 -dump
   web02
[root@web02 nginx]# 

  


三、Nginx分发算法

  集群分发算法:如何将用户请求按照一定的规律分发给业务服务器。主要分为Nginx集群默认算法和基于请求头分发算法。

1、Nginx集群默认算法

  upstream module   

nginx的upstream 目前支持4种方式的分配

(1)轮询(默认)   每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

(2)weight   指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况,权重越大,访问的次数就越多。

(3)ip_hash   每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务,好处是可以解决session的问题。   

因此前两种只能处理静态页面,而这种方式可以处理动态网站。

(4)fair(第三方)   按后端服务器的响应时间来分配请求,响应时间短的优先分配。

(5)url_hash(第三方)   按访问url的hash结果来分配请求,使每个url定向到同一个后端服务 ,后端服务器为缓存时比较有效。

2、upstream中设置的Nginx业务服务器状态

示例

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream web{    # 名为web的反向代理群组
        server 192.168.199.228 down;#设置业务服务器的状态 down,不参与分发
        server 192.168.199.229;
    }
    server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass http://web;   # 去找反向代理
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

  

  每个设备的状态设置参数:

  • down 表示当前的server暂时不参与负载;

  • weight 默认为1,weight越大,负载的权重就越大;

  • max_fails 允许请求失败的次数默认为1,当超过最大次数时,返回proxy_next_upstream模块定义的错误;

  • fail_timeout 失败超时时间,在连接Server时,如果在超时时间之内超过max_fails指定的失败次数,会认为在fail_timeout时间内Server不可用,默认为10s

  • backup

    备份服务器,业务不忙不会使用这台服务器,业务非常忙会调用这台服务器,其他所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。

3、Nginx集群默认算法测试

  集群环境与之前完全相同。

主机名IP角色
Master 192.168.199.226 主分发器
Backup 192.168.199.227 备分发器
Web01 192.168.199.228 数据服务器1
Web02 192.168.199.229 数据服务器2

(1)轮询算法分发

注意:在轮询中,如果服务器down掉了,会自动剔除该服务器。,默认的配置就是轮询策略。此策略适合服务器配置相当,无状态且短平快的服务使用。

修改主分发器设置

upstream web {
    server 192.168.199.228; 
    server 192.168.199.229;
}
server {
    listen 80;
    server_name localhost; 
    location / {
        proxy_pass http://web;
    } 
}

  

  前面已经测试验证了轮询算法分发。配置backup参数如下所示:

upstream web {
    server 192.168.199.228 weight=1; 
    server 192.168.199.229 weight=1 backup;
}
server {
    listen 80;
    server_name localhost; 
    location / {
        proxy_pass http://web;
    } 
}

  

  关停第一个web01节点情况,访问尝试:

[root@web02 ~]# elinks http://192.168.199.226 -dump 
    web02
[root@web02 ~]# elinks http://192.168.199.226 -dump 
    web02
[root@web02 ~]# elinks http://192.168.199.226-dump 
    web02
 

  

(2)基于权重的分发

权重越高分配到需要处理的请求越多。此策略可以和ip_hash结合使用。此策略比较适合服务器的硬件配置差别比较大的情况。

修改主分发器设置

upstream web {
    # 设置权重比例1:2
    server 192.168.199.228 weight=1; 
    server 192.168.199.229 weight=2 ;
}
server {
    listen 80;
    server_name localhost; 
    location / {
        proxy_pass http://web;
    } 
}

  

访问测试验证:

[root@web02 ~]# elinks http://192.168.199.226 -dump
   web02
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web02
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web02
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web02
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web02 ~]# 
​

  

通过权重比例的分配,可以让性能更强的服务器承担处理更多的请求。

(3)基于ip_hash分发

  ip_hash算法能够保证来自同样源地址的请求都分发到同一台主机。   需要注意:在nginx版本1.3.1之前,不能在ip_hash中使用权重(weight)。 ip_hash不能与backup同时使用。默认权重为1

此策略适合有状态服务,比如session,当有服务器需要剔除,必须手动down掉。

upstream web { 
    ip_hash;    # 指定ip_hash即可
    server 192.168.199.228; 
    server 192.168.199.229;
}
server { 
    listen 80;
    server_name localhost; 
    location / {
        proxy_pass http://web;
    } 
}

  

  访问测试验证:


# 源ip固定,每次访问的结果都一样
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web02 ~]# elinks http://192.168.199.226 -dump
   web1
​
#换一台机器,只要ip固定,一直访问某台服务器
[root@web01 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web01 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web01 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web01 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web01 ~]# elinks http://192.168.199.226 -dump
   web1
[root@web01 ~]# elinks http://192.168.199.226 -dump
   web1
​

  


四、Nginx基于请求头的分发

  前面的分发方式都是基于一个集群分发的,而基于请求头分发一般都是用于多集群分发的。   浏览器开发者工具network工具下,获取请求的请求头信息如下所示:

Request URL: http://192.168.199.226/     # 请求的URL
Request Method: GET              # 请求的方法
Status Code: 200 OK
Remote Address: 1192.168.199.226:80
Referrer Policy: no-referrer-when-downgrade         # 请求的策略
​
Response headers    # 响应头
Accept-Ranges: bytes
Connection: keep-alive
Content-Length: 6
Content-Type: text/html
Date: Fri, 26 Oct 2018 12:43:02 GMT
ETag: "5bd3014d-6"
Last-Modified: Fri, 26 Oct 2018 11:58:05 GMT
Server: nginx/1.15.5
​
Request Headers    # 请求头
GET /index.php HTTP/1.1      # 请求方法是GET;域名后面的部分就是路径,默认是‘/’;使用的HTTP协议是1.1 
Host: 192.168.31.43    # 访问的域名(域名或IP均可)
Connection: keep-alive    # 长连接
Upgrade-Insecure-Requests: 1    
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36   # 用户浏览器的类型
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8   # 可以接受的数据类型
Accept-Encoding: gzip, deflate      # 压缩
Accept-Language: zh-CN,zh;q=0.9     # 语言

  

1、基于host分发

  基于host分发这种分发方式适用于多集群分发。例如:一个公司有多个网站,每个网站就是一个集群。

在主分发器上设置

http {
    upstream web1 {   # 名为web1的反向代理群组
    server 192.168.199.228; 
    }
    upstream web2 {   # 名为web2的反向代理群组
    server 192.168.199.229;
    }
    server {    # web1虚拟主机
        listen 80;
        server_name www.web1.com;    # 基于域名分发必须有域名
        location / {
            proxy_pass http://web1; 
        }
    }
    server {    # web2虚拟主机
        listen 80;
        server_name www.web2.com;    # 基于域名分发必须有域名 
        location / {
            proxy_pass http://web2; 
        }
    }
}
 

  

选择web02做客户机,修改hosts文件

[root@web02 ~]# vi -r /etc/hosts
​
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain
4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain
6
​
192.168.199.226  www.web1.com
192.168.199.226  www.web2.com
~                                  

  

基于域名的分发测试:

[root@web02 ~]# elinks http://www.web1.com -dump
   web1
[root@web02 ~]# elinks http://www.web1.com -dump
   web1
[root@web02 ~]# elinks http://www.web2.com -dump
   web02
[root@web02 ~]# elinks http://www.web2.com -dump
   web02
[root@web02 ~]# 

  

 

2、基于开发语言分发

  这种分发方式适用于混合开发的网站,某些大型网站既有php也有jsp,就可以基于开发语言分发。

配置测试环境

选择web01作为php环境的业务服务器,web02直接还是写html页面

在web01上安装php环境并写一个简单的php页面

#yum安装php环境
[root@web01 ~]# yum -y install httpd php
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirror.sunnyvision.com
 * extras: mirror.sunnyvision.com
 * updates: mirror.hostlink.com.hk
base    
...
#关掉nginx,启动apache
[root@web01 ~]# killall nginx
[root@web01 ~]# systemctl start httpd
[root@web01 ~]# 
​
​
# 编写php文件到web1
[root@web01 html]# echo "<?php phpinfo();?>" >/var/www/html/index.php
[root@web01 html]# 
​
#直接访问web01测试下是否安装成功
在物理机的浏览器访问 http://192.168.199.228/index.php 

  

 

在主分发器上设置

# 192.168.199.226分发器上nginx配置
http {
    upstream php {
        server 192.168.199.228; 
    }
    upstream html {
        server 192.168.199.229;
    }
    server {
        location ~* \.php$ {    # 以php结尾的
            proxy_pass http://php;
        } 
        location ~* \.html$ {   # 以html结尾的
            proxy_pass http://html;
        }
    }
}

  

 

基于开发语言的测试

在物理机访问分发器的ip192.168.199.226/index.php 可以看到php-info信息页面

在物理机访问分发器的ip192.168.199.226/index.html 可以看到web02

 

 

3、基于浏览器的分发

  这种基于浏览器的分发,常应用于PC端和移动端区分或浏览器适配。

构建测试环境

停止使用web01的apache,启动nginx

[root@web01 ~]# systemctl stop httpd 
[root@web01 ~]# lsof -i :80
[root@web01 ~]# /usr/local/nginx/sbin/nginx
[root@web01 ~]# lsof -i :80
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   7301   root    6u  IPv4 421650      0t0  TCP *:http (LISTEN)
nginx   7302 nobody    6u  IPv4 421650      0t0  TCP *:http (LISTEN)
[root@web01 ~]# 
​

  

 

在web01上增加一个虚拟主机

http {
    server {
        listen   80;
        server_name localhost;
        location / {
            root  html;
            index  index.html  index.htm;
        }
    }
    server {
        listen  81;
        server_name  localhost;
        location / {
            root  web3;
            index  index.html  index.htm;
        }
    }
}
 

  

在web01写入测试文件,重启nginx,测试是否正常

[root@web01 nginx]# mkdir /usr/local/nginx/web3
[root@web01 nginx]# echo web03 > /usr/local/nginx/web3/index.html
[root@web01 nginx]# killall nginx
[root@web01 nginx]# ./sbin/nginx 
[root@web01 nginx]# elinks http://192.168.199.228:81 -dump
   web03
[root@web01 nginx]# 

  


 

在主分发器修改配置文件

upstream elinks { server 192.168.199.228; }
upstream chrome { server 192.168.199.229; }
upstream any { server 192.168.199.228:81; }
server {
    listen 80;
    server_name www.web1.com;
    location / {
        proxy_pass http://any;
        if ( $http_user_agent ~* Elinks ) {
            proxy_pass http://elinks;
        }
        if ( $http_user_agent ~* chrome ) {
            proxy_pass http://chrome;
        }
    }
}
 

  

重启nginx

[root@master nginx]# ./sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@master nginx]# killall nginx
[root@master nginx]# ./sbin/nginx
[root@master nginx]# lsof -i :80
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   3533   root    6u  IPv4 146667      0t0  TCP *:http (LISTEN)
nginx   3534 nobody    6u  IPv4 146667      0t0  TCP *:http (LISTEN)
[root@master nginx]# 

  


 

在客户机web02,物理机测试效果

[root@web02 ~]# elinks http://192.168.199.226 -dump
   web

  chrome浏览器测试结果

IE浏览器测试结果

 

 

4、基于源IP分发

  像腾讯新闻、58同城等等网站,往往在什么地方登陆则获取哪个地方的数据。服务器通过源IP匹配判断,从对应的数据库中获取数据。

 

(1)geo模块

  Nginx的geo模块不仅可以有限速白名单的作用,还可以做全局负载均衡,可以要根据客户端ip访问到不同的server。   geo指令是通过ngx_http_geo_module模块提供的。默认情况下,nginx安装时是会自动加载这个模块,除非安装时人为的手动添加--without-http_geo_module。   ngx_http_geo_module模块可以用来创建变量,其值依赖于客户端IP地址。

 

geo指令 语法: geo [$address] $variable { ... } 默认值: — 配置段: http 定义从指定的变量获取客户端的IP地址。默认情况下,nginx从$remote_addr变量取得客户端IP地址,但也可以从其他变量获得。如

geo $remote_addr $geo {
        default 0;
        127.0.0.1 1;
}
#如果用户的$remote_addr值是127.0.0.1 则返回 1,即$geo变量的值是1
geo $arg_ttlsa_com $geo {
        default 0;
        127.0.0.1 1;
}

  

(2)基于源IP主分发器的配置

修改主分发器的nginx配置

upstream bj.server {
    server 192.168.199.228;    # web01
}
upstream sh.server {
    server 192.168.199.229;      # web02
}
upstream default.server {
    server 192.168.199.228:81;      # web03
}
geo $geo {       # IP库
    default default;
    192.168.199.228/32 bj;    # 北京
    192.168.199.229/32 sh;   # 上海
}
server {
    listen  80;
    server_name   www.web1.com;
​
    location / {
        proxy_pass http://$geo.server$request_uri; #$request_uri传递原来的url的其他参数
    }
}

  

重启nginx

[root@master nginx]# ./sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@master nginx]# killall nginx
[root@master nginx]# ./sbin/nginx
[root@master nginx]# lsof -i :80
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   3609   root    6u  IPv4 152318      0t0  TCP *:http (LISTEN)
nginx   3610 nobody    6u  IPv4 152318      0t0  TCP *:http (LISTEN)
[root@master nginx]# 
​

  

访问测试验证

在web01测试

[root@web01 nginx]# elinks http://192.168.199.226 -dump
   web1
[root@web01 nginx]# 
​

  

在web02测试

[root@web02 ~]# elinks http://192.168.199.226 -dump
   web02
[root@web02 ~]# 
​

  

在物理机的测试

 

参考资料

[1]https://www.cnblogs.com/xiugeng/p/10155283.html

 

 

posted on 2020-01-28 19:17  Nicholas--  阅读(1415)  评论(0编辑  收藏  举报

导航