Android架構之高可用行動網路連線

wingjay發表於2019-03-03

《億級Android架構》小專欄文章列表:

《億級 Android 架構》專欄隨談》

《Android 架構之網路連線與加速》

《Android 架構之長連線技術》

《Android 架構之高可用行動網路連線》

《Android 架構之網路安全演進》

《Android 架構之高效能移動端日誌系統》

《Android 架構之秒級移動配置中心》

正文

讀者好,前面我們在《Android 架構之網路連線與加速》《Android 架構之長連線技術》兩篇文章中,講解了Http短連線、TCP長連線、連線複用與速度優化、資料壓縮等方面的知識點。不過,真實的網路環境是很複雜的,存在各種各樣的因素會導致網路服務不可用,比如DNS劫持、伺服器當機、弱網等。換言之,如果服務都不可用,那上面這些優化也就沒有意義了。

因此,本文主要談一下在真實的網路環境下,存在哪些常見的網路不可用原因,以及大多數公司是如何解決並兜底,從而達到高可用連線這個目標的。

文章會從下面幾方面進行闡述:

  • DNS劫持與可靠IP獲取
    • HttpDNS
    • 內建IP列表+自動測速
  • IP列表的快取更新策略
  • IP列表可用性兜底策略
  • 針對弱網的多IP複合連線測速
  • 自主網路診斷

DNS劫持與可靠IP獲取

我們知道,大多數的網路請求第一步就是DNS過程,經過1-RTT的時間將域名轉化為IP地址,然後再去發起請求。但是,有相關經驗的開發者應該瞭解,DNS過程不僅耗時不穩定(3G下200ms,4G下100ms),而且可能解析失敗,甚至被劫持,將使用者匯入到了錯誤的IP地址。如果攻擊者自己做一個仿冒的網站,劫持你的DNS並將IP轉到這個假網站上,可能會造成很大的使用者資料洩漏和公司品牌損失。

為了解決這個問題,獲得可靠的IP列表,現有大廠會採用下面一些方案:

1. HTTPDNS

比如阿里雲和騰訊雲都推出了自己的HttpDNS服務,在全國多地部署相關的伺服器提供安全解析DNS服務。

基本的原理就是通過發起Http請求到HttpDNS伺服器,獲取某個域名對應的可用IP列表。這個IP列表可以根據使用者當前的地點進行返回,而且預設會進行IP測速,按速度排序。同時,伴隨這IP列表,伺服器還會下發一個快取有效時間 TTL,有了這個時間,客戶端可以放心的將IP列表快取在本地,並在即將過期前及時去更新IP列表,保證每次網路請求都可以使用當前最優的IP地址。

2. 內建IP列表+自動測速

當然,自建HttpDNS服務需要一定規模的機房部署、大量的客戶端測速資料上報、全球IP庫收集等,需要不少的投入。因此,有些公司比如攜程就採用了更加輕量一點的方案:內建IP列表

具體原理如下:

在APK打包時會內建一份IP列表進去。當App啟動時,這些IP的權重相同,此時會隨機從裡面獲取IP來使用。但是這有個問題,對不同地區的使用者而言,最優IP肯定是不同的。比如對於上海的使用者而言,上海區伺服器的IP肯定是最快的,而對於深圳的使用者而言,華南區IP才是最快的。因此,在App執行過程中,我們會通過依次對IP列表逐個進行Ping測速,根據測速結果動態變更IP的權重,然後提供給網路連線使用。

Android架構之高可用行動網路連線

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地址列表。

具體有下面幾種方式:

  1. 定時器監聽HttpDNS返回的TTL過期時間。當IP列表即將過期前,發起請求獲取下一輪的IP列表並進行更新;
  2. 監控網路連線狀態,網路鏈路切換,比如Wi-Fi/3G/4G轉換,如果是Wi-Fi,還可以監控SSID資訊變更(針對不同的Wi-Fi熱點),及時觸發IP列表重新整理;在非同步更新過程中,可以仍然使用舊快取IP提供服務;
  3. 配置中心下發,這種有時會用在伺服器分流,比如某臺伺服器壓力過大,可以通過配置中心繫統下發新的IP列表給客戶端訪問。

另外,IP列表快取應該對不同網路型別、網路標識有對應的一份快取,可以使用網路型別(3G、4G、Wi-Fi等)+網路標識(SSID、ispCode等)作為快取Key,當網路切換時,使用Key去查詢快取。

這些快取可以持久化到多個檔案,以Key作為檔名,同時可以基於當前網路狀態,快取一份IP列表到記憶體供使用,當網路狀態變化,則重新整理記憶體快取。

Android架構之高可用行動網路連線

IP列表可用性兜底策略

通過更新機制,我們可以保證本地IP列表快取動態更新的及時性。那麼,如果HttpDNS伺服器出現故障呢,或者首次開啟App,HttpDNS還沒有完成,或者大面積DNS劫持等,怎麼辦呢?

所以說,除了及時獲取最優IP列表,我們還要考慮,如果獲取不到IP列表,如何進行兜底?保證使用者的網路請求不受影響。

線上上執行中,可以採取下面四組IP兜底策略,按優先順序排列如下:

  • HttpDNS IP:即大廠自建的HttpDNS服務獲取動態IP;
  • DNS IP:即常規Local DNS獲取IP;
  • Auth IP:通過配置下發的動態保底IP列表;
  • Hardcode IP:本地寫死的保底IP列表

