Comet, 下一代反向AJAX(即服務器推送技術- Server-side push)

理解 Comet

您可能已經聽說過 Comet,因爲它最近受到了一定的關注。Comet 有時也稱反向 Ajax 或服務器端推技術(server-side push)。其思想很簡單:將數據直接從服務器推到瀏覽器,而不必等到瀏覽器請求數據。聽起來簡單,但是如果熟悉 Web 應用程序,尤其是 HTTP 協議,那麼您就會知道,這絕不簡單。實現 Comet 風格的 Web 應用程序,同時保證在瀏覽器和服務器上的可伸縮性,這只是在最近幾年才成爲可能。目前一些主流網站都有類似的原理,例如:webQQ、開心網、白社會等等,它們中消息動態都是採用類似的技術,也許具體實現方式不一樣;

使用 Comet 的動機

HTTP 協議的成功毋庸置疑。它是 Internet 上大部分信息交換的基礎。然而,它也有一些侷限性。特別是,它是無狀態、單向的協議。請求被髮送到 Web 服務器,服務器處理請求併發回一個響應 — 僅此而已。請求必須由客戶機發出,而服務器則只能在對請求的響應中發送數據。這至少會影響很多類型的 Web 應用程序的實用性。典型的例子就是聊天程序。另外還有一些例子,例如比賽的比分、股票行情或電子郵件程序。

HTTP 的這些侷限性也是它取得一定成功的原因。請求/響應週期使它成爲了經典的模型,即每個連接使用一個線程。只要能夠快速爲請求提供服務,這種方法就有巨大的可伸縮性。每秒鐘可以處理大量的請求,只需使用少量的服務器就可以處理很大數量的用戶。對於很多經典的 Web 應用程序,例如內容管理系統、搜索應用程序和電子商務站點等等而言,這非常適合。在以上任何一種 Web 應用程序中,服務器提供用戶請求的數據,然後關閉連接,並釋放那個線程,使之可以爲其他請求服務。如果提供初始數據之後仍可能存在交互,那麼將連接保持爲打開狀態,因此線程就不能釋放出來,服務器也就不能爲很多用戶服務。

但是,如果想在對請求做出響應併發送初始數據之後,仍然保持與用戶的交互呢?在 Web 早期,這一點常使用 meta 刷新實現。這將自動指示瀏覽器在指定秒數之後重新裝載頁面,從而支持簡陋的輪詢(polling)。這不僅是一種糟糕的用戶體驗,而且通常效率非常低下。如果沒有新的數據要顯示在頁面上呢?這時不得不重新呈現同樣的頁面。如果對頁面的更改很少,並且頁面的大部分沒有變化呢?同樣,不管是否有必要,都得重新請求和獲取頁面上的一切內容。

Ajax 的發明和流行改變了上述狀況。現在,服務器可以異步通信,因此不必重新請求整個頁面。現在可以進行增量式的更新。只需使用 XMLHttpRequest 輪詢服務器。這項技術通常被稱作 Comet。這項技術存在一些變體,每種變體具有不同的性能和可伸縮性。我們來看看這些不同風格的 Comet。

Comet 風格

Ajax 的出現使 Comet 成爲可能。HTTP 的單向性質可以有效地加以規避。實際上有一些不同的方法可以繞過這一點。您可能已經猜到,支持 Comet 的最容易的方式是輪詢(poll)。使用 XMLHttpRequest 向服務器發出調用,返回後,等待一段固定的時間(通常使用 JavaScript 的 setTimeout 函數),然後再次調用。這是一項非常常見的技術。例如,大多數 webmail 應用程序就是通過這種技術在電子郵件到達時顯示電子郵件的。

這項技術有優點也有缺點。在這種情況下,您期望快速返回響應,就像任何其他 Ajax 請求一樣。在請求之間必須有一段暫停。否則,連續不斷的請求會沖垮服務器,並且這種情況下顯然不具有可伸縮性。這段暫停使應用程序產生一個延時。暫停的時間越長,服務器上的新數據就需要越多的時間才能到達客戶機。如果縮短暫停時間,又將重新面臨沖垮服務器的風險。但是另一方面,這顯然是最簡單的實現 Comet 的方式。

現在應該指出,很多人認爲輪詢並不屬於 Comet。相反,他們認爲 Comet 是對輪詢的侷限性的一個解決方案。最常見的 “真正的” Comet 技術是輪詢的一種變體,即長輪詢(long polling)。輪詢與長輪詢之間的主要區別在於服務器花多長的時間作出響應。長輪詢通常將連接保持一段較長的時間 — 通常是數秒鐘,但是也可能是一分鐘甚至更長。當服務器上發生某個事件時,響應被髮送並隨即關閉,輪詢立即重新開始。

長輪詢相對於一般輪詢的優點在於,數據一旦可用,便立即從服務器發送到客戶機。請求可能等待較長的時間,期間沒有任何數據返回,但是一旦有了新的數據,它將立即被髮送到客戶機。因此沒有延時。如果您使用過基於 Web 的聊天程序,或者聲稱 “實時” 的任何程序,那麼它很可能就是使用了這種技術。

長輪詢有一種變體,這是第三種風格的 Comet。這通常被稱爲流(streaming)。按照這種風格,服務器將數據推回客戶機,但是不關閉連接。連接將一直保持開啓,直到過期,並導致重新發出請求。XMLHttpRequest 規範表明,可以檢查 readyState 的值是否爲 3 或 Receiving(而不是 4 或 Loaded),並獲取正從服務器 “流出” 的數據。和長輪詢一樣,這種方式也沒有延時。當服務器上的數據就緒時,該數據被髮送到客戶機。這種方式的另一個優點是可以大大減少發送到服務器的請求,從而避免了與設置服務器連接相關的開銷和延時。不幸的是,XMLHttpRequest 在不同的瀏覽器中有很多不同的實現。這項技術只能在較新版本的 Mozilla Firefox 中可靠地使用。對於 Internet Explorer 或 Safari,仍需使用長輪詢。

至此,您可能會想,長輪詢和流都有一個很大的問題。請求需要在服務器上存在一段較長的時間。這打破了每個請求使用一個線程的模型,因爲用於一個請求的線程一直沒有被釋放。更糟糕的是,除非要發回數據,否則該線程一直處於空閒狀態。這顯然不具有可伸縮性。幸運的是,現代 Java Web 服務器有很多方式可以解決這個問題。搞JAVA開發的程序員,相對而言比較幸運,PHP目前還不是很多的;我今天花了一天的時間,找了各方面的資料,共享一個國外的author寫的demo附件;有興趣的朋友可以研究一下,研究出更好的“服務器推”方案;


轉載自:http://bbs.phpchina.com/thread-166038-1-1.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章