对用户IP做一次哈希计算,得到一个固定数值,再对这个数值做取模运算,映射到后端节点;同一个IP永远算出同一个结果,所以始终被分到同一个节点。
这套机制不需要在服务器端保存任何会话数据,也不需要额外的缓存组件,一切由算法本身保证,本文从原理、对比、配置到局限,把源地址哈希调度的会话保持机制讲透,并给出可直接落地的操作路径。
源地址哈希调度的工作原理
源地址哈希调度属于静态调度算法,它在负载均衡器收到请求的瞬间完成一次计算,处理过程分三步:
哈希计算:把IP变成一串数字
负载均衡器取出请求的源IP地址,比如0.113.5,通过哈希函数(如CRC32)计算出一个整数哈希值,哈希函数的特性是:相同输入永远产生相同输出,这正是”固定”二字的来源。
取模映射:把数字变成节点编号
用哈希值对当前可用节点数量做取模运算,得到的余数就是目标节点的索引,例如哈希值是10000,有3个节点,10000 % 3 = 1,该请求就被分配到节点1。
节点定位与转发
负载均衡器根据索引找到对应节点的IP和端口,把请求转发过去,整个过程耗时极短,通常在微秒级别完成,对用户完全无感知。
这套流程的关键在于:哈希函数和节点数量共同决定映射结果,只要这两者不变化,用户和节点之间的绑定关系就不会变。
源地址哈希和ip hash区别:先看是哪一层
“源地址哈希”和”ip hash”经常被混用,实际使用中要区分语境。
应用层负载均衡中的ip hash
在Nginx、HAProxy这类应用层负载均衡中,ip hash指的就是以客户端IP为哈希键的调度策略,Nginx的ip_hash指令和HAProxy的balance source都是这类实现,其行为等同于源地址哈希调度。
内核态LVS中的源地址哈希
LVS(Linux Virtual Server)的sh算法(Source Hashing)专门针对源IP做哈希调度,与目标地址哈希(dh)相对,LVS的sh算法为了保证调度一致性,内部维护了一个哈希表而非简单的取模运算,但对外表现相同:同一源IP固定落在同一节点。
网络层哈希与HTTP层哈希的选择
| 维度 | 源地址哈希 / IP哈希 | 一致性哈希 | Cookie会话保持 |
|---|---|---|---|
| 会话保持粒度 | 整个IP | 整个IP | 精确到浏览器会话 |
| 依赖数据 | 纯IP,无额外开销 | 虚拟机IP或自设键值 | 需要Cookie读写 |
| 节点变更影响 | 大量重映射 | 仅影响相邻节点 | 无影响 |
| 适用范围 | 内网、TCP长连接 | 分布式缓存 | 公网HTTP场景 |
行业共识认为,公网环境下多用户共享出口IP(如公司NAT、校园网出口)会导致源地址哈希调度失衡,这时优先考虑Cookie会话保持。
源地址哈希配置方法:三个主流场景的操作路径
Nginx配置ip_hash实现会话保持
在upstream块中直接添加ip_hash指令即可:
upstream backend_cluster {
ip_hash;
server 192.168.1.10:8080 weight=1;
server 192.168.1.11:8080 weight=1;
server 192.168.1.12:8080 down; # 备份节点不参与哈希
}
server {
listen 80;
location / {
proxy_pass http://backend_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
配置完成后执行nginx -t校验语法,再执行nginx -s reload平滑重载,需要注意的是,ip_hash模式下weight参数不生效,Nginx会根据节点列表顺序直接进行哈希取模。
HAProxy配置source算法
backend web_servers
balance source
hash-type consistent
server web1 192.168.1.10:8080 check
server web2 192.168.1.11:8080 check
server web3 192.168.1.12:8080 check
hash-type consistent启用一致性哈希,避免节点增减时大量会话失效。
LVS配置sh调度算法
ipvsadm -A -t 192.168.100.100:80 -s sh ipvsadm -a -t 192.168.100.100:80 -r 192.168.1.10:8080 -g ipvsadm -a -t 192.168.100.100:80 -r 192.168.1.11:8080 -g
-s sh指定源地址哈希调度,-g使用DR模式(直接路由),LVS的sh算法在节点数变化时会部分重建哈希表,这是它的固有特性。
为什么节点故障会导致会话重映射
源地址哈希调度依赖节点总数参与取模运算,当某个节点宕机,负载均衡器把节点数从N变为N-1,哈希取模的除数变了,几乎所有用户的映射结果都会改变,这不是算法缺陷,而是取模哈希的数学特性决定的。
| 节点状态 | 取模除数 | 映射影响 | 会话保持 |
|---|---|---|---|
| 全部正常 | N | 稳定 | 完全保持 |
| 新增节点 | N+1 | 大部分用户重映射 | 基本失效 |
| 移除节点 | N-1 | 大部分用户重映射 | 基本失效 |
业内专家指出,在节点数量频繁变动的微服务架构中,不建议单独使用源地址哈希,应结合一致性哈希或分布式会话方案。
实际案例:定时任务服务如何使用源地址哈希
某企业内部定时任务系统需要将任务状态保留在执行节点,由于内网IP固定且节点数量稳定,直接启用源地址哈希后,同一台办公机的所有请求稳定落在同一任务节点,省去了Redis会话共享的改造成本,这个方案在节点数为3、连续运行8个月的情况下,未出现过一次会话漂移。
源地址哈希的适用场景与局限性分析
适用场景
- 内网业务系统:内网IP固定,网络结构简单,哈希分布均匀
- TCP长连接服务:FTP、数据库连接池等需要连接状态的服务
- 无状态应用的唯一会话需求:临时存储用户数据的内存态应用
- 网关后的L4转发:后端节点只有一台或极少量时的简单场景
核心局限
- 公网NAT场景下多个用户共享出口IP,会集中到同一节点造成负载不均
- 节点数量变化导致大量会话重映射
- 权重配置基本无效,无法实现按需分配
- 调度前无法感知后端节点的实时负载情况
会话保持技术如何选择搭配
很多架构师把源地址哈希与其他会话保持手段配合使用,以弥补其缺陷:
组合方案一:Redis集中式会话存储
源地址哈希负责初步分配,后端节点把Session写入共享Redis,即使节点故障导致请求落到其他节点,新节点也能从Redis获取会话数据,业务不中断,这是目前主流的Web架构方案。
组合方案二:Cookie会话保持
Nginx的sticky cookie指令下发一个加密Cookie标识节点ID,用户在浏览器端保存标识,请求时自动携带,负载均衡器依据Cookie直接定向,该方案不受NAT出口IP问题影响,适合电商平台和公众用户系统。
组合方案三:一致性哈希
对节点采用一致性哈希环结构,节点增减时仅有少量请求发生重映射,保留了大部分会话关系,适用于分布式缓存(如Redis集群)和分布式存储系统的数据分片。
源地址哈希调度常见问题解答
源地址哈希调度适合公网系统吗?
适合IP固定且数量可控的场景,一旦涉及大量移动用户、NAT出口共享或动态IP,会引发哈希分布不均和会话集中,此时最佳方案是Cookie会话保持,比如Nginx的sticky route,公网高并发系统建议源地址哈希只作为兜底策略,主调度方式配合健康检查和Session共享机制。
节点扩容后源地址哈希映射全乱了怎么办?
源地址哈希取模方式节点数变化必然导致重映射,解决路径有三条:第一,在负载均衡层使用一致性哈希替代取模;第二,应用层把Session迁移到Redis等外部存储,让调度算法变更不再影响数据;第三,在低峰期操作扩容,配合灰度切换少量节点逐步验证,国内常见的云负载均衡服务在控制台切换调度算法也比较方便,但底层逻辑不变。
ip_hash能否保证同一IP的请求永远分配到同一节点?
不能”永远”,仅在节点列表不变且有节点均健康时成立,节点宕机、标记为down、扩容缩容都会改变映射结果,Nginx的ip_hash仅对IPv4的前三段做哈希,特殊场景下的IPv6地址处理方式也不同。
源地址哈希和会话保持是同一个概念吗?
不一样,源地址哈希是调度算法,是决定”请求发给谁”的策略,会话保持是业务需求,指用户状态在多次请求间不丢失,源地址哈希是实现会话保持的一种手段,但会话保持还可以通过Cookie、Redis会话复制、数据库会话表等多种技术实现,源地址哈希只是解决会话保持问题的其中一条技术路径。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/635541.html


