眾所周知,當我們使用IIS的時候,在使用負載均衡的情況下,想停掉一個站點,通常會點擊Sites(網站)中的Stop(停止)來停止一個站點。但是這樣做,會帶來一個問題,當點擊Stop(停止)時,正在響應中的請求會立刻被切斷,使客戶端無法收到響應,後續也無法連接該站點,在某些業務場景中,比如涉及金額交易 ...
眾所周知,當我們使用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和博客園,歡迎讀者轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接!請讀者/爬蟲們尊重版權