前面兩種動態IP不用多說,大家都清楚,這兩者可以動態獲取IP,效果最好。但是,如果發生故障,導致這兩個方案都不可用,比如大面積DNS劫持之類的,這時客戶端必須能夠自動降級到靜態兜底IP,保證網路服務可用。

但這也可能存在一個問題,就是靜態兜底IP對應伺服器訪問量可能會突然暴增,如果峰值太高可能造成更大的危害如雪崩。因此,除了內建靜態兜底IP,還需要為客戶端提供一個可通過配置動態下發兜底IP列表,可以做到負載均衡,將流量分散到不同機器上。而且這些靜態IP貴精不貴多,並且要有高可用的後臺服務保證,作為全域性網路服務的兜底。

針對弱網的多IP複合連線測速

通過上面的幾套方案,可以保證使用者能夠高可用的獲取最優IP列表,提高使用者訪問速度,而且能應對各種複雜的網路狀態。

那麼現在考慮這樣一種情況,上面的IP列表我們能夠正常的獲取,但是,使用者處於弱網狀態下,IP連線成功率很低,怎麼辦呢?

針對弱網一般有兩種方式:

  • 序列連線:先連線第一個IP,直到發生了超時,再去對第二個IP建連;
  • 並行連線:同時對多個IP建立連線,哪個連成功了就用哪個;

這兩種方案的缺點是:序列連線可能需要很長時間的試錯,才能找到可用的IP,而且這裡還取決於如何選擇超時時間,如果超時時間較長,則需要很長時間才能找到可用IP;如果很短,則可能會漏掉一些相對優質的IP,不斷去嘗試新IP,惡性迴圈;而並行連線則會對服務端造成極大的連線負載壓力和一定程度的浪費,對於電量也有一定程度開銷。

因此,這裡我們介紹下Mars裡的複合連線策略作為學習參考:

Android架構之高可用行動網路連線

在弱網狀態下,依次發起對5組IP+Port的連線,10s作為超時時間。當前一個連線發起了4s鍾還未成功,則立即發起下一個連線,以此類推。當其中有一個連線建立成功,則立即停止其他連線。這樣的方式可以兼備序列連線和並行連線的優勢:較快找到可用IP,同時對於伺服器不會造成過大的連線壓力。至於這個超時時間10s,則可以通過上報資料來動態統計,找到一個合理的超時時間。

Android架構之高可用行動網路連線

自主網路診斷

在真實的線上環境我們發現,即使IP和後臺服務均有效,仍有一部分使用者的網路連線會出現失敗。而此時單純從IP地址已經分析不出原因,很有可能是該使用者的網路鏈路上存在問題導致連線失敗。

這時就需要我們主動去探測這個使用者的網路連線並診斷整條連線鏈路。

因此,為了準確瞭解線上網路錯誤的使用者的真實情況,我們會在客戶端裡內建網路診斷策略,通過Ping或者TraceRoute探測使用者手機到伺服器的整條網路鏈路上的情況,並將資料儲存上報,用於分析使用者的真實網路錯誤原因。

Ping大家比較熟悉,目的是為了測試另一臺主機是否可達,向目標主機傳送Echo包並等待回包;而TraceRoute可以獲取資料包在IP網路經過的路由器的IP地址,原理如下:

  • 程式是利用增加存活時間(TTL)值來實現其功能的。每當資料包經過一個路由器,其存活時間就會減1。當其存活時間是0時,主機便取消資料包,併傳送一個ICMP TTL資料包給原資料包的發出者。
  • 程式發出的首3個資料包TTL值是1,之後3個是2,如此類推,它便得到一連串資料包路徑。注意IP不保證每個資料包走的路徑都一樣。

在Android上一般有兩種方式來實現這個診斷:

  1. 通過後臺執行緒執行ping命令的方式,模擬traceroute的過程;
  2. 通過編譯開源網路檢測庫iputilsC程式碼的方式對traceroute進行了套接字傳送ICMP報文模擬。

感興趣的可以參考文末提供的開源專案LDNetDiagnoService,通過診斷可以把日誌上報用於分析,並作出相關的調整和優化。

小結

本文針對如何提高網路連線的高可用性做了講解和分析,線上方案最重要考慮的就是兜底,無論發生何種問題,都要保證網路服務可用。如果使用者連我們的伺服器都連線不上,那可能會帶來非常嚴重的災難;當然,我們也要考慮伺服器負載,不能造成伺服器壓力過大,導致雪崩之類的問題。

有相關疑問歡迎隨時留言。


謝謝。

wingjay


《億級Android架構》小專欄介紹

業務的快速增長離不開穩定可靠的架構。《億級Android架構》小專欄會基於作者實際工作經驗,結合國內大廠如阿里、騰訊、美團等基礎架構現狀,嘗試談談如何設計一套好的架構來支援業務從0到1,甚至到億,希望與大家多多探討。

本專欄主要內容:

  1. 當前大廠有哪些Android架構;
  2. 這些架構能解決什麼問題;
  3. 這些架構的原理是什麼;
  4. 學習這些架構對我們自身的意義。

《億級Android架構》小專欄文章列表:

《億級 Android 架構》專欄隨談》

《Android 架構之網路連線與加速》

《Android 架構之長連線技術》

《Android 架構之高可用行動網路連線》

《Android 架構之網路安全演進》

《Android 架構之高效能移動端日誌系統》


參考文章

《微信終端跨平臺元件 Mars 系列(三)連線超時與IP&Port排序》

《海量之道系列文章之弱聯網優化》

《LDNetDiagnoService_Android》

《美團點評行動網路優化實踐》

相關文章