avatar

29.Nginx学习之路之七层负载均衡

在上一篇笔记中我们简单的了解了Nginx的基本知识,也动手搭建了我们的第一台Nginx服务器,并且实现了反向代理功能。那么今天我们继续来探究一下Nginx的另一个功能——负载均衡。话不多说,赶紧进入正题。
今日目标如下:
  1. 了解负载均衡基本含义;
  2. 动手搭建Nginx负载均衡;
  3. 使用Consul+upsync+Nginx实现动态负载均衡

0x01 负载均衡基本概念

  1. 官方表述什么是负载均衡(摘自百度百科)
    • 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
    • 负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
  2. 白话文描述什么是负载均衡
    • 每当一个请求过来时,首先会请求负载均衡服务器,然后负载均衡服务器通过一些算法(轮询、ip绑定、权重等)来确定去到哪台真实服务器,当然真实服务器需要构成一个集群,这样才算真正的负载均衡。
  3. 负载均衡的目的:
    • 减轻服务器压力。这个很明显就可以看出。没做负载均衡之前,所有的请求都压在一台服务器上。请求量一多,服务器自然而然就会挂,但是做了负载均衡后,减轻了压力,不同的请求,分发到不同的服务器上,并且如果集群中有台服务器挂了也不会影响整个系统的运行。
  4. 负载均衡带来的问题:
    • 要做负载均衡,真实服务器肯定要构成一个集群,其实与其说是负载均衡带来的问题,还不如说是集群带来的一些分布式的问题。
      • session一致性问题
      • 分布式事务问题
      • 分布式锁等问题
  5. 什么是7层负载均衡?
    1. 首先谈下OSI 7层网络模型。图如下:
      • 如图所示,从下到上,依次是物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。这些都是网络的基本概念,在这里我就不多说,反正当时背这个背的要死。
    2. 有了上面这张图,我们来说说7层负载均衡。
      • 这里的7层,不是指做了7层的负载均衡。而是基于OSI模型的应用层所做的负载均衡。是基于URL或者HTTP协议实现的。也就是基于Web请求,比较常见的就是Nginx的负载均衡
    3. 既然有了7层负载均衡,那么是不是还有其他层的负载均衡?答案是有的。比如4层复杂均衡。
      • 四层负载均衡,就是根据请求的ip+端口,根据设定的规则,将请求转发到后端对应的IP+端口上。即基于IP+端口的负载均衡。比较常见的就是LVS。但是Nginx在1.9.0之后,加了个stream模块用于实现4层负载均衡。
    4. 那么最后一个问题。4层和7层负载均衡区别是什么?
      • 四层负载均衡,在网络模型中的传输层中,基于主要是基于tcp协议报文实现负载均衡(比如LVS、haproxy就是四层负载均衡器),使用改写报文的源地址和目的地址。
      • 七层负载均衡,在网络模型中应用层中,基于URL或者HTTP协议实现负载均衡,Web服务器。

