Nginx负载均衡

什么是反向代理

反向代理是指以代理服务器来接收Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从内部网络服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外表现为一个服务器

有反向代理,自然也存在正向代理的概念。正向代理是一个位于客户端和目标服务器之间的代理服务器(中间服务器)。为了从目标服务器获取内容,客户端向代理服务器发送一个请求,并且指定目标服务器,之后代理向目标服务器转交并且将获得的内容返回给客户端。正向代理的情况下需要客户端进行一些特别的设置才能使用

反向代理正好相反。对于客户端来说,反向代理就好像是目标服务器,并且客户端不需要进行任何设置。客户端向反向代理发送请求,接着反向大力判断请求转向,并将响应内容转交给客户端,使得这些内容好似是代理服务器的一般,客户端不会感知到代理服务器后面的服务,因为客户端不需要进行任何的设置,只需要把代理服务器当成真正的服务器就好。

区别

正向代理需要你主动设置代理服务器ip或者域名进行访问,由设置的服务器ip或者域名去获取访问内容并返回;而反向代理不需要你做任何设置,直接访问服务器真实ip或者域名,但是服务器内部会自动根据访问内容进行跳转及内容返回,你不知道它最终访问的是哪些机器。

正向代理是代理客户端,为客户端收发请求,使真实客户端对服务器不可见;而反向代理是代理服务器端,为服务器收发请求,使真实服务器对客户端不可见

  1. 正向代理:正向代理允许客户端通过它访问任意网站并且隐蔽客户端自身,因此你必须采取安全措施来确保仅为经过授权的客户端提供服务
  2. 反向代理:对外是透明的,访问者并不知道自己访问的是代理。对访问者而言,他以为访问的就是原始服务器

Nginx负载均衡
Nginx负载均衡

为什么使用反向代理

  1. 保护网站安全,任何来自Internet的请求都必须先经过代理服务器
  2. 实现负载均衡。减轻服务器压力

负载均衡

upstream机制使得Nginx以反向代理的形式运行。当Nginx接收来自客户端的请求时,根据客户端的请求选择后端服务器。但是若存在多台后端服务器时,Nginx则需要利用负载均衡策略决定哪个后端服务器接收此请求

负载均衡策略

Nginx的负载均衡策略可以划分为两大类:内置策略和扩展策略。内置策略包括加权轮询和ip hash,在默认情况下,这两种策略会被编译进Nginx内核,只需在Nginx配置中指明参数即可。

加权轮询

Nginx负载均衡
Nginx采用先深搜索算法,首先将请求都分配给高权重的机器,知道该机器的权值降到了比其他机器低,才开始将请求分配给下一个高权重的机器。当所有的后端服务器都down掉时,Nginx会立即将所有机器的标志位清成初始化状态,避免所有机器处于timeout状态。

最少连接

Web请求会被转发到连接数最少的服务器上

http{ 
  upstream sampleapp { 
    least_conn; #设置最少连接负载均衡策略
    server <<dns entry or IP Address(optional with port)>>; 
    server <<another dns entry or IP Address(optional with port)>>; 
  } 
  .... 
  server{ 
    listen 80; 
    ... 
    location / { 
     proxy_pass http://sampleapp; 
    }  
  } 
ip_hash

前面两种负载均衡策略中,同一客户端连续的Web请求可能会被分发到不同的后端服务器上,因此如果涉及到会话Session,则会话比较复杂,后台处理数据时稍显复杂。
可以使用基于IP地址哈希的负载均衡策略,这样的话,同一客户端连续的Web请求都会被分发到同一服务器进行处理。
ip_hash算法的原理很简单,根据请求所属的客户端IP计算得到一个数值,然后把请求发往该数值对于的后端。

Nginx负载均衡
ip hash算法的核心实现如下:

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

 p = hash % iphp->rrp.peers->number;        

第一步,根据客户端IP计算得到一个数值。

hash1 = (hash0 * 113 + addr[0]) % 6271;
hash2 = (hash1 * 113 + addr[1]) % 6271;
hash3 = (hash2 * 113 + addr[2]) % 6271;

hash3就是计算所得的数值,它只和初始数值hash0以及客户端的IP有关

第二步,根据计算所得数值,找到对应的后端

w = hash3 % total_weight;
while (w >= peer->weight) {
w -= peer->weight;
peer = peer->next;
p++;
}

total_weight为所有后端权重之和。遍历后端链表时,依次减去每个后端的权重,直到w小于某个后端的权重。选定的后端在链表中的序号为p。因为total_weight和每个后端的weight都是固定的,所以如果hash3值相同,则找到的后端相同

http{ 
  upstream sampleapp { 
    ip_hash; #设置ip_hash负载均衡策略
    server <<dns entry or IP Address(optional with port)>>; 
    server <<another dns entry or IP Address(optional with port)>>; 
  } 
  .... 
  server{ 
    listen 80; 
    ... 
    location / { 
     proxy_pass http://sampleapp; 
    }  
  } 
 
fair

fair策略是扩展策略,默认不被编译进Nginx内核。其原理是根据后端服务器的响应时间判断负载情况,从中选出负载最轻的的机器进行分流。这种策略具有很强的适应性,但是实际的网络环境往往部署那么简单,因此慎用。

通用hash和一致性hash

这两种也是扩展策略,在具体的实现上有些差别,通用hash比较简单,可以以nginx内置的变量为key进行hash,一致性hash采用了nginx内置的一致性hash环,可以支持memcache

本文借鉴于此