香港服务器IIS并发如何调优?从连接数到应用池回收
IIS并发调优的起点,不是把 maxConnections、应用池队列或线程数统一调大,而是先确认请求究竟堵在连接接入、HTTP.sys 队列、应用池工作进程、线程池,还是数据库和磁盘等共享资源上。香港服务器上的连接数还会受到用户所在地、网络往返时延、Keep-Alive、HTTP/2 多路复用和长连接业务的影响,因此“连接很多”不等于“IIS处理能力不足”。

较稳妥的做法是先建立延迟、吞吐、队列、CPU、内存、I/O和错误率的基线,再针对瓶颈调整连接上限、队列长度、应用池进程模型和回收策略。组策略与补丁管理则负责保证电源策略、安全扫描、重启和系统更新不会破坏这条基线;它们通常不是直接提升 RPS 的开关,却可能改变性能结果和稳定性。
围绕IIS网站、业务后台、数据库和接口服务的并发承载,A5数据提供香港物理服务器资源,覆盖入门建站、Xeon Gold与AMD EPYC等配置,并配备SSD或NVMe存储及不同内存规格,为多进程运行、数据库访问和日志读写提供硬件基础。香港产品还提供CN2与国际带宽选项,结合美国、日本、新加坡等地区的服务器资源,可匹配不同访问区域和业务部署需求。
先把“并发”拆成几个可观测指标
TCP连接不等于正在执行的请求
IIS场景中至少要区分以下几类数量:
| 指标 | 含义 | 适合判断的问题 |
|---|---|---|
| TCP当前连接数 | 已建立或处于特定状态的网络连接数量 | 长连接、Keep-Alive、WebSocket、客户端连接释放是否正常 |
| 请求并发数 | 此刻正在执行或等待执行的HTTP请求数量 | 应用池、线程池和后端资源是否被占满 |
| RPS | 每秒完成的请求数量 | 实际吞吐能力 |
| 应用池队列长度 | 已到达应用池但尚未被工作线程处理的请求数量 | 工作进程或下游资源是否成为瓶颈 |
| p95/p99延迟 | 95%或99%请求的响应时间上界 | 尾部延迟和拥塞程度 |
| 5xx错误率 | IIS或应用返回的服务端错误比例 | 是否已经超过可接受容量 |
启用 Keep-Alive 后,一个TCP连接可以承载多个HTTP请求;启用HTTP/2后,一个连接还可能并行承载多个请求。因此,Current Connections 很高时,不能直接推导出需要提高应用池队列。反过来,连接数不高,也不能证明没有并发瓶颈:短请求可能快速建立、快速释放连接,但在应用池内排队。
可以使用一个简单关系估算请求层面的并发量:
请求并发数 ≈ 吞吐量(每秒请求数)× 平均响应时间(秒)
例如,一个接口稳定完成 80 RPS,平均服务时间为 0.5 秒,正在处理的请求大约为 40 个。这个数字不是TCP连接数,也不是应该直接设置的 queueLength,只是帮助判断请求处理规模的参考。
香港节点需要把网络时延单独拆出来
香港服务器面向不同地区用户时,客户端看到的总延迟可以拆成:

