• 【从单体架构到分布式架构】(三)请求增多,单点变集群(2):Nginx


    上一个章节,我们学习了负载均衡的理论知识,那么是不是把应用部署多套,前面挂一个负载均衡的软件或硬件就可以应对高并发了?其实还有很多问题需要考虑。比如:
    
    1. 当一台服务器挂掉,请求如何转发到其他正常的服务器上?
    2. 挂掉的服务器,怎么才能不再访问?
    3. 如何保证负载均衡的高可用性?
    
    等等等等...
    
    让我们带着这些问题,实战学习一下 Nginx 的配置和使用。
    

    1. 前置概念

    在正式介绍 Nginx 之前,首先让我们先了解一下概念。

    1. 中间件

    干 IT 太累了,我准备辞职开了个烧烤摊,卖羊肉串;

    卖羊肉串首先就得有羊肉,于是我就联系了很多养殖场,我又是一个比较负责任的人,为了保证羊肉的质量,我就去考察了一家又一家养殖场,同时我也是个“小气”的人,所以我考察过程中,和对方谈判、比价,最终选了一个养殖场作为我的羊肉供应商,为我提供羊肉。

    经营了一阵子,这个养殖场提供的羊肉质量没有以前好了,那么我就重新考察、谈判、比价,如此反复,我投入了大量的时间和精力。

    于是我找到了一个信得过的代理公司,约定要羊肉的质量和数量,谈好价钱,以后我只找代理商拿货,具体代理商找的哪家养殖场我不去过问,甚至代理商可以送货上门。

    在这个例子里面,卖烧烤就是业务,我的烧烤摊是业务端,养殖场是底层,而 这个信得过的代理公司,就是中间件。

    2. 正向代理和反向代理

    正向代理:我住在北京,但是想回老家买套房,但是我没办法亲自回老家考察,于是我就派我的管家回老家考察;管家就是正向代理服务器;正向代理服务器代表了客户端,在正向代理的过程中,服务端只和代理服务器打交道(房东只和我的管家谈),并不知道真正的客户端是谁。

    正向代理

    反向代理:我住在北京,但是想回老家买套房,但是我没办法亲自回老家考察,于是我打个电话联系了老家的房屋中介去办这件事儿;房屋中介就是反向代理;这里的反向代理,代表的是房东,在反向代理的过程中,客户端只和反向代理服务器打交道,并不知道真正的服务端是谁。

    反向代理

    当然,我的管家也可以联系我老家的房屋中介,那么架构图就会变成:

    2. Nginx 的概念

    了解完上面的几个概念,那么 Nginx 的概念理解起来就简单很多了:

    Nginx 就是一个开源的、高性能的、可靠的 Http 中间件; 它经常被用作 Http 代理、反向代理、负载均衡等等,当然它也能做正向代理,但是实际很少有这么用的。

    3. 最简单的 Nginx 使用示例

    本章节项目的代码:chapter3

    Step 1. 部署多套环境

    我们将章节 1 中的项目 chapter1 复制出来一份,改名为 chapter3,表示是第 3 章节的项目,同时修改:

    1. pom.xml 中的 artifactId 修改为 chapter3
    2. application.yml 中的 server.port 修改成 8089

    这样我们分别启动 chapter1 和 chapter3,这样就相当于把相同的项目部署了两套,端口分别是 8088 和 8089 。

    Step 2. 下载 Nginx

    我们可以在 Nginx 的官网 下载我们所需的版本,因为我使用 windows 环境开发,所以我在这里就选择了 nginx/Windows-1.14.2 这个版本。

    下载完成解压缩,不需要额外的安装,可以直接使用。

    Step 3. 配置 Nginx

    进入 nginx-1.14.2conf 目录下,用文本编辑器打开 nginx.conf,对配置文件进行如下修改:

    1. 在 http 中增加 upstream,并配置两台环境的地址;
    2. 在 http.server.location 中增加 proxy_pass 的配置;

    http {
        ...
    
        #增加 upstream 的配置,其中 myserver 是自己起的名字
        upstream myserver{
    	     server 127.0.0.1:8088;  #有几套环境,就配置几条
    	     server 127.0.0.1:8089;
        }
    
        server {
            listen       80;
            server_name  localhost;
    
            #charset koi8-r;
    
            #access_log  logs/host.access.log  main;
    
            location / {
                root   html;
                index  index.html index.htm;
                proxy_pass  http://myserver; #增加,其中 http://myserver 的 myserver 要和上文对应
            }
    
          }
        }
        ...
    }
    

    完整配置文件请参考:nginx.conf

    Step 4. 启动 Nginx

    我们可以直接双击 nginx-1.14.2 目录下的 nginx.exe 启动;也可以通过 cmd 命令打开控制台,进入 nginx-1.14.2 目录执行如下命令启动 Nginx:

    start nginx //启动 Nginx ;启动后可能一闪而过,我们可以看一下任务管理器是否有名字叫做 nginx.exe 的进程
    
    nginx.exe -s stop //停止 Nginx
    nginx.exe -s quit //停止 Nginx
    

    nginx-start

    Step 5. 测试 Nginx

    让我们测试一下 Nginx 是否配置并启动成功,打开浏览器输入:

    http://127.0.0.1/queryAdmin
    

    注意这里并没有加端口号,是因为 url 中没有端口号的时候表示端口号为 80,而我们 Nginx 的配置文件中,监听的正是 80 端口 (listen 80);我们可以在浏览器中看到服务返回的结果:

    User : Admin
    

    这就说明 Nginx 已经转发了我们的请求到了服务端,并正确返回,那么负载均衡是如何体现的呢?让我们多刷新几次浏览器,然后看看后台日志:

    console

    我前后一共调用了 5 次服务,可以看到两个服务端分别接收到了 2 次和 3 次请求,负载均衡达到了效果。

    4. Nginx 常见的路由策略

    1. 轮询法

    最简单的轮询法,多余的配置不需要增加。

    upstream myserver{
       server 127.0.0.1:8088;  # 有几套环境,就配置几条
       server 127.0.0.1:8089;
    }
    

    2. 源地址哈希法

    使用 ip_hash 关键字,每一个请求,都按 hash(IP) 的结果决定访问哪台服务器;

    upstream myserver{
       ip_hash; # hash(IP)
       server 127.0.0.1:8088;  # 有几套环境,就配置几条
       server 127.0.0.1:8089;
    }
    

    如果我们本地测试,多次访问接口,可以发现请求永远落到同一个服务上,因为本地 IP 一直没有改变。

    console_ip

    3. 加权轮询法

    使用 weight 关键字,设置每台服务器的权重;

    upstream myserver{
       server 127.0.0.1:8088 weight=1;  # 20% 请求会发给8088
       server 127.0.0.1:8089 weight=4;
    }
    

    console_weight

    4. 最小连接数法

    根据每个服务器节点的连接数,动态地选择当前连接数最少的服务器转发请求;

    upstream myserver{
       least_conn;
       server 127.0.0.1:8088;
       server 127.0.0.1:8089;
    }
    

    5. 最快响应速度法

    根据每个服务器节点的响应时间(请求的往返延迟),动态地选择当前响应速度最快的服务器转发请求;需要额外安装 nginx-upstream-fair 模块。

    upstream myserver{
       fair; # 额外安装 nginx-upstream-fair 模块
       server 127.0.0.1:8088;
       server 127.0.0.1:8089;
    }
    

    6. URL 哈希算法

    对 URL 进行 Hash 运算,根据结果来分配请求,这样每个 URL 都可以访问到同一个服务端;当服务端有缓存的时候,比较有效。

    upstream myserver{
       hash $request_uri;
       server 127.0.0.1:8088;  # 有几套环境,就配置几条
       server 127.0.0.1:8089;
    }
    

    也可以安装第三方模块,比如我们要使用 URL 一致性哈希算法,那么我们可以安装 ngx_http_upstream_consistent_hash 模块。

    upstream myserver{
       consistent_hash $request_uri;
       server 127.0.0.1:8088;
       server 127.0.0.1:8089;
    }
    

    参考资料:Upstream Consistent Hash

    5. Nginx 常用功能

    5.1 请求失败重试

    当一台服务器挂掉,请求如何转发到其他正常的服务器上?
    

    我们可以先做个试验,就是关闭 8089 端口的服务,只保留 8088 端口的服务,然后调用几次接口,如果其中一次调用长时间不返回(浏览器访问状态图标一直在打转),表示本次请求发送到了 8089 端口,那么让我们等待一段时间...大约一分钟之后,8080 端口服务的后台日志,打印出来日志,调用端接收到了返回,这说明:

    1. Nginx 默认有失败重试机制;
    2. 默认的超时时间为 60s 。

    console-one-down

    这里的超时时间是可以修改的,需要在 http.server.location 中增加如下配置:

    location / {
                root   html;
                index  index.html index.htm;
                proxy_pass  http://myserver;
                proxy_connect_timeout 5; # 连接超时时间
                proxy_send_timeout 5; # 发送数据给后端服务器的超时时间
                proxy_read_timeout 5; # 后端服务器的相应时间
                #proxy_next_upstream off; # 是否要关闭重试机制
            }
    

    完整配置文件请参考:设置超时重试时间5秒-nginx.conf

    不过这里要注意一点,如果设置了服务器相应超时时间(比如设置了 10s ),万一应用的业务处理时间比较慢(业务处理花费了 15s ),那么会导致 Nginx 超时重试,那么可能会造成重复处理。

    5.2 后端服务器节点健康状态检查

    如果挂掉一台服务器,路由到这台服务器请求每次都要等到超时时间过去,才能发起重试,如果 Nginx 不再把请求发送给挂掉的服务器,那就省事多了;
    
    这就叫做“后端服务器节点健康状态检查”。
    

    如果不安装第三方模块,可以做如下配置完成“后端服务器节点健康状态检查”:

    1. 设置超时时间:

    location / {
                root   html;
                index  index.html index.htm;
                proxy_pass  http://myserver;
                proxy_connect_timeout 5; # 连接超时时间
                proxy_send_timeout 5; # 发送数据给后端服务器的超时时间
                proxy_read_timeout 5; # 后端服务器的相应时间
                #proxy_next_upstream off; # 是否要关闭重试机制
            }
    

    2. 设置尝试重试的次数:

    upstream myserver{
      	server 127.0.0.1:8088 max_fails=1 fail_timeout=100s;
      	server 127.0.0.1:8089 max_fails=1 fail_timeout=100s;
    }
    

    其中 max_fails 表示最多失败次数,fail_timeout 表示在一个时间段内,服务器不会再次尝试访问;上面的配置表示在 100s 内,只要超时失败 1 次,就不再访问该服务器。

    完整配置文件请参考:设置超时重试时间5s-失败1次100秒之内不再访问-nginx.conf

    除此之外,我们还可以安装第三方模块来实现“后端服务器节点健康状态检查”:

    5.3 Nginx 的高可用

    以为使用 Nginx ,部署了多台应用服务器,可以保证应用服务器的高可用(挂掉一台,还有其他服务器可以用);
    
    但是如何保证负载均衡的高可用性?也就是万一 Nginx 挂了怎么办?
    

    Nginx 同样也需要部署多台,架构大概是这个样子的:

    nginx-master-backups

    现在应用比较广泛的是利用 keepalived 实现 Nignx 的高可用:
    nginx-keeplived-1
    nginx-keeplived-2

    5.4 其他

    除了以上的常见功能,强大的 Nginx 还可以:

    1. 限制 IP 访问频率和带宽占用;
    2. 缓存静态资源;
    3. 文件压缩;
    4. TCP 负载;
    5. 防盗链;
    6. 等等等等...

    总结

    我们现在的架构已经变成了:

  • 相关阅读:
    Delphi公用函数单元
    Delphi XE5 for Android (十一)
    Delphi XE5 for Android (十)
    Delphi XE5 for Android (九)
    Delphi XE5 for Android (八)
    Delphi XE5 for Android (七)
    Delphi XE5 for Android (五)
    Delphi XE5 for Android (四)
    Delphi XE5 for Android (三)
    Delphi XE5 for Android (二)
  • 原文地址:https://www.cnblogs.com/CodeDaShu/p/13118284.html
Copyright © 2020-2023  润新知