本文的实验环境:Windows 11 + nginx/1.26.2 for Windows(从 nginx.org 官网下载的 zip 包解压即用),两个"后端"是我用 Python 起的临时 HTTP 服务,只返回一个字符串标识自己是 A 还是 B。
下文所有命令行输出、错误日志、请求分布计数,都是我在这个环境里真跑出来的,不是凭记忆写的。为便于阅读,回显里的演示目录路径统一简写成 C:/nginx-test/,命令、参数与输出格式均与原样一致。
涉及具体产品的配置界面与默认值,均按截至 2026 年 10 月的官方文档为准。
windows服务器怎么实现负载均衡 —— 这个问题我接过不下十次,而且每次的场景都不一样。有的是三台 Windows 服务器跑同一个站点,前面要加个"分流量"的东西;有的是两台 IIS 跑 OA,领导要求别再单点挂;有的是四台跑 WebAPI,早晚高峰总有一台先扛不住;还有一种是已经有两台了,问能不能不加新机器就实现。
真正让人意外的地方在于:这几种场景要的东西根本不是一回事,但大家张口都是同一个词——“加个负载均衡”。更反直觉的是,Windows 上三条最常见的路里,有两条压根不在乎你的应用是死是活,只在乎那台机器的网卡还在不在喘气。这个差别,要等到半夜后端 500 了、流量还在往它身上打的时候才会被想起来。
我把 ARR、NLB 和 nginx for Windows 三条路都搭过一遍,下面按"先决定分什么、再挑工具、最后管健康"的顺序说。
一、先分清楚一件事:你要分的是"连接",还是"会话"
动工之前先问自己一个问题:同一台机器先后发了 10 个请求,你希望它们是被随机摊开的,还是必须落到同一台后端?
答案决定了技术路线,而且是硬分界,不是调参能绕过去的。
| 你的情况 | 该被分摊的单位 | 后果 |
|---|
| 后端是无状态的(静态页、WebAPI、纯计算) | 单个请求 / 单条 TCP 连接 | 随便分,怎么均匀怎么来 |
| 后端把会话状态存在本机(ASP.NET 的 InProc Session、本机内存缓存、本地临时文件) | 整个用户会话 | 必须让同一用户始终命中同一台,否则用户会反复掉登录 |
判断标准很土但很管用:把某台后端单独重启,用户需不需要重新登录?需要 → 你分的是会话;不需要 → 你分的是连接。
本文讲的是后者为主、前者为辅:三条路都支持"把同一个用户钉在某台后端上",但各自的代价完全不同,第五节到第九节逐个说。
还有一条更省事的岔路我得先提醒:**如果会话状态是你自己能改的,把它挪出本机(挪到 Redis 或者数据库)通常比为它配粘性会话划算得多。**粘性会话一旦配上,某台机器一挂,钉在它上面的用户全部重新登录,这是设计层面躲不掉的。
二、Windows 上的三条路,各自的边界在哪
回到开头那个问题——windows服务器怎么实现负载均衡。Windows 上能干这活的,主流就三个东西:IIS 的 ARR 扩展、系统自带的 NLB、以及 nginx for Windows。它们不是同一层的东西,放在一起比有点像拿"面包、面粉、小麦"比,但用户视角里它们确实是三条平行的路。
按这几个维度看它们的差别:
| 维度 | IIS ARR | NLB(系统自带) | nginx for Windows |
|---|
| 工作层级 | 七层,看得懂 HTTP 头和 URL | 四层,只看 IP 包和端口 | 七层(也能做四层 stream) |
| 能不能看懂应用死没死 | 能,配 URL 探活 | 不能,只看机器心跳 | 半能,只在请求失败时被动记录 |
| 安装方式 | IIS 管理器里装扩展 | Install-WindowsFeature NLB | 官网下载 zip 解压 |
| 是否需要额外机器 | 需要一台跑 ARR 的入口机 | 不需要,每台都是入口 | 需要一台跑 nginx 的入口机 |
| 典型适用 | 已有 IIS 农场,要按 URL 分流 | 同子网内的无状态服务 | 跨机、跨机房、混合后端 |
第一个要泼的冷水:ARR 和 nginx 都需要一台额外的入口机。你手上有两台服务器的话,装完还是两台,但每台都得装反向代理组件,或者单独再要一台小的当入口 —— 这点在申请预算的时候经常被忘记。NLB 是唯一不需要额外机器的选项,代价是它的限制最多(第四节)。
第二个提醒:这一节里"适用"两个字很重要。我见过把 ARR 装在入口机上、然后入口机单点挂掉的完整案例 —— 加了一层"均衡",却多了一个单点。
三、IIS ARR:Server Farm 上那几个图标,默认值是什么
ARR(Application Request Routing)是 IIS 的一个官方扩展模块,装完之后 IIS 管理器根节点下面会多出一个 Server Farms 节点。它干的事情是:用 URL Rewrite 规则把进来的请求判给某个"服务器场",再按负载均衡算法投给场里的某台机器。
按微软官方文档的说法,建一个场是这几步:IIS 管理器 → 右键 Server Farms → Create Server Farm,起个名字,把后端机器地址一台台填进去。向导跑完会自动生成一条 URL Rewrite 规则,把所有 HTTP 请求重写到这个场上。
建完之后,选中这个场,中间面板会出现一排图标。真正要改的其实只有三个:
Load Balance —— 选算法。文档里提到的英文名包括 Weighted round robin(加权轮询)和 Server variables hash 这类,选项因 ARR 版本不同而有增减,以你自己界面上那几项为准。默认不是加权轮询,这一点值得留意。
Health Test —— 配探活 URL。微软文档给的做法是在后端放一个静态文件(示例内容是 I am healthy.),然后在 URL 里填 http://<服务器名>/healthCheck.txt,Response match 填 healthy。文档里明确写的默认检测间隔是 30 秒。
这里有个细节我很喜欢:ARR 的探活是"主动"的,它不管有没有真实流量,到点就会发一个 GET 去问。而且它有两个来源——live traffic(真实流量失败也算数)和 explicit URL testing(显式探测),默认两者并行。
Server Affinity —— 配粘性。勾选 Client affinity 之后,ARR 会给客户端写一个 cookie(界面上显示的 cookie 名是 ARR Affinity),此后同一客户端的请求全部走同一台后端。这个开关默认是关的,开了之后官方文档也明说了:负载均衡算法只对客户端的第一个请求生效。
不想点鼠标的话,官方给出的等价命令是这样的:
- appcmd.exe set config -section:webFarms /[name='myServerFarm'].applicationRequestRouting.affinity.useCookie:"True" /commit:apphost
复制代码
还有一个很多人不知道、但知道之后会倒吸一口气的默认值:SSL offloading 默认开启。意思是客户端到 ARR 是 HTTPS,ARR 到后端变成明文 HTTP。在受信任的内网段里这没毛病(文档也是这么描述的,好处是省后端加解密开销),但如果你的 ARR 和后端隔着不可信网络,请去 Routing Rules 里把 Enable SSL offloading 取消掉。
完整的配置路径与逐步实验,微软官方 HTTP Load Balancing using Application Request Routing 文档里有,照着点一遍比看我复述快。
四、NLB:装得上,不等于用得了
NLB(Network Load Balancing)是 Windows Server 自带的网络功能,我用一句话概括它的性质:它是网卡驱动的组件,不是应用层的东西。
安装本身极其简单,按微软 NLB 文档的命令一行搞定,还不用重启:
- Install-WindowsFeature NLB -IncludeManagementTools
复制代码
但它动手之前有三条硬约束,一条不满足就得回头改网络:
第一,所有主机必须在同一个子网。 文档原话是所有主机必须 reside on the same subnet。跨 VLAN、跨机房的,直接不用考虑它。
第二,全集群的网卡模式必须统一。 要么全是单播,要么全是多播,微软明确写了不支持混合模式。而如果选单播,那张处理客户端流量的网卡必须支持修改自己的 MAC 地址 —— 虚拟化环境里这条经常是卡的(尤其是某些网卡直通或者老 hypervisor 的默认配置)。
第三,IP 必须静态,NLB 会把它所配置接口上的 DHCP 直接关掉。 文档里那句 “NLB does not support Dynamic Host Configuration Protocol (DHCP)” 说得很直白。另外这台网卡上只允许跑 TCP/IP,不要挂别的协议。
装完之后管理地方在这里:服务器管理器 → 工具 → 网络负载均衡管理器(命令行敲 nlbmgr 也一样)。新建集群的时候,要配一个被所有节点共享的群集 IP,客户端访问的是这个虚拟 IP,不是任何一台机器的真实 IP。
现在说它的致命短板。
按微软 IIS 一侧文档的说明:NLB 不监控你的应用的健康状态(原文是 NLB does not monitor the health of your application)。节点之间发的是心跳报文,某台机器的心跳断了,其余节点会重新分摊负载——它判断的是"这台机器还在不在",不是"这台机器上的服务还响不响应"。
后果是什么?IIS 进程池崩了、应用抛 500 了、应用起不来了,但机器活着、网卡在、心跳照发 —— NLB 会继续往这台机器上打流量。用户那边看到的就是"偶尔刷新一下又好了"。
所以我的判断是:NLB 适合无状态的、健壮的四层服务(比如 DNS、某些 TCP 长连接网关),不适合作为 IIS 站点的唯一均衡层。真要用它,至少要配应用层自监控或者挂在后面的 HTTP 探活。
五、nginx for Windows:upstream 四个参数我用 1.26.2 实测过
第三条路是 nginx,也是我认为做 windows服务器怎么实现负载均衡最省事的一条:官方直接提供 Windows 版本的 zip 包,解压就是一个 nginx.exe,配置是纯文本、能进 Git、改起来最快。这是三条路里唯一能摆脱 IIS 的方案,配置文件纯文本、能进 Git、改起来最快。
先把丑话说在前面 —— nginx 官网那篇 nginx for Windows 文档明确写着几件事,我在决定用它之前是必须先接受的:
- 它只用 select() 和 poll() 这两种连接处理方式,官方原话是性能和可扩展性都不要指望(high performance and scalability should not be expected);
- 基于这个原因和其他已知问题,Windows 版本被视为 beta 版本;
- 已知问题里有一条很狠:虽然可以起多个 worker,实际干活的只有一个;
- 不支持 UDP(连带 QUIC 也不支持);
- 它是标准控制台程序,不是 Windows 服务,用 nginx -s stop / nginx -s quit / nginx -s reload 管理。
这几条叠起来,我的立场是:验证、演示、小规模内部服务可以;大流量生产入口,别拿它赌。
配置本身就是一个 upstream 块加一个 proxy_pass,我实测用的最小配置长这样:
- upstream backend_pool {
- server 127.0.0.1:8081 weight=3 max_fails=1 fail_timeout=10s;
- server 127.0.0.1:8082 weight=1 max_fails=1 fail_timeout=10s;
- }
- server {
- listen 8088;
- location / {
- proxy_pass http://backend_pool;
- proxy_set_header Host $host;
- }
- }
复制代码
upstream 里 server 后面那一串参数,按 nginx upstream 模块官方文档 的定义:
| 参数 | 官方默认值 | 它管什么 |
|---|
| weight | 1 | 权重,越大分到的请求越多 |
| max_fails | 1 | 在 fail_timeout 期间失败几次就把这台标记为不可用;设为 0 表示关闭失败计数 |
| fail_timeout | 10 秒 | 兼管两件事:统计失败次数的时间窗,以及被判定不可用后的隔离时长 |
| down / backup | 无(标记位) | down 永久下线;backup 平时不分流量,主节点全挂才顶上 |
这里最容易被误解的是 fail_timeout,它同时是两个含义:窗口和刑期。文档原文就是这么写的——“指定次数的失败尝试要发生在这个时间段内”,并且"服务器被认为不可用的时长也是这个值"。文档还补了一句:什么算"一次失败",由 proxy_next_upstream 之类的指令定义,不是 nginx 单方面说了算。
还有一个我第一次部署就踩到的坑:Windows 版 nginx 用运行目录作为配置文件里相对路径的基准(官方文档原话 “uses the directory where it has been run as the prefix”)。我把 include mime.types; 跟 Windows 路径混着写,第一次 -t 直接报错:
- nginx: [emerg] CreateFile() "C:/nginx-test/mime.types" failed (2: The system cannot find the file specified) in C:/nginx-test/nginx.conf:10
- nginx: configuration file C:/nginx-test/nginx.conf test failed
复制代码
改成绝对路径之后才通过:
- nginx: the configuration file C:/nginx-test/nginx.conf syntax is ok
- nginx: configuration file C:/nginx-test/nginx.conf test is successful
复制代码
改完配置别急着 reload,先跑一次 nginx -t。 这条对所有 nginx 都成立,但在 Windows 上尤其重要 —— -s reload 之后如果配置有问题,旧进程已经优雅退了、新进程没起来,服务就是断的,而控制台窗口你不一定看得见。
六、实测:同一份配置,我打了三轮请求
配置是上面那份,权重 3 比 1。下面三组数字是我本机打出来的真实结果。
第一轮:两台后端都活着,连打 20 次。
- 15 FROM-APP-A
- 5 FROM-APP-B
复制代码
15 比 5,正好吻合 weight=3:1。这一步没什么技术含量,但它是后面所有判断的基准线 —— 先确认流量按你想要的比例分,再去谈故障转移,顺序反了容易把"权重没生效"误判成"摘除没生效"。
第二轮:把 A 的进程杀掉,立刻再打 12 次。
全部落到 B。表面看很完美,但真正的答案在 error.log 里:
- 2026/10/12 10:23:48 [error] 62936#62664: *57 connect() failed (10061: No connection could be made because the target machine actively refused it) while connecting to upstream, client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8081/", host: "127.0.0.1:8088"
复制代码
关键点在于:第 57 号请求确实被发给了已经死掉的 A,失败了,然后 nginx 才重试到 B,所以客户端根本没感知。换成真实业务,那一次失败就是用户肉眼可见的一次卡顿,或者一个 500 页面。
这就是开源版 nginx 的本质——被动健康检查。它不会主动去问后端活着没有,它只有在用户请求转发失败的时候才记一笔。
第三轮:把 A 重启起来,然后分两个时间点打。
- # 刚重启完立刻打 20 次
- 9 FROM-APP-A
- 11 FROM-APP-B
- # 等 11 秒之后再打 20 次
- 15 FROM-APP-A
- 5 FROM-APP-B
复制代码
这组数据是我觉得整篇文章里最值得看的。它把 fail_timeout=10s 的行为完整地摊开了:在这 10 秒刑期内,nginx 不会理 A;刑期一过,它先试探性地给 A 一点流量,确认能通,就把权重完整还回去。中间那个 9 比 11 的"过渡态",不是配置写错了,是恢复发生在我打请求的半路上。
顺带一个推论:如果你机器上所有后端都挂了,日志里出现的是另一种形态——no live upstreams while connecting to upstream,用户看到的是整页 502。这句话的意思不是某台后端有问题,而是这一组后端全军覆没,两者排查方向完全不同。
七、健康检查:谁在主动探,谁只能被动等
前面分三条路讲下来,探活这块其实只剩三句话:
- IIS ARR:主动探。到点就发一个 HTTP GET 过去问,文档给的间隔示例是 30 秒,还能比对返回的文本内容(文档示例里匹配的是 healthy 这个词)。
- NLB:只有节点心跳,机器活着就算健康,看不见应用。这条在第四节已经讲透,它是三层工具的天然边界。
- nginx 开源版:被动计数。fail_timeout 那个 10 秒窗口里失败 max_fails 次就隔离,刑期过了再试探,第六节那三组数字就是这个过程的完整录像。
所以别再问开源的 nginx 为什么没有云上那种好看的健康状态了 —— 开源版确实不带主动探测模块,这不是调参能补上的。
顺着这个差别往下说:云上的负载均衡产品里,健康检查是一等公民,不仅有主动探测,还有阈值换算表。下面这张表我把阿里云 CLB、腾讯云、华为云 ELB 三家官方文档里关于健康检查的关键参数摆在一起(都不需要额外付费判断,纯粹的技术参数对比):
| 参数 | 阿里云 CLB | 腾讯云 CLB | 华为云 ELB |
|---|
| 探测源地址 | 100.64.0.0/10 保留网段 | 默认 100.64.0.0/10 | ELB 后端子网内的 IP |
| HTTP 探测方法默认 | HEAD | HEAD | HTTP GET |
| 健康检查间隔(文档推荐/默认) | 2 秒 | 默认 5 秒 | 可配,参与时间窗公式 |
| 响应超时(文档推荐/默认) | 5 秒 | 默认 2 秒 | 参与时间窗公式 |
| 健康/不健康阈值 | 3 次 / 3 次 | 3 次 / 3 次 | 参与时间窗公式 |
| 摘除一台坏节点大概要多久 | 约(5×3)+2×(3−1)=19s(按文档推荐值算) | 约(2×3)+5×(3−1)=26s(按默认值算) | 公式统一:超时×阈值 + 间隔×(阈值−1) |
三家各自的文档入口在这,截图参数比我这表格细:阿里云 CLB 配置和管理健康检查、腾讯云 配置健康检查、华为云 ELB 健康检查介绍。
这里有三条经验,都是这三份文档里白纸黑字写着、却很少被重视的:
第一,探测源地址那个网段必须放行。 阿里云和腾讯云都明说健康检查流量来自 100.64.0.0/10(华为云则来自 ELB 后端子网)。云主机自带的安全组通常不需要额外配置,但只要你机器上加了防火墙软件或者 iptables 规则,就必须放行这个网段,否则健康检查一律失败、后端全部显示异常——这是我最常见到的"明明服务是好的,云上偏说它挂了"的原因。
第二,探测方式默认是 HEAD,不是 GET。 阿里云和腾讯云的 HTTP 健康检查默认都发 HEAD。如果你的后端或中间件把 HEAD 请求拦了(有些老旧框架、某些 WAF 规则会),健康检查就会一直失败。改 GET,或者先 curl -I 自己试一下。
第三,健康状态切换有延迟,别一上来就觉得它坏了。 三家都是"连续 N 次成功/失败才切换"。华为云文档直接给了时间窗公式:等于 超时 × 阈值 + 间隔 × (阈值-1)。按腾讯云的默认值(超时 2 秒、间隔 5 秒、阈值 3)算,判定一台机器"不健康"需要 26 秒左右;阿里云按推荐值算也要 19 秒上下。重启之后等状态切换生效,才等十秒就开始怀疑人生 —— 这事我自己干过。
八、什么时候不该在 Windows 上自己搭负载均衡
四条边界,每条我都见过有人踩:
第一,流量已经超出单台 nginx for Windows 的处理能力。 官方文档明确写了它只用 select()/poll()、且是 beta 版本,还有多个 worker 实际只有一个干活的已知问题。这时候应该把它换成 Linux 上的 nginx/HAProxy,或者直接用云厂商的负载均衡服务,而不是给它加 CPU。
第二,会话状态非要留在本机。 你可以用粘性会话顶住,代价是某台机器挂掉时,钉在上面的用户集体掉线,而且多了故障节点就不"均衡"了。真正的解是把 Session 挪到 Redis 或数据库里。粘性会话是止痛药,不是治疗方案。
第三,NLB 用来做 IIS 站点的唯一均衡层。 它不检查应用健康,网站 500 了它照样转发。这条在第四节已经说过,但因为它实在太常被忽略,值得再说一遍。
第四,没有第二台机器,或者没有监控。 单台机器上装"负载均衡"是伪需求;而没有监控和第二台入口机,你只是把一个单点变成了两个单点。这一条比技术选型重要得多。
九、顺序总结
回头把这一整套串起来:
确定要分的是连接还是会话 → 会话要能改的话先改造(挪出本机) → 挑工具(已有 IIS 用 ARR / 同子网无状态用 NLB / 跨机混合用 nginx) → 入口机记得留一台(ARR 和 nginx 都需要) → 配健康检查(ARR 主动、NLB 不管、nginx 被动,差别看前面那张表) → 放行探测源网段、核对 HEAD 方法 → 把切换延迟算清楚(约 20-30 秒,别误判) → -t 校验后再上线。
我最想钉在这里的一句话:负载均衡真正难的地方从来不是"把流量分开",而是判断哪台后端已经不该再要流量了。分流量这件事半小时就能配完,判断后端死没死这件事你可能要调上好几个月。
具体到windows服务器怎么实现负载均衡这件事,我的建议是按"如果能接受买/配一台入口机 → ARR 或 nginx;如果一分钱预算都没有且服务无状态 → NLB;如果流量有份量 → 直接上云产品"这条线走。
各家云厂商的健康检查参数、控制台入口和默认值会随产品迭代调整,实际请以官网当期公示为准。
FAQ
windows服务器怎么实现负载均衡,是不是必须得买第三台服务器?
不一定。NLB 方案不需要:每台机器自己就是入口,客户端访问共享的群集 IP,省掉一台机器。但 ARR 和 nginx 需要一台额外的机器(或至少一台独立进程)承担流量入口。代价上 NLB 少了机器,多了同子网、网卡 MAC、静态 IP 这些网络层限制,且不检查应用健康。
有两台 windows 服务器,能不能只在一台上装 nginx 做入口?
可以,那台nginx跑起来确实能工作,但它成了新的单点。真要消单点,Windows 上的常见做法是在两台入口机之间再叠一层 NLB,或者直接把入口交给云厂商的负载均衡服务 —— 后者连入口机自身的高可用都不用你自己管。
服务器windows server版本怎么选,才能用上这些功能?
ARR 是 IIS 的扩展,微软文档明确要求 IIS 7.0 及以上,WindowsServer服务器管理器工具里就能装;NLB 是系统网络功能,服务器系统windows server 下载安装完后用 Install-WindowsFeature 添加;nginx 对系统版本几乎没要求,只要有 Win32 运行环境。选版本时真正要留意的是 IIS 版本与 ARR 版本的匹配,而不是 Windows 的版本号。
健康检查配好了,为什么后端一直显示异常?
按优先级排:先看有没有拦住探测源网段(阿里云、腾讯云是 100.64.0.0/10,华为云是 ELB 后端子网地址);再确认后端支不支持 HEAD 方法;最后确认健康检查路径指向的是不是静态文件。这三条能覆盖我遇到过的绝大多数情况。
负载均衡配完,用户的登录状态老掉怎么办?
说明没配粘性会话,或者配了但后端依旧不满足条件。ARR 里在 Server Affinity 里开启 Client affinity(cookie 名 ARR Affinity);nginx 开源版只能用 ip_hash 做近似的客户端绑定(按源 IP 哈希,不是按 cookie)。但根因解法还是把会话状态从本机内存里挪出去。