客户端总延迟 ≈ 网络往返时延 + TLS及连接建立耗时 + IIS排队时间 + 应用处理时间 + 数据传输时间
如果客户端侧 p95 为 900 ms,而IIS日志中的 time-taken 只有 180 ms,同时应用池队列为0、CPU约为50%,继续提高应用池并发通常不会解决问题。此时应优先检查访问线路、TLS连接复用、响应体大小和用户到香港节点之间的网络路径。
如果IIS time-taken 也持续升高,且队列长度随并发增长,才更可能是服务器端处理能力不足。测试时应分别记录客户端耗时和IIS日志耗时,避免把网络问题误判成IIS线程问题。
先建立基线,再决定调哪个参数
测试目标要固定业务比例
并发测试不能只用一个空接口或静态首页。至少应区分:
- 静态资源请求,例如图片、CSS、JavaScript和下载文件;
- CPU型动态请求,例如模板渲染、序列化和加密计算;
- 数据库型请求,例如列表、搜索、订单查询;
- 外部依赖请求,例如支付、短信、第三方API;
- 长连接或长耗时请求,例如文件上传、导出和实时推送。
测试前固定以下条件,结果才有可比性:
- 使用与真实业务接近的请求比例、响应体大小和认证流程。
- 记录冷启动与预热后的结果,不能只看第一次访问。
- 压测端不要与香港服务器共用CPU、内存或出口带宽。
- 采用逐步加压,而不是一开始直接发送最大并发。
- 每个负载档位至少保持数分钟,并观察队列、错误率和内存是否持续增长。
- 同一轮测试中不要同时修改应用池、数据库连接池和操作系统策略。
一个可执行的测试流程可以是:预热5分钟,分阶段加压5分钟,目标负载稳定运行15分钟,最后进行30分钟以上的持续运行。短时间冲高适合发现队列和CPU瓶颈,持续运行则更容易发现内存增长、句柄泄漏、连接池未释放和定时回收问题。
需要同时观察的指标
| 观测层 | 主要指标 | 异常时的第一判断 |
|---|---|---|
| IIS日志 | time-taken、sc-status、sc-substatus、sc-win32-status | 是应用慢、排队,还是连接被拒绝 |
| HTTP.sys和IIS | 当前连接、请求队列、拒绝请求 | 请求是否堵在进入工作进程之前 |
| CPU | 总CPU、w3wp.exe CPU、特权态CPU | 应用计算、驱动或安全扫描是否占用处理器 |
| 内存 | 可用内存、工作集、Private Bytes、提交量 | 是否存在泄漏、缓存过大或回收时内存不足 |
| 线程和句柄 | 工作进程线程数、句柄数、上下文切换 | 是否线程阻塞、句柄泄漏或线程过度增长 |
| 磁盘 | 平均读写延迟、队列长度、写入速率 | 日志、临时文件、数据库或杀毒扫描是否拖慢请求 |
| 网络 | 入出方向速率、丢包、连接状态 | 带宽、长连接或连接建立是否成为限制 |
| 共享资源 | 数据库连接等待、锁等待、缓存命中率 | IIS只是表面瓶颈,真正限制在后端 |
Windows Server可以先使用性能计数器获取一组基线。以下命令只读取指标,不会改变配置:
Get-Counter `
'\Processor(_Total)\% Processor Time', `
'\Memory\Available MBytes', `
'\LogicalDisk(_Total)\Avg. Disk sec/Read', `
'\LogicalDisk(_Total)\Avg. Disk sec/Write', `
'\Network Interface(*)\Bytes Total/sec', `
'\HTTP Service Request Queues(*)\CurrentQueueSize', `
'\Web Service(_Total)\Current Connections' `
-SampleInterval 5 -MaxSamples 12
如果计数器名称因系统语言或组件安装情况不同而无法识别,可以先查询本机可用计数器:
Get-Counter -ListSet * | Select-Object -ExpandProperty Counter
同时查看每个工作进程的资源变化:
Get-Process w3wp -ErrorAction SilentlyContinue |
Select-Object Id, CPU, WorkingSet64, PrivateMemorySize64, Threads, Handles
连接状态则不能只依赖任务管理器:
Get-NetTCPConnection -State Established |
Group-Object OwningProcess |
Sort-Object Count -Descending
如果某个进程的连接数持续增长,但请求吞吐没有同步增加,应检查Keep-Alive、WebSocket、请求超时和客户端连接释放。若 TIME_WAIT 大量增长,则要进一步确认是否为出站短连接过多,不能简单通过提高IIS入站连接上限处理。
IIS请求路径:连接、队列、进程和共享资源
连接上限用于保护,不是吞吐开关
站点连接相关设置主要解决两个问题:
- 防止大量长连接耗尽内存和句柄;
- 在服务器已经无法继续处理时尽早拒绝一部分请求,避免所有请求都排队到超时。
maxConnections 应根据实际连接峰值、连接类型和内存余量设置。静态短请求、普通动态请求、文件上传和WebSocket的连接占用方式不同,不能套用同一个数值。
connectionTimeout 也要结合业务设置。将超时时间改得很短,可以减少慢客户端长期占用连接,但会误伤大文件上传、弱网用户和服务端处理时间较长的接口。将其无限延长,则可能让异常连接长期占用资源。
查看站点当前配置:
Import-Module WebAdministration
Get-ItemProperty 'IIS:\Sites\Default Web Site' |
Select-Object Name, Bindings, Limits
Get-ItemProperty 'IIS:\AppPools\DefaultAppPool' |
Select-Object Name, queueLength, managedRuntimeVersion, processModel
如果确实需要调整站点连接限制,应先备份IIS配置,并在低流量时段执行。下面的备份命令会保存当前IIS配置:
& "$env:windir\system32\inetsrv\appcmd.exe" add backup BeforeConcurrencyTune
示例配置仅用于说明调整对象,数值不能直接视为所有业务的推荐值:
Import-Module WebAdministration
Set-ItemProperty 'IIS:\Sites\Shop' `
-Name limits.maxConnections `
-Value 1500
Set-ItemProperty 'IIS:\Sites\Shop' `
-Name limits.connectionTimeout `
-Value ([TimeSpan]::FromMinutes(2))
设置前应确认站点名称、IIS版本和业务类型。修改站点或应用池配置可能触发配置重新加载,个别应用会发生短暂回收。回滚时优先把参数改回变更前的值;如果需要恢复完整备份,应在维护窗口执行,因为恢复IIS配置可能影响多个站点:
& "$env:windir\system32\inetsrv\appcmd.exe" restore backup BeforeConcurrencyTune
不要把连接上限设置为一个远高于物理资源承载能力的数字。更高的上限只意味着更多连接可以进入服务器,并不代表CPU、内存、数据库和出口带宽会同步增加。
应用池队列长度决定等待方式
应用池队列中的请求已经到达IIS,但暂时没有被工作进程处理。队列长度过小,突发流量会较快返回503;队列长度过大,请求虽然暂时不报错,却可能等待数秒甚至更久,最终以超时结束。
可以用下面的方式估算一个起始范围:
可接受队列容量 ≈ 目标到达速率 × 可接受等待时间
例如,动态请求到达速率约为120 RPS,业务允许最多等待2秒,计算结果约为240个等待请求。实际还需要考虑流量突发、请求大小和下游资源,因此可以从300左右的量级开始验证,而不是直接使用数千甚至数万。
应用池队列参数示例:
Import-Module WebAdministration
Set-ItemProperty 'IIS:\AppPools\ShopPool' `
-Name queueLength `
-Value 300
调整后重点观察:
- 队列是否只在短时突发时上升,随后能够回落;
- p95和p99是否因排队明显增加;
- 503错误是否减少,但超时是否增加;
- 工作进程CPU是否已经达到瓶颈;
- 数据库连接等待是否随队列一起增长。
如果队列持续增长且CPU只有40%,通常不应该继续加大队列。此时应检查数据库连接池、锁等待、外部API、文件I/O或应用代码中的同步阻塞。队列只是把压力保存下来,不会创造处理能力。
工作进程数量不是越多越好
常规业务应用池通常从一个工作进程开始。把 maximumWorkerProcesses 改成多个进程,也就是启用Web Garden,可能减少单进程线程竞争,但会带来以下代价:
- 进程内Session无法自然共享;
- 进程内缓存需要重复加载;
- 每个进程可能各自创建数据库连接池;
- 内存占用和启动预热时间增加;
- 回收或故障时可能同时影响多个进程。
只有在应用明确支持多进程、单进程CPU或锁竞争已经被证明是瓶颈,并且Session、缓存和连接池都经过验证时,才考虑增加工作进程数量。多数情况下,先修复同步I/O、慢SQL和锁等待,比直接增加进程更有效。
线程数应由阻塞证据驱动
动态请求通常会经过应用线程池。以下现象可能指向线程池或同步阻塞:
- CPU不高,但请求队列和延迟持续升高;
- 工作进程线程数不断增长;
- 大量线程处于等待状态;
- 数据库或HTTP调用使用同步方式占用线程;
- 少量慢请求会拖慢大量普通请求。
ASP.NET Framework和ASP.NET Core的线程调度机制并不完全相同,不能把某个版本的 maxWorkerThreads、minFreeThreads 或 maxConcurrentRequestsPerCPU 直接复制到另一种应用。尤其是盲目提高线程上限,可能增加上下文切换、内存占用和下游连接压力。
更优先的检查顺序是:
- 确认应用是否存在同步等待、锁竞争或长时间阻塞。
- 检查数据库查询、外部HTTP调用和文件操作是否支持异步或超时。
- 检查线程池可用线程、线程增长速度和请求排队时间。
- 只有在应用栈、运行时版本和压测结果都支持时,才调整线程相关参数。
- 调整后同时观察CPU、上下文切换、线程数和p95,而不是只看RPS。
共享资源决定了IIS调优的上限
数据库连接池需要按进程数计算
如果应用池有两个工作进程,每个进程的数据库连接池上限为100,那么理论上可能出现接近200个数据库连接。若服务器上有三个类似应用池,数据库端可能承受的连接数就不再是100,而是多个进程和应用池的总和。
因此应使用以下关系核对:
数据库潜在连接数 ≈ 应用池数量 × 工作进程数 × 单进程连接池上限
实际连接数还会受到并发请求、连接复用和查询时长影响,但配置上限不能只看单个进程。若IIS队列增加时,数据库连接等待也增加,而数据库CPU、锁等待或磁盘延迟已经较高,继续提高IIS并发只会把压力推向数据库。
文件、日志和杀毒扫描会制造隐性I/O
以下资源经常被忽略:
- 大量访问日志写入同一磁盘;
- 应用生成临时文件或导出文件;
- 上传目录被实时扫描;
- 数据库文件与IIS日志共用低性能磁盘;
- 应用频繁读取网络共享目录;
- 缓存失效后同时加载大量文件。
如果CPU、队列和数据库指标都正常,但磁盘平均延迟在高并发时显著升高,应先区分读取、写入、日志和安全扫描来源。不要为了短期性能直接关闭防护或对整个磁盘设置排除项。任何安全软件排除都应限定到经过确认的目录,并经过安全审批和回滚验证。
带宽也要按单位计算
例如,一个接口每秒返回20个10 MB文件,十进制口径下:
- 数据量:20 × 10 MB = 200 MB/s;
- 换算为比特:200 × 8 = 1600 Mb/s;
- 因此约为1.6 Gb/s。
这还没有计算协议开销、其他业务流量和上下行方向。如果服务器出口只有1 Gb/s,继续提高IIS连接数不会提高文件下载吞吐,反而会增加等待和超时。动态接口则应同时考虑响应体大小、压缩CPU和带宽占用。
应用池回收:控制风险,不要用来掩盖泄漏
正常回收和异常回收要分开
应用池回收有几种常见触发方式:
- 按固定时间间隔回收;
- 按计划时间回收;
- 私有内存或虚拟内存超过阈值;
- 配置变更、应用部署或系统重启;
- 快速失败保护触发;
- 手工回收。
固定间隔回收可以降低长期运行风险,但如果回收时间与业务峰值重叠,就会把预热、缓存重建和连接重新建立的成本叠加到高峰期。更可控的方式是在低流量时段安排回收,并确保应用有健康检查和预热机制。
私有内存阈值适合用于已确认的内存持续增长场景,但它不是泄漏修复方案。如果应用每隔一段时间就因阈值回收,内存曲线仍然上升,应分析托管堆、非托管内存、缓存、句柄和第三方组件,而不是不断提高阈值。
关注回收时的内存峰值
启用重叠回收时,旧工作进程退出前,新工作进程可能已经启动。这样可以缩短切换期间的不可用时间,但也可能出现短时间内两个进程同时占用内存。
例如,单个工作进程稳定使用3.5 GB内存,服务器可用余量只有2 GB,那么重叠回收时可能触发分页、内存压力甚至新进程启动失败。此类应用需要在压测中观察回收期间的Private Bytes、可用内存、启动耗时和错误率,再决定是否调整重叠回收策略。

