聊聊负载均衡

750 阅读4分钟

一般情况下,客户端发送多个请求到服务器,服务器处理请求,其中一部分可能要操作一些资源比如数据库、静态资源等,服务器处理完毕后,再将结果返回给客户端。

这种模式对于早期的系统来说,功能要求不复杂,且并发请求相对较少的情况下还能胜任,成本也低。随着信息数量不断增长,访问量和数据量飞速增长,以及系统业务复杂度持续增加,这种做法已无法满足要求,并发量特别大时,服务器容易崩。

很明显这是由于服务器性能的瓶颈造成的问题,除了堆机器之外,最重要的做法就是负载均衡。

请求爆发式增长的情况下,单个机器性能再强劲也无法满足要求了,这个时候集群的概念产生了,单个服务器解决不了的问题,可以使用多个服务器,然后将请求分发到各个服务器上,将负载分发到不同的服务器,这就是负载均衡,核心是「分摊压力」。Nginx 实现负载均衡,一般来说指的是将请求转发给服务器集群。

比如晚高峰乘坐地铁的时候,入站口经常会有地铁工作人员大喇叭“请走 B 口,B 口人少车空....”,这个工作人员的作用就是负载均衡。

负载均衡

负载均衡(Load Balance),是一种计算机技术,意思是将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。是解决高性能,单点故障(高可用),扩展性(水平伸缩)的终极解决方案。负载平衡服务通常可以由专用软件(nginx、Lvs等)和硬件(F5负载均衡器)来完成。

负载均衡的作用:

  • 解决并发压力,提高应用处理性能(增加吞吐量,加强网络处理能力);
  • 提供故障转移,实现高可用;
  • 通过添加或减少服务器数量,提供网站伸缩性(扩展性);
  • 安全防护,做一些过滤,黑白名单等处理。

常用算法

轮询法-随机法

将请求按照顺序轮流的分配到服务器上,它均衡的对待每一台后端的服务器,不关心服务器的的连接数和负载情况. 适用于每台服务器处理的事情和处理能力都差不多的情况。

加权轮询法

以轮询的方式依次请求调度不同的服务器;实现时,一般为服务器带上权重; 这样有两个好处:

  • 针对服务器的性能差异可分配不同的负载;
  • 当需要将某个结点剔除时,只需要将其权重设置为0即可;

最小连接-最快响应

通过连接数和响应时间来分配,也就是根据服务器当前剩余的能力来分配任务。也是最靠谱的方案。

实现

2层:对外IP转发不同的mac地址。 3层:对外IP转发对内IP。 4层:建立在传输层,将数据包(流量)转发到指定的IP+端口。 7层:建立在引用层,基于URL等应用层信息做转发。

通常我们都用的nginx做7层负载均衡,实现:

nginx的反向代理有几种实现方式:

  1. 仅使用模块ngx_http_proxy_module实现简单的反向代理。指令为proxy_pass。
  2. 使用fastcgi模块提供的功能,反向代理动态内容。指令为fastcgi_pass。
  3. 使用ngx_http_memcached_module模块提供的功能,反向代理memcached缓存内容,指令为memcached_pass。
  4. 结合upstream模块实现更人性化的分组反向代理。

使用模块ngx_http_proxy_module实现简单的反向代理

//反向代理服务器nginx-proxy(192.168.100.29)的配置

server {
      listen       80;
      server_name  www.test.com;
      location ~ \.(png|jpg|jpeg|bmp|gif)$ {
          proxy_pass http://192.168.100.28:80;
      }
      location / {
          proxy_pass http://192.168.100.30:80/;
      }
      location ~ \.(php|php5)$ {
          proxy_pass http://192.168.100.25:80;
      }
      error_page   500 502 503 504  /50x.html;
      location = /50x.html {
          root   html;
      }
    }
  
//提供动态服务的nginx服务器(192.168.100.25)的配置
server {
    listen       80;
    server_name  www.test.com;
    location / {
        root    /www/test/;
        index   index.php index.html index.htm;
    }
    location ~ \.php$ {
        root /php/;
        fastcgi_pass    192.168.100.27:9000;
        fastcgi_index   test.php;
        include         fastcgi.conf;
    }
}

//php-fpm服务器(192.168.100.27)上的/www/test/index.php
<h1>page from php-fpm</h1> 
 <?php 
  phpinfo();
?>

详细语法:

  • proxy_buffer_zize
  • proxy_set_header:在将客户端请求发送给后端服务器之前,更改来自客户端的请求头信息;
  • proxy_hide_header:隐藏头
  • proxy_connect_timeout:配置 Nginx 与后端代理服务器尝试建立连接的超时时间;
  • proxy_read_timeout:配置 Nginx 向后端服务器组发出 read 请求后,等待相应的超时时间;
  • proxy_send_timeout:配置 Nginx 向后端服务器组发出 write 请求后,等待相应的超时时间;
  • proxy_redirect:用于修改后端服务器返回的响应头中的 Location 和 Refresh。

使用upstream模块实现分组反向代理

借助ngx_http_upstream_module模块,该模块用于定义后端服务器池,后端服务器也称为上游服务器(upstream),可以为每一种类型的后端服务器分一个组。然后在结合proxy_pass或其他代理指令将相应的请求转发到池内。

服务器池可以有多台服务器,多台服务器如何实现负载均衡和算法有关,默认是指定权重的加权均衡算法。

http {
    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;

    # define server pool
    upstream dynamic_pool {
        server IP1:80;
    }
    upstream pic_pool {
        server IP3:80 weight=2;
        server IP4:80 weight=1;
    }
    upstream static_pool {
        server IP5:80 weight=1;
        server IP6:80 weight=1;
    }

    server {
        listen 80;
        server_name www.test.com;

        # define how to proxy
        location ~ \.(php|php5)$ {
            proxy_pass http://dynamic_pool;
        }
        location ~ \.(png|jpeg|jpg|bmp|gif)$ {
            proxy_pass http://pic_pool;
        }
        location / {
            proxy_pass http://static_pool;
        }
    }
}

后端服务器在负载均衡调度中的状态: down:当前的server暂时不参与负载均衡

  • backup:预留的备份服务器
  • max fails:允许请求失败的次数
  • fail timeout:经过max,fails失败后,服务暂停的时间
  • max conns:限制最大的接收的连接数

调度算法:

  • 轮询:按时间顺序逐一分配到不同的后端服务器
  • 加权轮询:weight值越大,分配到的访问几率越高。
  • ip_hash:每个请求按访问IP的hash结果分配,这样来自同一个IP的固定访问一个后端服务器。
  • least conn:最少链接数,那个机器连接数少就分发。
  • url hash:按照访问的URL的hash结果来分配请求,是每个URL定向到同一个后端服务器。
  • hash关键数值:hash自定义的key,比如用户ID。