ip_hash机制
轮询round-robin负载均衡算法无法保证某一类请求只能由一台服务器去处理,ip_hash机制保证了某一类请求只会由某一台服务去处理。该算法基于用户的IP地址进行hash算法。
Nginx中的ip_hash技术能够将某个ip 的请求定向到同一台后端web机器中,这样一来这个ip 下的客户端和某个后端 web机器就能建立起稳固的session。ip_hash机制能够让某一客户机在相当长的一段时间内只访问固定的后端的某台真实的web服务器,这样会话就会得以保持,在网站页面进行login的时候就不会在后面的web服务器之间跳来跳去了,也不会出现登录一次的网站又提醒重新登录的情况。
ip_hash(通过客户端请求ip进行hash,再通过hash值选择后端server):
当你服务端的一个特定url路径会被同一个用户连续访问时,如果负载均衡策略还是轮询的话,那该用户的多次访问会被打到各台服务器上,这显然并不高效(会建立多次http链接等问题)。甚至考虑一种极端情况,用户需要分片上传文件到服务器下,然后再由服务器将分片合并,这时如果用户的请求到达了不同的服务器,那么分片将存储于不同的服务器目录中,导致无法将分片合并。所以,此类场景可以考虑采用nginx提供的ip_hash策略。既能满足每个用户请求到同一台服务器,又能满足不同用户之间负载均衡。
ip_hash实例
实现很简单只需要加入ip_hash
upstream backend{
ip_hash;
#这里虽然配置了权重weight但是并不会生效,因为ip_hash指令会必须根据用户的IP地址进行确认。用户IP地址只能落在同一台server
server 192.168.179.100 weight=2 max_conns=2 max_fails=2 fail_timeout=5;
server 192.168.179.101 weight=1;
keepalive 256;
}
#为了使得上游服务获取到用户端真实IP做IP Hash使用了real_ip模块,real_ip模块设置了信任地址,即本机地址,可以从X-Forwarded-For里面最后一个IP地址作为remot_addr的值,以该值作为IP地址去做Hash算法
#使用proxy_pass反向代理到backend,然后使用负载均衡Hash算法
server {
listen 80;
server_name www.test.com;
set_real_ip_from 192.168.179.99;
real_ip_recursive on;
real_ip_header X-Forwarded-For;
error_log myerror.log info;
access_log logs/upstream_access.log main;
location /{
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
[root@localhost html]# curl 192.168.179.101;sleep 1;done --101是没有宕机的
proxy this is 192.168.179.101 page
[root@localhost ~]# while true;do curl 192.168.179.99;sleep 1;done --可以看到请求都固定在192.168.179.100上面,没有做轮询到192.168.179.101上面
proxy this is 192.168.179.100 page
proxy this is 192.168.179.100 page
proxy this is 192.168.179.100 page
proxy this is 192.168.179.100 page
ip_hash存在缺陷,当前端服务器再多一层时,将获取不到用户的正确IP,获取的将是前一个前端服务器的IP,因此 nginx1.7.2版本推出了 url_hash
url_hash 配置:
upstream xxx {
hash $request_uri;
server 127.0.0.2;
server 127.0.0.3;
}
使用hash算法可以确保某一类请求只会路由到某一台上游服务当中,无论这台上游服务是否正常在线。当一台上游服务有一台机器损坏了或者下线了,我们不能之间从upstream当中将这台server从配置里面移除,因为移除以后会导致它的hash算法发生变化,就会同时影响原本路由到其他上游server的请求也发生变化,这样会造成严重的后果。然而一致性hash算法能够缓解这个问题。