应用池回收的核对重点如下:
| 配置项 | 适合关注的场景 | 主要风险 |
|---|---|---|
| 固定时间回收 | 应用需要周期性释放资源 | 与业务峰值重合,造成瞬时延迟 |
| 计划回收 | 流量高低峰明确 | 流量变化后原计划不再适合 |
| 私有内存阈值 | 已发现内存持续增长 | 反复回收掩盖内存泄漏 |
| 空闲超时 | 低频业务、启动成本可接受 | 高峰前首次请求变慢 |
| AlwaysRunning或预加载 | 启动和缓存预热耗时较长 | 持续占用内存和后台资源 |
| 重叠回收 | 需要缩短切换中断 | 回收期间内存可能接近两倍 |
| 快速失败保护 | 防止应用池反复崩溃拖垮服务器 | 不应为了减少503而关闭 |
如果启用Always Running或站点预加载,应确保应用启动过程幂等、健康检查地址不会触发真实业务写入,并确认启动时不会一次性建立过多数据库连接。应用启动失败时要保留快速失败保护,避免故障进程不断重启。
组策略:关注会改变性能基线的设置
组策略不直接决定IIS能处理多少请求,但可能改变CPU频率、重启时间、磁盘访问和安全扫描行为。
电源策略要先测再改
先查看当前电源方案:
powercfg /getactivescheme
powercfg /list
如果服务器在虚拟化环境中,还要结合宿主机CPU调度和超分配情况判断。对延迟敏感业务,可以在维护窗口测试高性能方案与平衡方案的差异,但不应仅因CPU曾达到高位就永久切换。比较时应使用同一批请求,观察p95、CPU频率、功耗、温度和宿主机资源。
不要用组策略关闭安全功能换取吞吐
以下做法不应作为常规IIS优化手段:
- 关闭Windows Defender实时防护;
- 关闭安全审计和系统日志;
- 关闭Windows Update服务;
- 放宽所有目录权限;
- 对整个系统盘设置杀毒排除;
- 随意修改TCP端口范围或注册表参数。
只有在确认某个安全组件的扫描行为与特定目录存在性能冲突时,才应采用最小范围、可审计、可撤销的调整,并在调整后重新进行安全检查。端口耗尽也不能靠修改注册表作为第一反应,应先确认是出站短连接、TIME_WAIT、连接泄漏还是应用没有复用连接。
补丁管理要纳入性能测试
Windows Server、IIS、.NET运行时和安全组件更新后,可能发生以下变化:
- TLS或加密开销变化;
- HTTP协议栈行为变化;
- .NET线程池或垃圾回收行为变化;
- 安全扫描策略变化;
- 驱动、存储或网卡性能变化;
- 更新重启导致应用池全部冷启动。
更新前可以记录当前补丁和运行环境:
Get-HotFix |
Sort-Object InstalledOn -Descending |
Select-Object -First 15 HotFixID, InstalledOn, Description
Get-ComputerInfo |
Select-Object WindowsProductName, WindowsVersion, OsBuildNumber
建议采用以下补丁流程:
- 在测试或预发布服务器安装更新,执行与生产相同的接口混合压测。
- 检查IIS配置备份、应用版本、数据库兼容性和第三方组件。
- 选择一台或一组低风险节点进行灰度更新。
- 重启后先执行健康检查和应用预热,再开始对比测试。
- 对比更新前后的p95、5xx、CPU、Private Bytes、队列、磁盘延迟和启动时间。
- 只有在结果稳定后,才扩大更新范围。
- 若出现回归,按变更记录执行回滚或切换到已验证镜像,不要在生产中反复试改多个参数。
使用组策略管理更新时,应特别检查活动时间、自动重启、计划任务和登录脚本。更新本身可能不是性能问题来源,更新后的重启、预热、扫描和计划任务才可能造成短时波动。
用一组示例数据判断瓶颈位置
下面是一组用于说明判断方法的模拟结果,并非特定服务器的实测数据:

