如何优雅的关闭一个IIS站点

众所周知,当我们使用IIS的时候,在使用负载均衡的情况下,想停掉一个站点,通常会点击Sites(网站)中的Stop(停止)来停止一个站点。但是这样做,会带来一个问题,当点击Stop(停止)时,正在响应中的请求会立刻被切断,使客户端无法收到响应,后续也无法连接该站点,在某些业务场景中,比如涉及金额交易业务,在没有使用幂等,锁等手段的情况下,强行切断的请求后,客户端不知道该交易的交易情况,如果再次请求(因为本站点已停止,负载均衡会指向其他机器)会造成重复交易,如果不请求,客户端也不能确切的知道该交易已经成功。类似微服务中,服务间请求超时的情况。

熟悉IIS的读者通常不会直接停止站点,而会选择点击Application Pools(应用程序池)中的Stop(停止)来停止一个站点,应用程序池在被停止后,新的请求会被响应503,负载均衡识别到503后,会把该请求负载到其他机器上,以保证业务不会中断。同样的问题,当点击Stop(停止)停止时,正在响应的请求,会发生什么情况呢。有经验的开发/运维会回答,在Application Pools(应用程序池)里Advanced Settings(高级设置)中Process Model(进程模型)组包含一个Shutdown Time Limit(关闭时间限制)选项,默认值为90s。这就意味着当应用程序池停止、回收时,IIS会最多等待没响应的请求90s,如果90s内,所有的请求响应完毕,应用程序池就会被停止、回收。那么如何判断IIS在这90s内未响应请求是否全部被响应呢,如果部署的程序是ASP.NET Core,可以在Event Viewer(事件查看器)/Windows Logs(Windows 日志)/Application(应用程序)里查看事件日志,如果出现Failed to gracefully shutdown application 'MACHINE/WEBROOT/APPHOST/xxx'.这个警告,则表明存在请求没有被响应,被IIS强行关闭的情况。

事与愿违,在实际生产实践中,读者会发现IIS并没有"等待"90s,就会关掉连接,而客户端还在傻傻等待90s后才会显示无响应,造成正在请求的HTTP无法响应。通过阅读[官方文档](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-8.0#ihostapplicationlifetime ".NET Generic Host in ASP.NET Core")我们得知,等ASP.NET Core收到关闭信号时,对于正在处理的HTTP请求,会等待5s,5s之后会像IIS那样关闭连接。所以我们需要设置HostOptions
var builder = WebApplication.CreateBuilder(args);

......

builder.Services.Configure<HostOptions>(options =>
{
    //If the timeout period expires before all of the hosted services stop, any remaining active services are stopped when the app shuts down. The services stop even if they haven't finished processing. If services require more time to stop, increase the timeout.
    //Default: 5 seconds
    options.ShutdownTimeout = TimeSpan.FromSeconds(30);
});

......
按照文档修改程序后,实际测试发现,设置.NET Generic Host的ShutdownTimeout"似乎"不生效, 在改动前由于IIS的Shutdown Time Limit默认是90s ,ASP.NET Core中ShutdownTimeout默认值是5s,所以在改动前IIS站点会最多等待正在请求的HTTP 5s 在改动后,笔者把.NET Generic Host的ShutdownTimeout调整至30s后,实测下来发现点击停止应用程序池后,竟然只能等正在请求中的HTTP 10s ! 于是再次搜索资料,终于发现还有一个参数需要设置-> https://stackoverflow.com/questions/51634638/graceful-shutdown-of-ihostedservice  和官方文档[地址](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/aspnet-core-module?view=aspnetcore-3.1#attributes-of-the-aspnetcore-element "ASP.NET Core Module (ANCM) for IIS") 在最近的文档(.NET 8)里竟然把Attributes of the aspNetCore element这一节删掉(移走)了,导致查阅最新文档,根部搜索不到所需信息,接下来按照文档操作就十分简单了,加上shutdownTimeLimit属性,修改web.config如下:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2"
          resourceType="Unspecified" />
      </handlers>
      <aspNetCore shutdownTimeLimit="30" processPath="dotnet" arguments=".\WebApplicationTest.dll" stdoutLogEnabled="true"
        stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
    </system.webServer>
  </location>
</configuration>
修改后,再次实测,即符合预期,在使用ASP.NET Core的情况下关于shutdownTime总结(省流)如下:

IIS应用程序池shutdownTime默认值为90s

AspNetCoreModuleV2shutdownTime默认值为10s

.NET Generic Host(应用程序)默认值为5s

如要修改shutdownTime则需同时关注以上三处设置。祝您使用愉快!

声明

本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可,发表在CSDN博客园,欢迎读者转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接!请读者/爬虫们尊重版权

posted @ 2023-12-02 17:40  ChasingDreams  阅读(500)  评论(0编辑  收藏  举报