0x02 搭建Nginx负载均衡

  1. upstream块配置负载均衡用法

    • upstream块用于配置负载均衡。配置方法如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    upstream backServer{
    server 192.168.25.201:8080;
    server 192.168.25.202:8080;
    }

    #在server块里只需如下方式使用
    server{
    #监听80端口
    listen 80;
    server_name www.zyzling.top;
    location / {
    #在proxy_pass中指定upstream服务器(上游服务器)
    proxy_pass http://backServer;
    index index.html index.htm;
    }
    }
  2. 使用upstream搭建负载均衡

    • 说明:
      • web服务器使用tomcat,两个java项目,部署在不同的tomcat上,其中只有一个页面,模拟两台服务器
      • nginx在虚拟机中。在物理机访问虚拟机,然后虚拟机再通过负载均衡器访问到两台不同的java项目。
      • 172.16.53.131:8080/test1/test1.html页面如下:
      • 172.16.53.131:8081/test1/test1.html页面如下:
      • 目标效果:通过访问www.zyzling.top,每次都访问到不同的服务器。比如第一次是访问到test1,第二次访问到test2,第三次又访问到test1如此反复。
    • 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
      worker_processes  1;
      events {
      worker_connections 1024;
      }

      http {
      ##配置上游服务器 名称为zyzlingServer
      upstream zyzlingServer{
      server 172.16.53.131:8080;
      server 172.16.53.131:8081;
      }
      include mime.types;
      default_type application/octet-stream;

      sendfile on;

      keepalive_timeout 65;

      server {
      #监听80端口
      listen 80;
      #匹配www.zyzling.top这个域名
      server_name www.zyzling.top;
      #www.zyzling.top下面的所有请求
      location / {
      # 转发到上游服务器。
      proxy_pass http://zyzlingServer/;
      index index.html index.htm;
      }

      error_page 500 502 503 504 /50x.html;
      location = /50x.html {
      root html;
      }
      }
      }
    • 效果如下:
      • 第一次访问
      • 第二次访问
      • 可见,默认采用的负载均衡算法是轮询
  3. 负载均衡算法演示

    1. 轮询(默认采用的负载均衡算法)

      • 轮询的意识就是在upstream中配置的每台服务器都会按顺序循环被访问。效果在上面也演示了。如果不配置负载均衡算法,默认就是它了。
    2. 权重

      • 权重指的是在配置的upstream server后面加上访问这台服务器的权重。一般权重越大,访问该服务器的次数也就越多。
      • 配置方式:
        1
        2
        3
        4
        upstream zyzlingServer{
        server 172.16.53.131:8080 weight=1;
        server 172.16.53.131:8081 weight=2;
        }
        • 如上配置,8081端口的权重比8080端口大,所以请求的时候,访问8081端口的次数比8080端口的次数多。
    3. ip绑定(ip_hash)

      • 按字面意识理解,即它会把同一个ip的访客,绑定到一台服务器上,也就是说,如果你请求到的服务器是8080端口,在后续不管你怎么访问,在正常情况下,你永远访问的是8080端口这台服务器,因为你用的ip是一样的。其内部是按请求的ip进行hash结果分配。这种方式就可以解决分布式的Session共享问题。
      • 配置方式:
        1
        2
        3
        4
        5
        upstream zyzlingServer{
        server 172.16.53.131:8080;
        server 172.16.53.131:8081;
        ip_hash; ##在server下面写上ip_hash;即可
        }

