Ajax and Blocking IO - Server side performance tuning memo
我在 Ajax and Blocking IO - To Resolve Polling Anti-pattern 中闡述了 Ajax 設計時,如何運用 Blocking IO 模型解決輪詢反模式(polling anti-pattern);這整個模型,又稱之為「需求把持模型(Request handle model)」。結語時,我提到我們在實際應用中,需要在伺服端規劃另一種行程間通訊機制(IPC)。這就衍生了一個問題,即伺服端的需求把持模型與效能問題。
首先看下圖,一個最基本的 HTTP 需求把持模型,實際上牽動了三個行程以及兩段資料流。圖中的個體名稱,係按我在 Ajax and Blocking IO - To Resolve Polling Anti-pattern 的用語。
我們解決 Ajax 輪詢反模式的原理,就是在 Client 到 Getter 這一段資料流上運用 Blocking IO 模型。讓伺服端的 Getter 先把持住 TCP I/O設備,使此資料流兩端的 Client 與 Getter 進入擱置狀態。並透過我們規劃的 IPC 機制,讓 Poster 喚醒 Getter 接收資料。
在 Getter 與 Poster 之間的資料流,我們有很大的彈性選擇 IPC 機制。最簡單的方式就是採用 Blocking IO 模型,例如 Pipe 或 Socket 。但是這種做法在效能上有個很明顯的缺陷,那就是每一個 HTTP 需求,都帶來兩倍的 Blocking IO 維護成本; Client 到 Getter 一條資料流維護成本,Getter 到 Poster 一條資料流維護成本。就算資料流兩端的行程都無動作,僅是維持資料流的持續狀態,系統仍然會消耗一定的成本。如果有一千個使用者,透過瀏覽器等待伺服端的狀態異動,那就要維護2000條資料流。
為了減輕資料流的維護成本,我們在實務上往往選擇 Non-blocking 模型處理 Getter 與 Poster 之間的資料流。在 Non-blocking 模型中,又以透過 Poster 主動觸發 Getter 設定的事件處理方法的設計模式最常見,又稱為事件模型(Event model)。
目前有兩種實作品可以協助我們實現 Getter 與 Poster 之間的事件模型。我在 Ajax and Blocking IO - To Resolve Polling Anti-pattern 提到的 D-Bus 是一種。另一種則是 Cometd ,聽說 Java Serlvet3 會把 Cometd 列入規範。
關於 D-Bus 的部份,我改日再詳談。而 Cometd ,則可以閱讀 High-performance Ajax with Tomcat Advanced I/O。Jetty Cometd 的實現方式又有些微不同。我個人對 Cometd 興趣不高,不會多談。