在传统的负载均衡哈希策略中,当上游服务器数量发生变化时,会导致大量请求被路由到不同的服务器,从而引发缓存大规模失效或会话中断的问题。一致性哈希算法正是为解决这一问题而设计的,它通过构建一个哈希环来映射服务器和请求,在服务器变动时,仅影响环上相邻部分的数据,最大程度保持了缓存的一致性。
哈希算法存在的问题
假设一个简单的场景:我们有5个请求键和5台服务器,采用取模(模5)的哈希算法进行路由。当移除一台服务器,只剩下4台时,算法改为模4。结果是所有5个请求键的路由目标都发生了改变。
哈希算法在服务器数量变化时的问题
这意味着,如果后端服务未使用共享缓存(如 Redis),而是依赖本地缓存或会话,那么这次服务器缩容将导致几乎所有的缓存失效或用户会话丢失,对系统造成巨大冲击。
一致性哈希算法原理
一致性哈希算法的核心思想是将服务器节点和数据键都映射到一个固定的环形哈希空间上(通常是一个32位的哈希环,值域为 0 到 2^32-1)。
- 节点映射:将每台服务器通过哈希函数计算,分布到哈希环上。
- 数据路由:当一个请求键需要被路由时,同样计算其哈希值,并落到环上的某个点。然后从此点出发,沿顺时针方向找到的第一个服务器节点,即为该请求的目标节点。
- 应对变化:当新增或删除一个节点时,只会影响该节点在环上逆时针方向到前一个节点之间的区间数据,其他大部分数据的路由保持不变。
例如,下图展示了新增一个节点(Node 5)的情况,只有原属于 Node 4 的部分数据(Key 2, 3, 4)会重新映射到 Node 5,而其余数据(Key 0, 1)的路由不受影响,从而极大降低了缓存失效的比例。
一致性哈希算法环形结构示例
算法的优势与劣势
优势:
- 平滑扩容/缩容:服务器节点增减时,只有少量数据需要迁移,避免了“雪崩式”的缓存失效。
- 提高系统稳定性:特别适用于依赖本地缓存的高并发服务,是构建稳定后端服务架构设计的关键策略之一。
劣势:
- 负载可能不均:基础的一致性哈希可能导致服务器在环上分布不均,从而引发负载倾斜。通常通过引入“虚拟节点”来解决。
- 无法完全避免数据迁移:节点变动时,其邻近区间的数据仍会受到影响。
Nginx 配置一致性哈希实践
Nginx 的 upstream 模块中的 hash 指令支持通过 consistent 参数启用一致性哈希算法。
操作步骤:
-
准备后端服务器:创建两个测试用后端服务,监听不同端口。
# 在 10.20.172.214 主机上配置
tee /usr/local/nginx/conf.d/server.conf <<'EOF'
server {
listen 8011;
server_name localhost _;
default_type text/plain;
return 200 'From 8011 server response!\n';
}
server {
listen 8012;
server_name localhost _;
default_type text/plain;
return 200 'From 8012 server response!\n';
}
EOF
# 在 10.20.172.213 主机上配置
tee /usr/local/nginx/conf.d/server.conf <<'EOF'
server {
listen 8010;
server_name localhost _;
default_type text/plain;
return 200 'From 10.20.172.213:8010 server response!\n';
}
EOF
-
配置Nginx反向代理与一致性哈希:编辑代理配置文件,在 hash 指令后添加 consistent 关键字。
tee /usr/local/nginx/conf.d/proxy_server_hash.conf <<'EOF'
upstream backend {
# 启用一致性哈希算法,键值为 user_ 拼接URL中的user参数
hash user_$arg_user consistent;
server 127.0.0.1:8011 weight=2;
server 127.0.0.1:8012;
server 10.20.172.213:8010 max_fails=2 fail_timeout=10s;
keepalive 10;
}
server {
listen 80;
server_name test.weiyigeek.top;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
EOF
注意:hash 负载均衡方法不受服务器weight权重影响。
-
重启Nginx并测试
nginx -s reload
使用脚本模拟连续请求,观察路由情况:
for i in $(seq 1 30); do
echo -n "user_WeiyiGeek${i}:";
curl -H 'X-Forwarded-For: 100.10.2.215' http://test.weiyigeek.top?user=WeiyiGeek${i};
sleep 1;
done
-
模拟服务器宕机:在测试过程中,手动停止 10.20.172.213:8010 这台服务器。
# 在 213 主机执行
nginx -s stop
观察请求日志,你会发现只有一部分请求(原本路由到宕机服务器且哈希环上顺时针下一个节点是其他服务器)会失败并切换到其他可用后端,而大部分能命中其他后端服务器的请求将继续正常响应,这证明了在Linux运维环境下,一致性哈希能有效隔离故障影响。
测试结果示意:
在移除一台服务器后,仅部分请求的路由目标发生改变,其余请求仍能正确访问到原来的后端,有效保护了缓存命中率。
一致性哈希在节点失效时的请求路由变化
总结
一致性哈希算法是Nginx实现高性能、高可用负载均衡的重要策略之一。它通过巧妙的环形映射,显著降低了服务器集群规模变化时对系统整体的冲击,是解决缓存会话保持问题的有效方案。在实际生产环境中,尤其是涉及到数据库与中间件缓存层设计时,合理运用一致性哈希可以极大地提升系统的弹性和用户体验。
|