Kestrel是進程內伺服器,以一個包形式提供,自身不能單獨運行,必須HOST在一個.NET的WEB應用程式中。它內部封裝了對libuv的調用,但不是libuv庫簡單的封裝庫。Kestrel是個精簡的,高效的Http Server ...
1.1. 名詞解釋
內核態: CPU可以訪問記憶體所有數據, 包括外圍設備, 例如硬碟, 網卡. CPU也可以將自己從一個程式切換到另一個程式。
用戶態: 只能受限的訪問記憶體, 且不允許訪問外圍設備. 占用CPU的能力被剝奪, CPU資源可以被其他程式獲取。
1.2. Kestrel基本工作原理
Kestrel是進程內伺服器,以一個包形式提供,自身不能單獨運行,必須HOST在一個.NET的WEB應用程式中。它內部封裝了對libuv的調用,但不是libuv庫簡單的封裝庫。Kestrel是個精簡的,高效的Http Server。
1.2.1. Kestrel的基本架構
Kestrel遵循以下架構原則:
- libuv中使用單線程的事件迴圈模型。
- Kestrel支持多事件迴圈以支持更多的I/O。
- Kestrel僅在libuv的事件迴圈中做I/O工作。
- 所有非I/O工作,包括HTTP解析,請求幀處理等等都在標準的托管線程中進行。
- 更少的系統調用。
對應的架構圖如下:
Libuv
作為I/O底層,屏蔽各系統底層實現差異,為windows下,通過IOCP實現非同步;linux下通過epoll實現非同步。提供一個主程式和主迴圈。
I/O事件隊列
對應Libuv的工作隊列,為了利用現代伺服器的多核處理器,適當的隊列數量將提高更大的I/O吞吐能力。Kestrel預設為每兩個CPU核心設置一個I/O事件隊列,但至少有一個I/O事件隊列。每個隊列對應一個托管線程,該線程不屬於線程池。用戶可以設置隊列個數,通過設置KestrelServerOptions.ThreadCount即可,最多設置16個。
Kestrel線程
事件隊列對應的托管線程,主要控制讀取事件的迴圈機制:每次事件迴圈處理8個事件,然後等待下一次迴圈。
非托管記憶體池
這是在.net運行環境分配的非托管記憶體池,申請的比較大塊的堆記憶體,僅在首次請求或者池剩餘空間不足時分配,後續請求可以復用,不受GC管理。記憶體被分為n片,每片大小是128K,每頁大小4k,管理記憶體頁的數據結構採用鏈表方式。以獲取大塊連續空間的方式增長。遵循讀完後立即釋放的處理原則。
TCP監聽器
這個監聽器不同於套接字的監聽器,而是Libuv的Socket類型的連接事件監聽器。監聽TCP連接事件,對每一個TCP請求產生一個連接對象。連接對象包括暫停,繼續,終止。
連接管理
負責非同步結束連接對象。
HTTP協議模塊
該模塊包括HTTP幀的創建工廠,工廠在監聽器監聽到一個連接時產生一個HTTP幀。一個HTTP幀處理一次HTTP請求和返回。
更為詳細的結構視圖如下:
1.2.2. Kestrel的工作原理
1.2.2.1. 處理Request和Response
按照請求流轉方向會有以下處理過程:
1. 請求進入libuv
將請求事件放入事件隊列,隨後的事件迴圈中,監聽器回調函數執行。
2. 監聽器創建連接
根據請求信息創建一個連接對象,此時Http幀工廠被調用,產生一個Http幀對象;用於讀取Request的SocketInput、用於返回Response的SocketOutput對象被創建,二者會被Http幀使用。
3. 連接管理監控連接
連接管理器跟蹤連接的狀態,收集待關閉連接,然後非同步關閉。
4. Http幀處理
一個Http負責構建Http上下文的Request對象和Response對象。讀取Request數據和返回Response數據都要經過記憶體池。高效的記憶體讀寫和與和Libuv的讀寫事件協調,確保Request數據到達就能讀到記憶體池,到達記憶體池就能及時被讀;Response數據寫入記憶體池就能被套接字及時發出去,體現了Kestreld強大的非同步處理能力。
1.2.2.2. 記憶體池讀寫
讀取記憶體池數據時可讀取後續到達的數據,不需要重新等待事件,此時對應讀取Request數據情形:
寫數據到記憶體池時,libuv連續讀出併發送數據,也不需要重新等待時間,此時對應發送Response數據情形:
1.2.2.3. Libuv線程和托管線程通信
二者的通信機制保證Libuv線程永遠不會被阻塞:比如libuv線程在通知事件時會很小心嘗試獲取隊線程私有鎖,如果成功獲取就這在事件隊列線程上非同步處理,否則這一通信過程線上程池裡重覆執行直到成功,如圖:
1.3. Http.sys基本工作原理
1.3.1. Http.sys基本構成
1. 監聽器
監聽TCP請求,允許埠共用。TCP攜帶的HTTP報文會被Http Parser解析,名稱映射首先會根據url確定對應的web app,然後把請求放入該app的消息隊列中。
2. 消息隊列
Http.sys給每個註冊的web app一個消息隊列。
3. 響應緩存
請求的靜態資源和GET請求會緩存起來一段時間,如果請求url能匹配這直接返回緩存數據。
4. 響應模塊
將數據返回給用戶代理,如果返回的是可以緩存的資源,則會放入響應緩存中。
1.3.2. Http.sys工作原理
下圖表示在ASP.NET Core應用中接受一個http請求到返回數據的過程:
這裡的TCPIP.sys也是windows內核驅動,提供了TCPIP協議棧。
Http.sys的處理如在“基本構成”做所述。
ASP.NET Core應用程式裡面HttpSys模塊代表了Http.sys,它與應用程式代碼交流,交流的載體是HTTP上下文。
1.3.3. 總結
Kestrel伺服器運行在Asp.net core應用程式中,能高效的處理網路請求,且跨平臺。Http.sys運行在內核態中,極大減少了系統調用次數,運行效率很高;自帶生存環境的安全,魯棒性等特點;它也可以作為反向代理,因此它的功能更加強大,主要問題是只能運行在windows下。Kestrel應用在生產環境中需要運行在代理伺服器後面,以獲取安全性,負載均衡等能力。
功能 | Http.sys | Kerstrel |
---|---|---|
平臺支持 | Windows | Windows/Linux/Mac |
靜態文件 | Yes | Yes |
HTTP訪問日誌 | Yes | No |
埠共用/多應用程式 | Yes | No |
SSL證書 | Yes | Internal* |
Windows 授權 | Yes | No |
過濾請求&限制 | Yes | No |
IP&功能變數名稱約束 | Yes | No |
HTTP重定向規則 | Yes | No |
WebSocket 協議 | Yes | Middleware |
緩存Response | Yes | No |
壓縮 | Yes | Yes |
FTP伺服器 | Yes | No |
運行態 | 內核態 | 用戶態 |
* Internal:https通信僅僅工作在反向代理伺服器後面與ASP.NET程式之間,如果要想外暴露https服務這需要用到反向代理,比如IIS,nginx,apached。
參考文章
http://www.cnblogs.com/yxmx/articles/1652128.html
http://www.cnblogs.com/arbin98/archive/2010/09/03/1816847.html
https://stackify.com/kestrel-web-server-asp-net-core-kestrel-vs-iis/