[草稿]配置IIS支持10w并发
由于iis默认最多只能处理5000个并发请求,今天由于某种情况造成同时请求超过5000,从而报错 HTTP Error 503.2 - Service Unavailable
。
为了避免这样的错误,通过对IIS和OS的优化调整,让服务器从设置上支持10万个并发请求,示例以一台 40核-64GB-1200GB的物理机为例,具体设置如下:
适用的IIS版本:IIS 7.0, IIS 7.5, IIS 8.0, IIS 8.5
适用的OS版本:Windows Server 2008及2008 R2、Windows Server 2012
[TOC]
知识准备
工作线程数与队列长度
- 最大工作进程数 相当于某医院开设了多少个服务窗口,它是IIS实际可以第一时间处理的请求数。
比如,工作线程数 = 100,假如10000个连接请求同时涌过来, 那么只有100个可以被处理,其余9900个进入等待队列等待,或者直接以503错误(服务器不可用)返回。
- 队列长度 相当于某医院大厅的排队座位。除了IIS工作线程数可以第一时间进行处理外,其余的请求可以进入等待队列进行等待的数量。
比如:工作线程数 = 100,队列长度 = 5000,假如10000个连接请求同时涌过来,将有100个第一时间被处理,5000个等待,4900个以503返回。
- 最大并发连接数 = 队列长度 + 工作线程数。
#.场景1:
工作线程数 = 100
队列长度 = 5000
最大并发连接数 = 5000
那么10000个连接请求同时涌过来,将有100个第一时间被处理,4900个进入队列等待,5000个以503返回。
#.场景2:
工作线程数 = 100
队列长度 = 5000
最大并发连接数 = 10000
那么10000个连接请求同时涌过来,将有100个第一时间被处理,5000个进入队列等待,4900个以503返回。
关于 最大工作进程数 的最佳实践:
最大工作进程数,不要超过CPU核数;
- 按照每个工作进程能承载30个并发的原则来确定应用程序池的最大工作进程数;
- 每个工作进程大约会占用200M的物理内存,注意最大工作进程数与200M的乘积不要超过可用内存;
- 队列长度,建议 = 最高并发用户 x 1.5,例如:最高2000并发,则设置队列长度3000(用户数*1.5);
建议每次增加5个工作进程数的方式对最大工作进程数进行调整,调整完后对网站观察一段时间,如果依然无法满足要求,再继续增加5个工作进程数。
针对不同规模的网站,推荐的设置如下:
场景 | 硬件配置 | 最大工作进程数 | 队列长度 | 最大并发连接数 |
---|---|---|---|---|
小型网站(单台最高并发5h) | 4核-8G | 2(默认1) | 1000(默认1000) | 默认4294967295 |
中型网站(单台最高并发6k) | 16核-16G | 1-16,比如10 | 9000 | 默认4294967295 |
大型网站(单台最高并发2w) | 24核-32G | 20 | 65535 | 默认4294967295 |
网站性能指标
指标 | 好 | 正常 | 差 | 备注 |
---|---|---|---|---|
首屏时间 | 小于3秒 | 3~5秒 | 大于5秒 | 反映用户打开页面速度的直观感受 |
可用性 | 大于95% | 90~95% | 小于90% | 反映页面打开成功率,过低影响站点形象 |
DNS | 小于0.18秒 | 0.18~0.3秒 | 大于0.3秒 | DNS解析时间,用户访问页面的第一步 |
建立连接时间 | 小于0.15秒 | 0.15~0.3秒 | 大于0.3秒 | 浏览器和WEB服务器建立TCP/IP连接的消耗时间 |
重定向时间 | 无 | 小于0.1秒 | 大于0.1秒 | 从收到WEB服务器重定向指令,到请求WEB服务器的第一个元素之前的消耗时间 |
收到第一个包时间 | 小于0.2秒 | 0.2~0.4秒 | 大于0.4秒 | 从浏览器发送HTTP请求结束开始到收到WEB服务器返回的第一个数据包的消耗时间 |
总下载时间 | 小于10秒 | 10~20秒 | 大于20秒 | 页面所有内容下载时间,反映的是页面的总体消耗,不同类型站点标准不同。仅参考 |
CDN节点匹配率 | 大于95% | 90~95% | 小于90% | 指用户访问URL时是否分配到相应的运营商主机,如联通用户应访问联通主机 |
CND节点错误率 | 小于5% | 5~10% | 大于10% | 用户访问URL时各CDN节点的错误情况 |
主机性能对比 | 小于3秒 | 3~5秒 | 大于5秒 | 最好的CND主机与最差的CND主机首屏时间对比 |
请求过多可能造成的报错
- 场景1:请求过多导致的cat报错,关键词:0x80131904、找不到网络路径
System.Data.SqlClient.SqlException (0x80131904): 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。
未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。
(provider: Named Pipes Provider, error: 40 - 无法打开到 SQL Server 的连接) ---> System.ComponentModel.Win32Exception (0x80004005): 找不到网络路径。
- 场景2:同类的JDBC错误,关键词:0x80131904、信号灯超时时间已到
### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException:
Could not get JDBC Connection; nested exception is com.atomikos.jdbc.AtomikosSQLException: Failed to grow the connection pool.
Exception:System.Data.SqlClient.SqlException(0x80131904): 在从服务器接收结果时发生传输级错误。
(provider: TCP Provider, error: 0 – 信号灯超时时间已到) ===> System.ComponentModel.Win32Exception (0x80004005):信号灯超时时间已到
- 场景3:IIS连接数暴涨,网站无法登录或查询,而 SQL Server Log 爆出大量10856错误,CPU很低,窗口查询正常
日期 源 消息
2017/11/2 19:45:53 spid108 The client was unable to reuse a sessin with SPTD 108, which had been reset for connetion pooling, The failwre ID is 29.
2017/11/2 19:45:53 spid108 错误: 18056,严重性: 20,状态: 29。
SQL Server报18056错误的分析过程:
假设IIS的连接池设置100M,IIS连接数正常100个,那么每个session分配的连接池为1MB。由于数据库网络数据包默认4096字节(即4KB),假如每个session要返回4KB数据,则会话保持4/4=1秒。若偶尔几个需要返回2MB数据,该会话将会保持2*1024/4=512秒,正常情况可以慢慢消化,不会有太大问题。
若连接池100M,IIS连接数达到500个,则每个session分配的连接池为0.2MB,若每个session仅返回4KB数据,则会话保持4/4=1秒,但如果客户端不断的请求,超过最大连接数则会出现排队等待,直到有空闲的连接,这个等待时间受connection timeout(默认15s)限制,如果每个请求都能快速得到响应,即便有排队,也会慢慢消化。
若连接池100M,IIS连接数达到500个,则每个session分配的连接池为0.2MB,若有50个请求都要返回10MB(共500MB)数据,当数据库返回给IIS时发现连接池(100MB)没有足够的内存空间分配给这50个session。由于连接池不会随客户端请求的增加而自动增加,IIS就会释放掉无法处理的session。当数据库收到IIS请求并准备返回数据给相应session时却发现该spid已不存在,但是数据库的TCP连接不会因为spid不存在而立即抛弃这些数据,就会报18056错误,同时网卡流量也会增加。
- 场景4:在事件查看器中,看到大量 MSSQLSERVER 错误:
级别 日期和时间 来源 时间ID 任务类别
错误 2017/11/2 19:45:51 MSSQLSERVER 18056 服务器
客户端无法重新使用 SPID 为 226 的会话,该会话已被重置用于连接池。失败 ID 为 29。此错误可能是由于先前的操作失败引起的。请查看错误日志,了解紧位于次错误消息之前的失败操作。
- 场景5:收到iis连接数过多及http 503的告警,执行
netstat -ano > d:\netstat.log
并将该日志放到linux上分析,得到请求最多的ip、大量CLOSE_WAIT状态的连接
[root@localhost]# cat netstat.log | grep ":80" | wc -l
6371
[root@localhost]# cat netstat.log | grep ":80" | awk '{print $3}' | awk -F ':' '{print $1}' | sort|uniq -c |sort -nr |head -5
1987 81.70.194.152
1509 81.70.192.175
1387 81.70.205.211
755 81.70.198.136
396 10.20.101.161
[root@localhost]# cat netstat.log | grep ":80" | awk '{print $4}' | sort|uniq -c |sort -nr |head -5
4656 CLOSE_WAIT
1061 ESTABLISHED
393 TIME_WAIT
202 LAST_ACK
45 SYN_RECEIVED
优化配置实战
应用程序池的设置
打开应用程序池,找到Web站点对应的应用程序池,右键“高级设置”
- [01] (常规)-.NET CLR版本:确认为v4.0
- [02] (常规)-队列长度:默认值1000,将原来的队列长度改为 65535
- [03] (常规)-启动32位应用程序:默认值False,改为True, 否则安装一些32位的组件或php都会出错
- [04] (常规)-托管管道模式:默认Integrated,改为Integrated或Classsic
- [05] (进程模型)-闲置超时(分钟):默认20分钟,改为120分钟
注:也有建议设置为0,即不让应用程序池因为没有请求而回收
- [06] (进程模型)-最大工作进程数:默认1,改为xx(太大则造成内存紧张及其他副作用)
- [07] (快速故障防护)-已启用:默认True,改为False
- [08] (回收)-固定时间间隔(分钟):默认1740分钟,改为0,表示不回收。
注:即禁用应用程序池定期自动回收,解决第一次打开PEP速度慢的问题。
- [09] (回收)-禁用重叠回收:默认False,改为True
注:禁用之后,可有效避免Windows Server 2008 R2应用程序池回收假死的问题
- [待定] (快速故障防护)-最大故障数:默认5,改为65535
网站设置的设置
打开网站,找到对应的网站,右键“管理网站”,选择“高级设置”
- [10] (限制)-最大并发连接数:默认4294967295,改为100000
.Net Framework的相关设置
- [11] 调整IIS 7的appConcurrentRequestLimit设置,由原来的默认5000改为100000,以下在cmd中执行:
cd /d c:\windows\system32\inetsrv\
appcmd.exe set config /section:serverRuntime /appConcurrentRequestLimit:100000
type c:\windows\system32\inetsrv\config\applicationHost.config | findstr appConcurrentRequestLimit
- [12] 调整machine.config中的requestQueueLimit设置,以下在cmd中执行:
notepad %systemroot%\Microsoft.Net\Framework64\v4.0.30319\CONFIG\machine.config
打开 machine.config
后,在 <system.web>
中找到如下所示的 processModel
元素:
找到 <processModel autoConfig="true" />
改为 <processModel enable="true" requestQueueLimit="100000" />
- [13] 调整ASP.NET线程配置,以下在cmd中执行:
notepad %systemroot%\Microsoft.Net\Framework64\v4.0.30319\CONFIG\machine.config
打开 machine.config
后,在 <processModel>
中添加如下设置:
<processModel enable="true" maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50" minIoThreads="50" />
注册表的相关设置
- [14] 调整IIS 7支持的TCP最大并发数,由原来的默认5000改为100000,以下在cmd中执行:
reg add HKLM\System\CurrentControlSet\Services\HTTP\Parameters /v MaxConnections /t REG_DWORD /d 100000
reg query HKLM\System\CurrentControlSet\Services\HTTP\Parameters /v MaxConnections
for /f "tokens=3 delims= " %i in ('reg query HKLM\System\CurrentControlSet\Services\HTTP\Parameters /v MaxConnections') do set /a %i
- [15] 解决Bad Request - Request Too Long问题,以下在cmd中执行:
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters /v MaxFieldLength /t REG_DWORD /d 32768
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters /v MaxRequestBytes /t REG_DWORD /d 32768
应用设置
- [16] 在web.config中添加如下几行,设置
Cache-Control
为public
<configuration>
<system.webServer>
<staticContent>
<clientCache cacheControlCustom="public" />
</staticContent>
</system.webServer>
</configuration>
- [17] 代码上,Connection连接对象一定要及时 conn.Close() 关闭
- [18] IIS站点,要在web.config里合理设置数据库最大连接池 Max Pool Size(默认100,建议xxx)
<connectionStrings>
<add name="xxx" connectionstring="data source=192.168.4.120;pooling=true;max pool size=xxx;min pool size=5;packet size=4096;initial catalog=xxx;user id=xxx;password=xxx;connection timeout=180;" providername="system.data.sqlclient"/>
</connectionStrings>
- [19] 若是JAVA业务,要在连接字符串中配置 minPoolSize 及 maxPoolSize
<bean>
<property name="user" value="xxx"/>
<property name="password" value="xxx"/>
<property name="minPoolSize" value="5"/>
<property name="maxPoolSize" value="100"/>
<property name="borrowConnectionTimeout" value="60"/>
<property name="maxLifetime" value="1200"/>
</bean>
重启站点服务
- [20] 运行 iisreset 重启iis使设置生效
net stop http & net start http & iisreset
完成上述设置,就可以支持10万个并发请求。