0x03 Nginx动态负载均衡原理及搭建

  1. 动态负载均衡思路
    • 什么是动态负载均衡?
      • 如果不考虑动态负载均衡,我们之前每增加一台upstream server节点,或者修改权重,都要执行一次nginx -s reload去重新加载下配置文件,但是在这加载的过程中会断开所有的连接,其实也相当于先stop,然后在start,这样对线上用户当然体验不美好。而动态负载均衡的意思就是去动态修改upstream中的内容,却不需要重启服务器,配置就可以即时生效。
    • consul+upsync+nginx动态负载均衡实现思路
      • 使用consul作为我们存放我们配置的db,至于什么是consul,下面会简单介绍下。
      • 使用Nginx的第三方upsync模块,每隔一段时间去consul上面拉取我们配置的信息,动态更新Nginx配置。
      • 大致原理图如下:
  2. Consul简介
    • Consul是一个分布式服务注册发现中心,类似于Zookeeper。Consul通过HTTP API来实现服务注册、发现。具体等后面学习到SpringCloud的时候再详细介绍下。
    • consul启动命令解释
      • 先来一段命令./consul agent -dev -ui -node=consul-dev -client=0.0.0.0
        • consul:启动consul
        • agent:agent指令是consul的核心,它运行agent来维护成员的重要信息、运行检查、服务宣布、查询处理等等。
        • -dev:代表以dev模式启动,该模式kv存储不会持久化存储,全在内存中(重启consul就丢了!)
        • -ui:启动consul自带的web界面
        • -node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名
        • -client:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果你要对外提供服务改成0.0.0.0
    • consul启动后,访问ip:8500,我这里是访问192.168.25.201:8500.web页面效果:
    • consul对KV操作的HTTP API。官方文档地址:Consul官方文档
      • 添加、更新KV
        • url:v1/kv/{key}
        • method:PUT
        • head:Content-Type=application/json
      • 获取单个KV
        • url:v1/kv/{key}
        • method:GET
      • 获取该分类下所有KV
        • url:v1/kv/{key}?recurse
  3. upsync简介
    • upSync是新浪开发的一个Nginx第三方模块,用于从Consul上拉取配置文件,并动态更新Nginx的路由信息,upSync模块支持修改的属性有:weight、max_fails、fail_timeout、down。
      • weight:设置权重
      • max_fails:可以发生错误的最大次数
      • fail_timeout:在fail_timeout设定的时间内与后端服务器通信失败的次数超过max_fails设定的次数,则认为这个服务器不在起作用;在接下来的 fail_timeout时间内,nginx不再将请求分发给失效的server
      • down:如果需要临时移除某台服务器,可以把服务器的down置为1.相反,为0就代表可用。
  4. 使用Consul+Upsync+Nginx搭建动态负载均衡
    1. 下载consul。这里我们使用consul的版本为1.5.1 Linux命令如下:
      wget https://releases.hashicorp.com/consul/1.5.1/consul_1.5.1_linux_amd64.zip
    2. 下载upsync。upsync在github上开源,所以需要到github上下载最新版(master)。Linux命令如下:wget https://github.com/weibocom/nginx-upsync-module/archive/master.zip
    3. 下载Nginx。注意,这里的Nginx版本要在1.9.0以上
    4. 使用unzip命令解压consul(如果找不到unzip命令,则使用yum install unzip安装下)。
    5. 执行./consul命令确保可以运行。出现如下界面说明consul已经没有问题;
    6. 使用unzip解压upsync
    7. 解压Nginx
    8. 添加Nginx用户和组
      • groupadd nginx
      • useradd -g nginx -s /sbin/nologin nginx
      • mkdir -p /var/tmp/nginx/client/
      • mkdir -p /usr/local/nginx
      • 如果没有执行上面的命令。在启动Nginx的时候会报如下错误:
    9. 编译Nginx并安装。
      • 执行./configure命令。
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        ./configure 
        --prefix=/usr/local/nginx
        --user=nginx
        --group=root
        --with-http_ssl_module
        --with-http_flv_module
        --with-http_stub_status_module
        --with-http_gzip_static_module
        --with-http_realip_module
        --http-client-body-temp-path=/var/tmp/nginx/client/
        --http-proxy-temp-path=/var/tmp/nginx/proxy/
        --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/
        --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi
        --http-scgi-temp-path=/var/tmp/nginx/scgi
        --with-pcre
        --add-module=../nginx-upsync-module-master
      • 执行make && make install安装Nignx
    10. 配置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
      worker_processes  1;
      events {
      worker_connections 1024;
      }
      http {
      include mime.types;
      default_type application/octet-stream;

      upstream zyzlingServer {
      #使用upsync指定consul中拉取kv的地址。
      #upsync_timeout表示从consul拉取配置的超时时间
      #upsync_interval表示每隔500ms就去consul中获取一次
      #strong_dependency配置nginx在启动时是否强制依赖配置服务器,如果配置为on,则拉取配置失败时nginx启动同样失败
      upsync 192.168.25.201:8500/v1/kv/zyzling/ upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;
      # upsync_dump_path,指定从consul拉取的上游服务器后持久化到的位置,这样即使consul服务器出问题了,本地还有一个备份。
      upsync_dump_path /usr/local/nginx/conf/servers/servers_dump.conf;
      }

      sendfile on;
      keepalive_timeout 65;

      server {
      listen 80;
      server_name www.zyzling.top;
      location / {
      proxy_pass http://zyzlingServer/;
      index index.html index.htm;
      }

      error_page 500 502 503 504 /50x.html;
      location = /50x.html {
      root html;
      }

      }
      }
    11. 创建upsync_dump_path。mkdir -p /usr/local/nginx/conf/servers
    12. 启动consul,启动命令如下:./consul agent -dev -ui -node=consul-dev -client=0.0.0.0
    13. 使用postman调用Consul的http API。putKV键值对。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      url:http://192.168.25.201:8500/v1/kv/zyzling/172.16.53.131:8080
      param:
      {
      "weight":2,
      "max_fails":2,
      "fail_timeout":10,
      "down":0
      }
      url:http://192.168.25.201:8500/v1/kv/zyzling/172.16.53.131:8081
      param:
      {
      "weight":1,
      "max_fails":2,
      "fail_timeout":10,
      "down":0
      }
      • 执行后,到consul的web界面的看看效果。
        • 发现如果Consul帮我们分类了。点进去如下:
        • 再点进去,就是我们设置的值了。如下:
    14. 启动我们的Nginx。看看效果。
  5. 结果演示

    • 根据我们的负载均衡权重配置,8080端口(test1)的这台服务器的权重要比8081(test2)的大。所以访问8080端口的次数会多一些.
    • 使用postman请求consul,删除8081(test2)节点。看看效果怎样。
      • 请求:http://192.168.25.201:8500/v1/kv/zyzling/172.16.53.131:8081
      • method:DELETE
      • 结果:
      • 结果所有的请求都只会请求到8080端口(test1)上。

0x04 参考资料


评论