1. 程式人生 > >app中的長連線與實現方式

app中的長連線與實現方式

http2.0的好處不僅僅是multiplexing,請求壓縮,優先順序控制,server push等等都是亮點。  解決連線無法複用

http1.0協議頭裡可以設定Connection:Keep-Alive。在header裡設定Keep-Alive可以在一定時間內複用連 接,具體複用時間的長短可以由伺服器控制,一般在15s左右。到http1.1之後Connection的預設值就是Keep-Alive,如果要關閉連 接複用需要顯式的設定Connection:Close。一段時間內的連線複用對PC端瀏覽器的體驗幫助很大,因為大部分的請求在集中在一小段時間以內。 但對移動app來說,成效不大,app端的請求比較分散且時間跨度相對較大。所以移動端app一般會從應用層尋求其它解決方案,長連線方案或者偽長連線方 案:

方案一:基於tcp的長連結

現在越來越多的移動端app都會建立一條自己的長連結通道,通道的實現是基於tcp協議。基於tcp的socket程式設計技術難度相對複雜很多,而且 需要自己制定協議,但帶來的回報也很大。資訊的上報和推送變得更及時,在請求量爆發的時間點還能減輕伺服器壓力(http短連線模式會頻繁的建立和銷燬連 接)。不止是IM app有這樣的通道,像淘寶這類電商類app都有自己的專屬長連線通道了。現在業界也有不少成熟的方案可供選擇了,google的protobuf就是其 中之一。

方案二:http long-polling

long-polling可以用下圖表示:

[圖2]

客戶端在初始狀態就會發送一個polling請求到伺服器,伺服器並不會馬上返回業務資料,而是等待有新的業務資料產生的時候再返回。所以連線會一 直被保持,一旦結束馬上又會發起一個新的polling請求,如此反覆,所以一直會有一個連線被保持。伺服器有新的內容產生的時候,並不需要等待客戶端建 立一個新的連線。做法雖然簡單,但有些難題需要攻克才能實現穩定可靠的業務框架:

  • 和傳統的http短連結相比,長連線會在使用者增長的時候極大的增加伺服器壓力
  • 移動端網路環境複雜,像wifi和4g的網路切換,進電梯導致網路臨時斷掉等,這些場景都需要考慮怎麼重建健康的連線通道。
  • 這種polling的方式穩定性並不好,需要做好資料可靠性的保證,比如重發和ack機制。
  • polling的response有可能會被中間代理cache住,要處理好業務資料的過期機制。
long-polling方式還有一些缺點是無法克服的,比如每次新的請求都會帶上重複的header資訊,還有資料通道是單向的,主動權掌握在server這邊,客戶端有新的業務請求的時候無法及時傳送。

方案三:http streaming

http streaming流程大致如下:

同long-polling不同的是,server並不會結束初始的streaming請求,而是持續的通過這個通道返回最新的業務資料。顯然這個 資料通道也是單向的。streaming是通過在server response的頭部裡增加”Transfer Encoding: chunked”來告訴客戶端後續還會有新的資料到來。除了和long-polling相同的難點之外,streaming還有幾個缺陷:
  • 有些代理伺服器會等待伺服器的response結束之後才會將結果推送到請求客戶端。對於streaming這種永遠不會結束的方式來說,客戶端就會一直處於等待response的過程中。
  • 業務資料無法按照請求來做分割,所以客戶端沒收到一塊資料都需要自己做協議解析,也就是說要做自己的協議定製。
streaming不會產生重複的header資料。

方案四:web socket

WebSocket和傳統的tcp socket連線相似,也是基於tcp協議,提供雙向的資料通道。WebSocket優勢在於提供了message的概念,比基於位元組流的tcp socket使用更簡單,同時又提供了傳統的http所缺少的長連線功能。不過WebSocket相對較新,2010年才起草,並不是所有的瀏覽器都提供 了支援。各大瀏覽器廠商最新的版本都提供了支援。

2. 開拓者SPDY

