nginx

【nginx】nginx使用ip_hash调度方式,负载均衡问题

2022-08-31  本文已影响0人  Bogon

一、问题背景

现象:nginx和客户端处于同一个局域网,使用ip_hash负载均衡策略,不同客户端的请求全部都分发到同一个后台服务器。

原因:

官方解释:
This directive causes requests to be distributed between upstreams based on the IP-address of the client. 

The key for the hash is the class-C network address or the entire IPv6-address of the client. IPv6 is supported for ip_hash since 1.3.2 or 1.2.2. 

This method guarantees that the client request will always be transferred to the same server. But if this server is considered inoperative, then the request of this client will be transferred to another server. This gives a high probability clients will always connect to the same server. 

简译:将客户端ip转化成C类网络地址,然后将该网络地址当作hash关键字,来保证这个客户端请求总是被转发到一台服务器上。

看Nginx的ip hash算法,在ngx_http_upstream_ip_hash_module.c的源文件:

for ( ;; ) {
 
         for (i = 0; i < 3; i++) {  
            hash = (hash * 113 + iphp->addr[i]) % 6271; //iphp->addr[i]为ip的点分十进制法的第i段
        }
 
        p = hash % iphp->rrp.peers->number;
 
        n = p / (8 * sizeof(uintptr_t));
        m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
 
        if (!(iphp->rrp.tried[n] & m)) {
 
            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                            "get ip hash peer, hash: %ui %04XA", p, m);
 
            peer = &iphp->rrp.peers->peer[p];
 
            /* ngx_lock_mutex(iphp->rrp.peers->mutex); */
 
            if (!peer->down) {
 
                if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
                    break;
                }
 
                if (now - peer->accessed > peer->fail_timeout) {
                    peer->fails = 0;
                    break;
                }
            }
 
            iphp->rrp.tried[n] |= m;
 
            /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
 
            pc->tries--;
        }
 
        if (++iphp->tries >= 20) {
            return iphp->get_rr_peer(pc, &iphp->rrp);
        }
    }

主要代码 :

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

for循环i取 0,1,2三个值,而ip的点分十进制表示方法将ip分成四段(如:192.168.1.1),但是这里循环时只是将ip的前三个段作为参数加入hash函数。这样做的目的是保证ip地址前三位相同的用户经过hash计算将分配到相同的后端server。

作者的这个考虑是极为可取的,因此ip地址前三位相同通常意味着来着同一个局域网或者相邻区域,使用相同的后端服务让nginx在一定程度上更具有一致性。

通过上述解释,已经基本判断出问题原因了:公司使用的局域网前三段ip相同,这样Nginx在ip_hash(for循环后三个参数统一计入hash值)的时候,就将该类所有ip都转发到一个后端了。

另,不论A类B类C类等网络地址,Nginx的ip_hash算法都将一个ip地址的前三段作为hash的关键字。

二、解决方案

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

  1. 找到nginx源码压缩包,进行解压;
  2. 进入nginx目录下的src/http/modules/ngx_http_upstream_ip_hash_module.c文件;
  3. 如图所示,找到180多行,根据循环里的i值引用处,将3次改成4次(总共三处)。

重新编译后,果然生效了,就可以根据ip的不同进行负载分担了。

image.png image.png image.png

三、参考

Configuring Nginx as a load balancer/Using IP hash load-balancing
https://docs.appeon.com/ps2022/Using_IP_hash_load-balancing.html

nginx使用ip_hash分配方式时负载均衡问题
https://bbs.csdn.net/topics/391807343

如何通过Hash算法实现负载分担?
https://support.huawei.com/enterprise/zh/doc/EDOC1100087021

nginx 配置ip_hash不会自动剔除宕机的服务器
https://blog.csdn.net/liaomingwu/article/details/121328604

nginx 负载均衡之ip_hash
https://www.jianshu.com/p/be5c7efd37d7

nginx使用ip_hash后为什么请求访问的都在同一个服务器,而另外几个服务几乎是闲的?
https://blog.csdn.net/yswknight/article/details/107180893

nginx在局域网中使用ip_hash负载均衡策略,访问全部分发到同一个后端服务器
https://blog.csdn.net/sd4493091/article/details/54894479

上一篇下一篇

猜你喜欢

热点阅读