HttpPlatformHandler 是一個支援 IIS 8 與 IIS 8.5 的原生模組 (native module),主要使用於 Microsoft Azure Websites 網站服務中,用途是讓 Java 或其他第三方程序可以輕鬆整合到 IIS 之中,讓各種 Web 框架都能直接掛載到 IIS 之上。而近期發佈的 ASP.NET 5 Beta8 版本也正式宣告改採 HttpPlatformHandler 模組搭配 Kestrel HTTP Server 執行 ASP.NET 5 應用程式,想要了解其內部運作結構,必須得了解一下。
基本上 HttpPlatformHandler 主要做兩件事:
- Process Management of http listeners 任意第三方程序原本需要監聽 (listen) 可接受 HTTP 要求的通訊埠 (Port),都改交由 IIS 來接受要求。 例如 Tomcat, Jetty, Node.exe, Ruby 等等,當然 ASP.NET 5 的 Kestrel 也是屬於這個類型的程序。
- Proxy requests to the process that it manages 將那些交由 IIS 代理監聽的 HTTP 要求轉發到被管理的第三方程序。
簡單來說,原本你可能可以直接用 Node.js 或 Ruby 來執行網站,Node.js 或 Ruby 原本就能監聽 (listen) 通訊埠 (Port),但如果 Node.js 或 Ruby 掛掉的話,網站也就死了。不過若想透過 IIS + HttpPlatformHandler 來管理者些程序,優點就是所有接聽 HTTP 要求的任務都改由 IIS 負責,並且由 IIS 啟動第三方程序 ( 例如 Node.js 或 Ruby ),然後由 IIS 將這些 HTTP 要求轉發到第三方程序中。如果第三方程序掛掉了,IIS 就會視同沒有執行這個程序,並且自動重新啟動第三方程序。
HttpPlatformHandler 模組的設定主要設定在 web.config 或 applicationHost.config 設定檔裡,主要設定在 <system.webServer> 區段下,詳細的設定方法可參考 HttpPlatformHandler Configuration Reference 文件。
我們可以來看看幾個的設定範例:
1. ASP.NET 5
<configuration>
<system.webServer>
<handlers>
<add name="httpplatformhandler"
path="*"
verb="*"
modules="httpPlatformHandler"
resourceType="Unspecified" />
</handlers>
<httpPlatform
processPath="..\approot\web.cmd"
arguments=""
stdoutLogEnabled="false"
stdoutLogFile="..\logs\stdout.log"
startupTimeLimit="3600">
</httpPlatform>
</system.webServer>
</configuration>
2. Tomcat (Java)
<configuration>
<system.webServer>
<handlers>
<add name="httpplatformhandler"
path="*"
verb="*"
modules="httpPlatformHandler"
resourceType="Unspecified"/>
</handlers>
<httpPlatform processPath="c:\dev\javasites\bin\apache-tomcat-8.0.15\bin\startup.bat"
arguments=""
stdoutLogEnabled="true"
stdoutLogFile="\\?c:\dev\javasites\log.txt">
<environmentVariables>
<environmentVariable name="JRE_HOME" value="%programfiles%\java\jdk1.8.0_25" />
<environmentVariable name="CATALINA_OPTS" value="-Dport.http=%HTTP_PLATFORM_PORT% -Dsomeotherconfig=value"/>
<environmentVariable name="CATALINA_HOME" value="c:\dev\javasites\bin\apache-tomcat-8.0.15" />
</environmentVariables>
</httpPlatform>
</system.webServer>
</configuration>
3. Jetty (Java)
<configuration>
<system.webServer>
<handlers>
<add name="httpplatformhandler"
path="*"
verb="*"
modules="httpPlatformHandler"
resourceType="Unspecified"/>
</handlers>
<httpPlatform processPath="c:\Program Files\Java\jdk1.8.0_25\bin\java.exe"
arguments="-Djava.net.preferIPv4Stack=true -Djetty.port=%HTTP_PLATFORM_PORT% -Djetty.base="c:\dev\javasites\bin\jetty-distribution-9.2.6.v20141205" -jar "c:\dev\javasites\bin\jetty-distribution-9.2.6.v20141205\start.jar""
startupTimeLimit="20"
startupRetryCount="20"
stdoutLogEnabled="true">
</httpPlatform>
</system.webServer>
</configuration>
從以上幾個設定範例可以看出,其實 HttpPlatformHandler 的架構非常單純,就是由 IIS 幫你管理第三方程序,啟動第三方程序時,可直接設定啟動的程序 (processPath)、參數 (arguments) 與一些啟動參數,例如啟動時間限制 (startupTimeLimit)、啟動重試次數上限 (startupRetryCount)、是否輸出記錄到 stdout 管線中 (stdoutLogEnabled)、是否將輸出寫入到檔案中 (stdoutLogFile)、…等等,當然,必要的時候還可以設定額外的 環境變數 (environmentVariables) 給第三方程序使用。
關於 ASP.NET 5 Beta8 的重大變更
在 ASP.NET 5 發展的早期,有個 Helios 專案負責讓全新的 ASP.NET 5 框架能夠執行在 IIS 之上,這個 Helios 專案 (包含在 Microsoft.AspNet.Server.IIS 套件中) 主要用途是將 DNX 與 CLR 掛載到 System.Web hosting model 之中,在網站啟動之後動態抽換掉正在執行的 Runtime,改由 DNX 與 CoreCLR 來執行程式。這也意味著在 System.Web hosting model 與 DNX hosting model 有許多邏輯是重疊的,而日後在維護 ASP.NET 5 框架時勢必引發更複雜的實作,也很難維護兩個 hosting model 之間的一致性,因此微軟決定在 ASP.NET 5 Beta8 開始將 Helios 退役。
Helios 退役之後,便改用效能更好的 Kestrel 來執行 ASP.NET 5 應用程式,這個 Kestrel HTTP Server 基於 跨平台 的 libuv 函式庫,這個 libuv 函式庫採用非同步 I/O 架構,常用於 Node.js 之中,執行效能極佳,你可以看看 ASP.NET 5 Benchmarks 頁面最後的 Plain Text with HTTP Pipelining 測試數據,ASP.NET 5 on Kestrel 的壓力測試竟然可以測出每秒 443,528 個要求,這實在是個非常驚人的數字!
當然,你要知道 Kestrel 本身就是一台 HTTP 伺服器,不需要 IIS 也能運作,並且可在 Windows, Linux, OS X 上面跨平台執行。
只是在 Windows 平台上,你可以利用 IIS 搭配 HttpPlatformHandler 來執行,讓 IIS 幫你管理 Kestrel 程序,安全性與穩定度都將會大幅提高,不過唯一的缺點就是會犧牲掉一些效能,畢竟經由 IIS 代理所有的 HTTP 要求,這當中多少會有所損耗,但我認為這點損耗可以靠 橫向擴展 (Scale Out) 來解決,所以這是可以接受的權衡措施 (Trade-off)。
另外,使用 IIS / HttpPlatformHandler 搭配 Kestrel 來執行 ASP.NET 5 還有許多優點:
- 你的 IIS 應用程式集區不需要載入任何 Managed 程式碼,甚至於完全不用設定載入 CLR 就可以執行網站。( 因為所有 HTTP 要求都被轉送到 Kestrel 處裡 )
- 因為應用程式集區不需要載入 CLR,因此也不需要事先安裝 ASP.NET 相關元件。如下圖示,這就不一定要安裝了:
- 你原本的 ASP.NET 4.x 模組依然可以跑在 IIS 上面,就算你有啟用 HttpPlatformHandler 也完全不影響原本 IIS 模組的執行,因為 ASP.NET 4 與 ASP.NET 5 隸屬於完全不同的執行程序。
- 由於你可以在 web.config 中透過 HttpPlatformHandler 設定 環境變數 ,因此你可以透過 web.config 即可控制 ASP.NET 5 的 Environment 屬性值,只要透過設定檔就可以控制 ASP.NET 5 的執行過程。( 例如切換 Staging 或 Production 等模式,這些模式都可以自由設定,詳細說明可參考 ASP.NET 5 的 Working with Multiple Environments 文件 )
- 在多台伺服器之間使用一致的標準,處裡第三方程序的啟動錯誤。
- 一致的程式碼與執行過程:
- 無論你透過 self-hosted 或 IIS 執行 .NET Framework (full CLR) 時,都支援 app.config 設定檔讀取。 (ASP.NET 5 已經不再需要讀取 web.config 設定檔)
- 設定與使用服務元件時更加一致 ( Startup.cs )
- 一致的啟動過程 ( 不再有詭異的 bin\AspNetLoader.dll 檔案 )
最後,你若從 Visual Studio 2015 建立 ASP.NET 5 Beta8 專案,可以看到在 wwwroot\web.config 這個檔案
該檔案定義了 <httpPlatform> 設定,並在 processPath 與 arguments 放入了變數,這個變數會交由 Visual Studio 2015 進行管理,當在發佈網站時,會透過 dnu publish 命令,搭配 --iis-command 選項進行變更。
更詳盡的討論可以參考 Change to IIS hosting model · Issue #69 · aspnet/Announcements 網頁說明。
備註:未來所有 ASP.NET 5 的重大變更都會公告在 Issues · aspnet/Announcements 這裡。