http1.0和1.1雖然存在這麼多問題,業界也想出了各種優化的手段,但這些方法手段都是在嘗試繞開協議本身的缺陷,都有種隔靴搔癢,治標不治 本的感覺。直到2012年google如一聲驚雷提出了SPDY的方案,大家才開始從正面看待和解決老版本http協議本身的問題,這也直接加速了 http2.0的誕生。實際上,http2.0是以SPDY為原型進行討論和標準化的。為了給http2.0讓路,google已決定在2016年不再繼 續支援SPDY開發,但在http2.0出生之前,SPDY已經有了相當規模的應用,作為一個過渡方案恐怕在還將一段時間內繼續存在。現在不少app客戶 端和server都已經使用了SPDY來提升體驗,http2.0在老的裝置和系統上還無法使用(iOS系統只有在iOS9+上才支援),所以可以預見未 來幾年spdy將和http2.0共同服務的情況。

2.1 SPDY的目標

SPDY的目標在一開始就是瞄準http1.x的痛點,即延遲和安全性。我們上面通篇都在討論延遲,至於安全性,由於http是明文協議,其安全性 也一直被業界詬病,不過這是另一個大的話題。如果以降低延遲為目標,應用層的http和傳輸層的tcp都是都有調整的空間,不過tcp作為更底層協議存在 已達數十年之久,其實現已深植全球的網路基礎設施當中,如果要動必然傷經動骨,業界響應度必然不高,所以SPDY的手術刀對準的是http。

  • 降低延遲,客戶端的單連線單請求,server的FIFO響應佇列都是延遲的大頭。
  • http最初設計都是客戶端發起請求,然後server響應,server無法主動push內容到客戶端。
  • 壓縮http header,http1.x的header越來越膨脹,cookie和user agent很容易讓header的size增至1kb大小,甚至更多。而且由於http的無狀態特性,header必須每次request都重複攜帶,很浪費流量。

為了增加業界響應的可能性,聰明的google一開始就避開了從傳輸層動手,而且打算利用開源社群的力量以提高擴散的力度,對於協議使用者來說,也 只需要在請求的header裡設定user agent,然後在server端做好支援即可,極大的降低了部署的難度。SPDY的設計如下:

SPDY位於HTTP之下,TCP和SSL之上,這樣可以輕鬆相容老版本的HTTP協議(將http1.x的內容封裝成一種新的frame格式),同時可以使用已有的SSL功能。SPDY的功能可以分為基礎功能和高階功能兩部分,基礎功能預設啟用,高階功能需要手動啟用。

SPDY基礎功能

  • 多路複用(multiplexing)。多路複用通過多個請求stream共享一個tcp連線的方式,解決了http1.x holb(head of line blocking)的問題,降低了延遲同時提高了頻寬的利用率。
  • 請求優先順序(request prioritization)。多路複用帶來一個新的問題是,在連線共享的基礎之上有可能會導致關鍵請求被阻塞。SPDY允許給每個request設定 優先順序,這樣重要的請求就會優先得到響應。比如瀏覽器載入首頁,首頁的html內容應該優先展示,之後才是各種靜態資原始檔,指令碼檔案等載入,這樣可以保 證使用者能第一時間看到網頁內容。
  • header壓縮。前面提到過幾次http1.x的header很多時候都是重複多餘的。選擇合適的壓縮演算法可以減小包的大小和數量。SPDY對header的壓縮率可以達到80%以上,低頻寬環境下效果很大。

SPDY高階功能

  • server推送(server push)。http1.x只能由客戶端發起請求,然後伺服器被動的傳送response。開啟server push之後,server通過X-Associated-Content header(X-開頭的header都屬於非標準的,自定義header)告知客戶端會有新的內容推送過來。在使用者第一次開啟網站首頁的時 候,server將資源主動推送過來可以極大的提升使用者體驗。
  • server暗示(server hint)。和server push不同的是,server hint並不會主動推送內容,只是告訴有新的內容產生,內容的下載還是需要客戶端主動發起請求。server hint通過X-Subresources header來通知,一般應用場景是客戶端需要先查詢server狀態,然後再下載資源,可以節約一次查詢請求。

3. 救世主HTTP2.0

SPDY的誕生和表現說明了兩件事情:一是在現有網際網路設施基礎和http協議廣泛使用的前提下,是可以通過修改協議層來優化http1.x的。二 是針對http1.x的修改確實效果明顯而且業界反饋很好。正是這兩點讓IETF(Internet Enginerring Task Force)開始正式考慮制定HTTP2.0的計劃,最後決定以SPDY/3為藍圖起草HTTP2.0,SPDY的部分設計人員也被邀請參與了 HTTP2.0的設計

3.1 HTTP2.0需要考慮的問題

HTTP2.0與SPDY的起點不同,SPDY可以說是google的“玩具”,最早出現在自家的chrome瀏覽器和server上,好不好玩以 及別人會不會跟著一起玩對google來說無關痛癢。但HTTP2.0作為業界標準還沒出生就是眾人矚目的焦點,一開始如果有什麼瑕疵或者不相容的問題影 響可能又是數十年之久,所以考慮的問題和角度要非常之廣。我們來看下HTTP2.0一些重要的設計前提:

  • 客戶端向server傳送request這種基本模型不會變。
  • 老的scheme不會變,使用http://和https://的服務和應用不會要做任何更改,不會有http2://。
  • 使用http1.x的客戶端和伺服器可以無縫的通過代理方式轉接到http2.0上。
  • 不識別http2.0的代理伺服器可以將請求降級到http1.x。
因為客戶端和server之間在確立使用http1.x還是http2.0之前,必須要要確認對方是否支援http2.0,所以這裡必須要有個協商的過 程。最簡單的協商也要有一問一答,客戶端問server答,即使這種最簡單的方式也多了一個RTT的延遲,我們之所以要修改http1.x就是為了降低延 遲,顯然這個RTT我們是無法接受的。google制定SPDY的時候也遇到了這個問題,他們的辦法是強制SPDY走https,在SSL層完成這個協商 過程。ssl層的協商在http協議通訊之前,所以是最適合的載體。google為此做了一個tls的拓展,叫NPN(Next Protocol Negotiation),從名字上也可以看出,這個拓展主要目的就是為了協商下一個要使用的協議。HTTP2.0雖然也採用了相同的方式,不過 HTTP2.0經過激烈的討論,最終還是沒有強制HTTP2.0要走ssl層,大部分瀏覽器廠商(除了IE)卻只實現了基於https的2.0協議。 HTTP2.0沒有使用NPN,而是另一個tls的拓展叫ALPN(Application Layer Protocol Negotiation)。SPDY也打算從NPN遷移到ALPN了。

各瀏覽器(除了IE)之所以只實現了基於SSL的HTTP2.0,另一個原因是走SSL請求的成功率會更高,被SSL封裝的request不會被監 聽和修改,這樣網路中間的網路裝置就無法基於http1.x的認知去幹涉修改request,http2.0的request如果被意外的修改,請求的成 功率自然會下降。

HTTP2.0協議沒有強制使用SSL是因為聽到了很多的反對聲音,畢竟https和http相比,在不優化的前提下效能差了不少,要把https 優化到幾乎不增加延遲的程度又需要花費不少力氣。IETF面對這種兩難的處境做了妥協,但大部分瀏覽器廠商(除了IE)並不買帳,他們只認 https2.0。對於app開發者來說,他們可以堅持使用沒有ssl的http2.0,不過要承擔一個多餘的RTT延遲和請求可能被破壞的代價。

4.2 Android下http現狀

android和iOS情況類似,http2.0只能在新系統下支援,spdy作為過渡方案仍然有存在的必要。

對於使用webview的app來說,需要基於chrome核心的webview才能支援spdy和http2.0,而android系統的webview是從android4.4(KitKat)才改成基於chrome核心的。

對於使用native api呼叫的http請求來說,okhttp是同時支援spdy和http2.0的可行方案。如果使用ALPN,okhttp要求android系統 5.0+(實際上,android4.4上就有了ALPN的實現,不過有bug,知道5.0才正式修復),如果使用NPN,可以從android4.0+ 開始支援,不過NPN也是屬於將要被淘汰的協議。