nginx使用ip_hash后为什么请求访问的都在同一个服务器,而另外几个服务几乎是闲的

  • ip_hash作用
  • 问题描述
  • 解决方案


ip_hash作用

通过客户端请求ip进行hash,再通过hash值选择后端server。
当你服务端的一个特定url路径会被同一个用户连续访问时,如果负载均衡策略还是轮询的话,那该用户的多次访问会被打到各台服务器上,这显然并不高效(会建立多次http链接等问题)。甚至考虑一种极端情况,用户需要分片上传文件到服务器下,然后再由服务器将分片合并,这时如果用户的请求到达了不同的服务器,那么分片将存储于不同的服务器目录中,导致无法将分片合并。所以,此类场景可以考虑采用nginx提供的ip_hash策略。既能满足每个用户请求到同一台服务器,又能满足不同用户之间负载均衡。

问题描述

如图所示:
上面名为micro-service的upstream,包含的服务没有用到session,所以没有加ip_hash,负载是起作用的,请求能分发到不同的服务器中。
下面名为pub-service的upstream,包含的项目有用到session,所以需要增加ip_hash,来解决每次请求session不一致的问题。但是增加ip_hash后,所有请求都分发到了一台服务器上了,也就是说,另外两台服务器是闲置的,没有起到负载均衡的作用。

nginx ip_hash 修改源码 nginx ip_hash原理_nginx ip_hash 修改源码


打开access.log日志,可以看到请求来源都是这四台ip地址,相同点是请求IP地址的前三段都是相同的。

后来上网查了一下ip_hash的原理,原来ip_hash是使用ip地址的前三段进行hash运算,根据结果的不同,重定向到不同的服务器上。我们的电脑都在一个c网,所以算出的hashcode都是一样的,所以没有负载分担的效果。

我们系统的访问地址是被另外四台Apache服务器代理的,所以请求到我们的nginx地址,拿到的请求ip都是那四台代理服务器的IP,如图所示:

nginx ip_hash 修改源码 nginx ip_hash原理_linux_02

解决方案

修改nginx的源代码后,重新编译安装,就能实现根据ip地址来区分重定向的目的。

  1. 找到nginx压缩包,进行解压
  2. 进入nginx目录下的src/http/modules/ngx_http_upstream_ip_hash_module.c文件;
  3. 如图所示,找到180多行,根据循环里的i值引用处,将3次改成4次(总共三处)。
  4. 重新编译后,果然生效了,就可以根据ip的不同进行负载分担了。

nginx ip_hash 修改源码 nginx ip_hash原理_服务器_03


nginx ip_hash 修改源码 nginx ip_hash原理_nginx ip_hash 修改源码_04


nginx ip_hash 修改源码 nginx ip_hash原理_nginx_05

参考博客:http://blog.sina.com.cn/s/blog_438d53970102x2j6.html