共计 2407 个字符,预计需要花费 7 分钟才能阅读完成。
网络结构描述:
1 个 Nginx(前端)+ 2 个 tomcat(后端)
环境:
公司内网(网段:192.168.1.0/24),服务器也是分配的内网 ip:192.168.1.4(暂定);后端两个 tomcat:192.168.1.31/189
网站有 session,所有 Nginx 启用 ip_hash.
现象:
测试组用 loadrunner 模拟 N 多内网 ip 进行压测系统。发现,这些 ip 统一都转发到一个后端。
后经排查发现问题所在(结论最下面)。
1、请看官方解释:
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 关键字,来保证这个客户端请求总是被转发到一台服务器上)
2、请看 Nginx 的 ip hash 算法(该段代码为转发。原文链接:http://www.linuxidc.com/Linux/2014-02/96869.htm):
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(;;) {
for(i = 0; i < 3; i++) {
hash = (hash * 113+ iphp->addr[i]) % 6271;
1、for 循环 i 取 012 三个值,而 ip 的点分十进制表示方法将 ip 分成四段(如:192.168.1.1),但是这里循环时只将 ip 的前三个端作为参数加入 hash 函数。这样做的目的是保证 ip 地址前三位相同的用户经过 hash 计算将分配到相同的后端 server。
作者的这个考虑是极为可取的,因此 ip 地址前三位相同通常意味着来着同一个局域网或者相邻区域,使用相同的后端服务让 nginx 在一定程度上更具有一致性。
通过上述解释,已经基本判断出问题所在了。。
主要原因就是,公司局域网用的 192.168.1.0/24 C 类地址,这样 Nginx 在 ip_hash(for 循环后三个参数统一计入 hash 值)的时候,就将该类所有 ip 都转发到一个后端了。
另,晕了我半天了。。。不论 A 类 B 类 C 类等网络地址,Nginx 的 ip_hash 算法都将一个 ip 地址的前三段作为 hash 的关键字。。(规定)
Nginx 的详细介绍 :请点这里
Nginx 的下载地址 :请点这里
相关阅读 :
CentOS 6.2 实战部署 Nginx+MySQL+PHP http://www.linuxidc.com/Linux/2013-09/90020.htm
使用 Nginx 搭建 WEB 服务器 http://www.linuxidc.com/Linux/2013-09/89768.htm
搭建基于 Linux6.3+Nginx1.2+PHP5+MySQL5.5 的 Web 服务器全过程 http://www.linuxidc.com/Linux/2013-09/89692.htm
CentOS 6.3 下 Nginx 性能调优 http://www.linuxidc.com/Linux/2013-09/89656.htm
CentOS 6.3 下配置 Nginx 加载 ngx_pagespeed 模块 http://www.linuxidc.com/Linux/2013-09/89657.htm
CentOS 6.4 安装配置 Nginx+Pcre+php-fpm http://www.linuxidc.com/Linux/2013-08/88984.htm