Skip to content

Instantly share code, notes, and snippets.

@banjin
Last active September 16, 2023 09:39
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save banjin/cf8d890591aa6c16d09e4ebfa6471284 to your computer and use it in GitHub Desktop.
Save banjin/cf8d890591aa6c16d09e4ebfa6471284 to your computer and use it in GitHub Desktop.
在工作中经常使用Nginx的IP_hash策略做负载均衡,所以记录一下使用中的疑惑。
当对后端的多台动态应用服务器做负载均衡时,ip_hash指令能够将某个客户端IP的请求通过哈希算法定位到同一台后端服务器上。这样,当来自某个IP的用户在后端Web服务器A上登录后,再访问该站点的其他URL,能够保证其访问的还是后端Web服务器A。
如果不采用ip_hash指令,假设来自某个IP的用户在后端Web服务器A上登录后,再访问该站点的其他URL,有可能被定向到后端Web服务器B,C...上,由于用户登录后SESSION信息是记录在服务器A上的,B,C...上没有,这时就会提示用户来登录
在ip_hash策略中,它选择最初的server的方法是根据请求客户真个IP计算出一个哈希值,再根据哈希值选择后台的服务器。
1)由IP计算哈希值的算法如下, 其中公式中hash初始值为89,iphp->addr[i]表示客户真个IP, 通过三次哈希计算得出一个IP的哈希值:
  for (i = 0; i < 3; i++) {
  hash = (hash * 113 + iphp->addr[i]) % 6271;
  }
2)在选择下一个server时,ip_hash的选择策略是这样的:
  它在上一次哈希值的基础上,再次哈希,就会得到一个全新的哈希值,再根据哈希值选择另外一个后台的服务器。
  哈希算法仍然是
  for (i = 0; i < 3; i++) {
   hash = (hash * 113 + iphp->addr[i]) % 6271;
  }
在这种ip_hash策略,假如一个后台服务器不能提供提服务(连接超时或读超时),该服务器的失败次数就会加一,当一个服务器的失败次数达到max_fails所设置的值,就会在fail_timeout所设置的时间段内不能对外提供服务,这点和RR是一致的。
假如当前server不能提供服务,就会根据当前的哈希值再哈希出一个新哈希值,选择另一个服务器继续尝试,尝试的最大次是upstream中server的个数,假如server的个数超过20,也就是要最大尝试次数在20次以上,当尝试次数达到20次,仍然找不到一个合适的服务器,ip_hah策略不再尝试ip哈希值来选择server, 而在剩余的尝试中,它会转而使用RR的策略,使用轮循的方法,选择新的server。
3)除了以上部分不同外,IP_hash的其余部分和RR完全一样,由于它的其余部分功能的实现都是通过调用RR中的函数。
4)IP_hash是把同一个客户IP的请求分配给同一个后台服务器。
注意:
使用ip_hash指令无法保证后端服务器的负载均衡,可能有些后端服务器接收的请求多,有些后端服务器收到的请求少,而且设置后端服务权重等方法将不起作用。所以,如果后端的动态应用服务器能够做到SESSION共享,还是建议采用后端服务的SESSION共享方式代替Nginx的ip_hash方式。
如果后端服务器有时要从Nginx负载均衡中摘除一段时间,你必须其标记为“down”,而不是直接从配置文件中删除或注释掉该后端服务器的信息。例如:
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
这样,当原来为4台后端服务时,摘除backend3.example后,Nginx仍然会按4台服务器进行哈希。如果直接注释掉“server backend3.example.com”这行,Nginx就会按照3台服务器进行重新
哈希,原来被哈希到backend1.example.com的客户端IP有可能被哈希backend2.example.com服务器上,原有的SESSION就会失效。
附上:ip_hash实现源码
https://github.com/nginx/nginx/blob/master/src/http/modules/ngx_http_upstream_ip_hash_module.c
@ludengji
Copy link

你好。有个问题想请教一下。某个ip被hash分配到A机器后,假如机器A标记为down了,那这个ip是不是就会被分配到别的机器上了,比如机器B?如果机器A后面又好了的话,那这个ip是不是又从机器B分配回机器A了呢?相当于在A B之间来回处理了?

@Jackson0714
Copy link

Jackson0714 commented Sep 16, 2023

测试结果如下:
假设 IP 为 192.168.1.10
A -> down, 192.168.1.10 发送过来的请求会分配给 B
A-> 去掉 down,192.168.1.10 发送过来的请求会重新分配 A 来处理

你好。有个问题想请教一下。某个ip被hash分配到A机器后,假如机器A标记为down了,那这个ip是不是就会被分配到别的机器上了,比如机器B?如果机器A后面又好了的话,那这个ip是不是又从机器B分配回机器A了呢?相当于在A B之间来回处理了?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment