《億級Android架構》小專欄文章列表:html
《Android 架構之網絡鏈接與加速》github
《Android 架構之秒級移動配置中心》markdown
讀者好,前面咱們在《Android 架構之網絡鏈接與加速》和《Android 架構之長鏈接技術》兩篇文章中,講解了Http短鏈接、TCP長鏈接、鏈接複用與速度優化、數據壓縮
等方面的知識點。不過,真實的網絡環境是很複雜的,存在各類各樣的因素會致使網絡服務不可用,好比DNS劫持、服務器宕機、弱網等。換言之,若是服務都不可用,那上面這些優化也就沒有意義了。網絡
所以,本文主要談一下在真實的網絡環境下,存在哪些常見的網絡不可用緣由,以及大多數公司是如何解決並兜底,從而達到高可用鏈接
這個目標的。架構
文章會從下面幾方面進行闡述:
咱們知道,大多數的網絡請求第一步就是DNS過程,通過1-RTT的時間將域名轉化爲IP地址,而後再去發起請求。可是,有相關經驗的開發者應該瞭解,DNS過程不只耗時不穩定(3G下200ms,4G下100ms),並且可能解析失敗,甚至被劫持,將用戶導入到了錯誤的IP地址。若是攻擊者本身作一個仿冒的網站,劫持你的DNS並將IP轉到這個假網站上,可能會形成很大的用戶數據泄漏和公司品牌損失。
爲了解決這個問題,得到可靠的IP列表,現有大廠會採用下面一些方案:
好比阿里雲和騰訊雲都推出了本身的HttpDNS服務,在全國多地部署相關的服務器提供安全解析DNS服務。
基本的原理就是經過發起Http請求到HttpDNS服務器,獲取某個域名對應的可用IP列表。這個IP列表能夠根據用戶當前的地點進行返回,並且默認會進行IP測速,按速度排序。同時,伴隨這IP列表,服務器還會下發一個緩存有效時間 TTL,有了這個時間,客戶端能夠放心的將IP列表緩存在本地,並在即將過時前及時去更新IP列表,保證每次網絡請求均可以使用當前最優的IP地址。
固然,自建HttpDNS服務須要必定規模的機房部署、大量的客戶端測速數據上報、全球IP庫收集等,須要很多的投入。所以,有些公司好比攜程就採用了更加輕量一點的方案:內置IP列表
。
具體原理以下:
在APK打包時會內置一份IP列表進去。當App啓動時,這些IP的權重相同,此時會隨機從裏面獲取IP來使用。可是這有個問題,對不一樣地區的用戶而言,最優IP確定是不一樣的。好比對於上海的用戶而言,上海區服務器的IP確定是最快的,而對於深圳的用戶而言,華南區IP纔是最快的。所以,在App運行過程當中,咱們會經過依次對IP列表逐個進行Ping測速,根據測速結果動態變動IP的權重,而後提供給網絡鏈接使用。
經過HttpDNS或內置IP列表
的方案,咱們能夠爲網絡層提供一份相對可靠的IP地址做爲緩存,每次須要發起請求時,直接從緩存裏讀取這份IP列表便可創建IP直連。
那新的問題來了,移動網絡是在不斷變化的。最多見的場景,好比咱們從Wi-Fi切換到了4G,獲取進入電梯後從4G降級成3G,或者咱們從A Wi-Fi換到了B Wi-Fi,這都意味着咱們的網絡鏈路變動了。那麼,以前緩存的IP列表是否仍然可用,或者仍然最優呢?
顯然並不必定,好比從Wi-Fi切到了移動4G,背後整條網絡鏈路都不一樣了,以前的IP列表頗有可能不是最優的了,極端狀況下可能某些IP地址也不可用了。所以,咱們須要最好IP列表的及時更新,保證不管網絡如何切換,咱們都能使用最優的IP地址列表。
具體有下面幾種方式:
TTL過時時間
。當IP列表即將過時前,發起請求獲取下一輪的IP列表並進行更新;另外,IP列表緩存應該對不一樣網絡類型、網絡標識有對應的一份緩存,可使用網絡類型(3G、4G、Wi-Fi等)+網絡標識(SSID、ispCode等)
做爲緩存Key
,當網絡切換時,使用Key去查詢緩存。
這些緩存能夠持久化到多個文件,以Key做爲文件名,同時能夠基於當前網絡狀態,緩存一份IP列表到內存供使用,當網絡狀態變化,則刷新內存緩存。
經過更新機制,咱們能夠保證本地IP列表緩存動態更新的及時性。那麼,若是HttpDNS服務器出現故障呢,或者首次打開App,HttpDNS尚未完成,或者大面積DNS劫持等,怎麼辦呢?
因此說,除了及時獲取最優IP列表,咱們還要考慮,若是獲取不到IP列表,如何進行兜底?保證用戶的網絡請求不受影響。
在線上運行中,能夠採起下面四組IP兜底策略,按優先級排列以下:
前面兩種動態IP不用多說,你們都清楚,這二者能夠動態獲取IP,效果最好。可是,若是發生故障,致使這兩個方案都不可用,好比大面積DNS劫持之類的,這時客戶端必須可以自動降級到靜態兜底IP
,保證網絡服務可用。
但這也可能存在一個問題,就是靜態兜底IP
對應服務器訪問量可能會忽然暴增,若是峯值過高可能形成更大的危害如雪崩
。所以,除了內置靜態兜底IP,還須要爲客戶端提供一個可經過配置動態下發
的兜底IP列表
,能夠作到負載均衡,將流量分散到不一樣機器上。並且這些靜態IP貴精不貴多,而且要有高可用的後臺服務保證,做爲全局網絡服務的兜底。
經過上面的幾套方案,能夠保證用戶可以高可用的獲取最優IP列表
,提升用戶訪問速度,並且能應對各類複雜的網絡狀態。
那麼如今考慮這樣一種狀況,上面的IP列表咱們可以正常的獲取,可是,用戶處於弱網狀態下,IP鏈接成功率很低,怎麼辦呢?
針對弱網通常有兩種方式:
這兩種方案的缺點是:串行鏈接可能須要很長時間的試錯,才能找到可用的IP,並且這裏還取決於如何選擇超時時間,若是超時時間較長,則須要很長時間才能找到可用IP;若是很短,則可能會漏掉一些相對優質的IP,不斷去嘗試新IP,惡性循環;而並行鏈接則會對服務端形成極大的鏈接負載壓力和必定程度的浪費,對於電量也有必定程度開銷。
所以,這裏咱們介紹下Mars裏的複合鏈接策略
做爲學習參考:
在弱網狀態下,依次發起對5組IP+Port的鏈接,10s做爲超時時間。當前一個鏈接發起了4s鍾還未成功,則當即發起下一個鏈接,以此類推。當其中有一個鏈接創建成功,則當即中止其餘鏈接。這樣的方式能夠兼備串行鏈接和並行鏈接的優點:較快找到可用IP,同時對於服務器不會形成過大的鏈接壓力。至於這個超時時間10s,則能夠經過上報數據來動態統計,找到一個合理的超時時間。
在真實的線上環境咱們發現,即便IP和後臺服務均有效,仍有一部分用戶的網絡鏈接會出現失敗。而此時單純從IP地址已經分析不出緣由,頗有多是該用戶的網絡鏈路上存在問題致使鏈接失敗。
這時就須要咱們主動去探測這個用戶的網絡鏈接並診斷整條鏈接鏈路。
所以,爲了準確瞭解線上網絡錯誤的用戶的真實狀況,咱們會在客戶端裏內置網絡診斷策略,經過Ping
或者TraceRoute
探測用戶手機到服務器的整條網絡鏈路上的狀況,並將數據存儲上報,用於分析用戶的真實網絡錯誤緣由。
Ping你們比較熟悉,目的是爲了測試另外一臺主機是否可達,向目標主機發送Echo包並等待回包;而TraceRoute能夠獲取數據包在IP網絡通過的路由器的IP地址,原理以下:
在Android上通常有兩種方式來實現這個診斷:
iputils
C代碼的方式對traceroute進行了套接字發送ICMP報文模擬。感興趣的能夠參考文末提供的開源項目LDNetDiagnoService
,經過診斷能夠把日誌上報用於分析,並做出相關的調整和優化。
本文針對如何提升網絡鏈接的高可用性作了講解和分析,線上方案最重要考慮的就是兜底,不管發生何種問題,都要保證網絡服務可用。若是用戶連咱們的服務器都鏈接不上,那可能會帶來很是嚴重的災難;固然,咱們也要考慮服務器負載,不能形成服務器壓力過大,致使雪崩之類的問題。
有相關疑問歡迎隨時留言。
謝謝。
wingjay
業務的快速增加離不開穩定可靠的架構。《億級Android架構》小專欄會基於做者實際工做經驗,結合國內大廠如阿里、騰訊、美團等基礎架構現狀,嘗試談談如何設計一套好的架構來支持業務從0到1,甚至到億,但願與你們多多探討。
本專欄主要內容:
《億級Android架構》小專欄文章列表: