nginx配置之负载均衡

前提

nginx配置中负载均衡是web开发中常用技能,用于处理大量用户访问、高并发请求,海量数据,意义:将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。

1、高性能

解决并发压力,提高应用处理性能(增加吞吐量,加强网络处理能力)

2、单点故障(高可用)

出现异常时,可以通过只转移其中一个机器就可以实现服务平稳恢复

3、扩展性(水平伸缩)

可以添加或减少服务器数量,达到性能的提升

  • 反向代理(Reverse Proxy)

以代理服务器来接受网络连接请求,将请求转发给内部网络各个集群的服务器,并将各个服务器上得到的结果返回给请求的客户端(浏览器)。

反向代理还有另一个好处就是:安全

因为它与正向代理相反, 用户只知道他访问的是反向代理服务器,而不知道他访问的是A资源还是B资源或者C资源。

配置

添加 配置在http{}中,如

upstream myServer{
    server 10.1.0.1:80;  #这里是你自己要做负载均衡的服务器地址1
    server 10.1.0.2:8080; #这里是要参与负载均衡的地址2
}

配置一个web server服务转发到myServer

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include      mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream myServer{
        server 10.1.0.1:80;  #这里是你自己要做负载均衡的服务器地址1
        server 10.1.0.2:8080; #这里是要参与负载均衡的地址2
    } 
    server {
        listen      80;
        server_name  www.testing.com;
        location / {
        proxy_pass  http://myServer;
        }
    }
}

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

1、轮询(默认)

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

weight配置参数指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。

1:1负载, weight=1

当upstream配置块没有指定使用的分配算法时,默认使用加权轮询. 比如上面的例子,再比如:

#max_fails 允许请求失败的次数默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误
#fail_timeout max_fails次失败后,暂停的时间。
#以下的两个后端程序的权重是一样的,都是9(weight值越大权重越大,但是没有区别开来,一样视为1:1)
 upstream tomcats {
     server 10.1.0.1:80  max_fails=3 fail_timeout=3s weight=9;
     server 10.1.0.2:8000  max_fails=3 fail_timeout=3s weight=9;
 }

1:n负载, weight=n

再例如,下面这个就是不同权重。即可以简单理解为b流量会是c的两倍,a是c的4倍.

upstream backend  {
  server a.example.com weight=4;
  server b.example.com weight=2;
  server c.example.com weight=1;
}

2、RR策略

详细说来,每个后端都有三个权重变量:

(1)、weight

配置文件中指定的该后端的权重,这个值是固定不变的。

(2)、effective_weight

后端的有效权重,初始值为weight。

在释放后端时,如果发现和后端的通信过程中发生了错误,就减小effective_weight。

此后有新的请求过来时,在选取后端的过程中,再逐步增加effective_weight,最终又恢复到weight。

之所以增加这个字段,是为了当后端发生错误时,降低其权重。

(3)、current_weight

后端目前的权重,一开始为0,之后会动态调整。

当一个客户请求到达后,RR策略是从upstream的所有server中选择一个当前权重(current_weight)最大的server作为最初的server.

upstream的所有server是按照由高到低排序后存储在一个peers数组(后备队列)中,当最初选择的server不能提供服务时,RR策略就会选择peers数组中的下一个元素作为当前server,继续尝试, 如果已经达到数组的最大元素,就会从第一个元素再轮循。

加权轮询算法可描述为:

1、对于每个请求,遍历集群中的所有可用后端,对于每个后端peer执行:

peer->current_weight += peer->effecitve_weight。

同时累加所有peer的effective_weight,保存为total。

2、从集群中选出current_weight最大的peer,作为本次选定的后端。

3、对于本次选定的后端,执行:peer->current_weight -= total。

以上面1:n加权例子说明,每7个客户端请求中,a会被命中4次,b命中2次,c命中1次;正常运行分配.

我们来初始化一个peer(一个请求)中各个server(a,b,c)的current_weight值为{0, 0, 0}

通过上述过程,可得以下结论:

--- 7个请求中,a、b、c分别被选取了4、2、1次,符合它们的权重值。

--- 7个请求中,a、b、c被选取的顺序为a, b, a, c, a, b, a,分布均匀,权重大的后端a没有被连续选取。

--- 每经过7个请求后,a、b、c的current_weight又回到初始值{ 0, 0, 0 },因此上述流程是不断循环的。

3、ip_hash

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

upstream backend {
  server 127.0.0.1:8080 ;
  server 127.0.0.1:9090 ;
  ip_hash;
}

原理是: 根据请求客户端的IP计算出一个哈希值,再根据哈希值选择后台的服务器。

由IP计算哈希值的算法如下, 其中公式中hash初始值为89,iphp->addr[i]表示客户端的IP, 通过三次哈希计算得出一个IP的哈希值: 

for (i = 0; i < 3; i++) {
    hash = (hash * 113 + iphp->addr[i]) % 6271; 
}

在选择下一个server时,ip_hash的选择策略是这样的:    

它在上一次哈希值的基础上,再次哈希,就会得到一个全新的哈希值,再根据哈希值选择另外一个后台的服务器。 

哈希算法仍然是 

for (i = 0; i < 3; i++) {
    hash = (hash * 113 + iphp->addr[i]) % 6271;
} 

注意

ip_hash要求nginx一定是最前端的服务器,否则nginx得不到正确ip,就不能根据ip作hash。

1、squid做为最前端,这样到达nginx的都为固定ip,分流不起作用。

2、多层负载均衡时要注意。

4)、fair(第三方)

按后端服务器的响应时间来分配请求,响应时间短的优先分配。

5)、url_hash(第三方)