| 并发请求数 | 吞吐RPS | p95延迟 | CPU | 应用池队列峰值 | Private Bytes | 数据库等待 |
|---|---|---|---|---|---|---|
| 100 | 72 | 180 ms | 43% | 0 | 2.8 GB | 低 |
| 300 | 108 | 390 ms | 76% | 18 | 3.0 GB | 中 |
| 500 | 111 | 1.9 s | 94% | 260 | 3.1 GB | 中 |
| 700 | 108 | 4.8 s | 97% | 620 | 3.2 GB | 高 |
这组数据中,300到500并发之间已经出现明显拐点:吞吐几乎不再增加,p95从390 ms升至1.9 s,CPU接近饱和,队列快速增长。此时直接把队列长度从1000调到5000,只会让更多请求等待,不能把吞吐从111 RPS提升到更高水平。
应进一步确认:
- CPU是否主要消耗在应用计算,还是特权态、压缩或安全扫描;
- 单个接口是否存在热点代码;
- 数据库等待是否由CPU、锁或慢查询造成;
- 是否可以通过缓存、批量查询或异步I/O降低单请求占用;
- 响应体大小和压缩是否占用大量CPU;
- 应用池回收或内存压力是否出现在同一时间段。
如果CPU只有50%,队列却持续升高,判断方向就不同:重点应转向数据库连接池、外部API、文件I/O、锁等待和线程阻塞,而不是继续提高CPU相关参数。
按照现象选择调整动作
| 现象 | 更可能的原因 | 优先动作 | 不宜立即做的事 |
|---|---|---|---|
| 连接数高但请求耗时低 | Keep-Alive、HTTP/2或长连接 | 核对连接类型、超时和内存占用 | 盲目提高工作线程 |
| 队列高、CPU高、吞吐不再增加 | 应用计算能力达到上限 | 优化热点代码、拆分接口或增加实例 | 只增大队列 |
| 队列高、CPU低、线程多 | 同步阻塞或下游等待 | 查数据库、外部调用、锁和线程池 | 直接提高CPU配额 |
| 503.2增加、队列很快达到上限 | 队列过小或突发流量 | 校验可接受等待时间和到达速率 | 无限制扩大队列 |
| 回收后延迟明显上升 | 缓存和运行时重新预热 | 安排低峰回收、完善预热 | 关闭所有回收 |
| Private Bytes持续上升 | 内存泄漏或缓存无界增长 | 采集堆、句柄和缓存数据 | 仅通过频繁回收掩盖问题 |
| 客户端延迟高、IIS耗时低 | 网络路径或传输问题 | 分析RTT、响应体和连接复用 | 继续调应用池 |
| 磁盘延迟高、CPU正常 | 日志、临时文件、数据库或扫描 | 拆分磁盘负载并查I/O来源 | 关闭安全防护 |
每次变更只改一类变量。例如先调整应用池队列并完成复测,再决定是否修改连接上限;不要同时改变队列、线程、数据库连接池和组策略,否则即使结果变好,也无法知道是哪项变更起作用。
以复测门槛确定容量余量
容量不能只用“最大并发数”表示,更适合定义为满足业务目标时的稳定吞吐。一个可执行的容量判断条件可以包括:
- p95延迟低于业务目标;
- p99没有持续向上爬升;
- 5xx和超时率低于既定错误预算;
- 应用池队列在稳态时能够回落;
- CPU、内存、磁盘和网络中没有一项长期贴近上限;
- 数据库连接等待和锁等待处于可接受范围;
- 经过至少一轮长时间运行后,Private Bytes和句柄没有持续增长;
- 回收、重启和补丁后的预热结果仍然满足目标。
例如,某业务在110 RPS时p95为420 ms、错误率低、队列可回落;在125 RPS时p95超过1.2 s且队列持续增加,那么110 RPS附近才是当前配置下的稳定容量参考。若要留出30%的突发余量,生产常态流量就不宜长期贴近该上限,具体比例应根据业务峰值和扩容速度确定。
完成调优后,应在以下条件下复测:
- 使用同样的请求比例、响应大小和测试地区。
- 使用同样的应用版本、数据库数据量和缓存状态。
- 记录客户端总耗时与IIS
time-taken,分离网络和服务器处理时间。 - 分别进行短时峰值测试和长时间稳定性测试。
- 至少覆盖一次应用池正常回收、系统重启后的预热和补丁后的验证。
- 对每项参数保留变更前值、变更时间、影响站点和回滚方式。
当队列、CPU、数据库等待和p95在同一个负载档位同时出现拐点时,通常已经找到了容量边界;当只有客户端延迟升高而服务器端指标平稳时,则应把问题交给网络、线路或响应传输环节,而不是继续增加IIS并发参数。