【前五篇】系列文章傳送門:
- 網絡協議 12 - HTTP 協議:常用而不簡單
- 網絡協議 13 - HTTPS 協議:加密路上無盡頭
- 網絡協議 14 - 流媒體協議:要說愛你不容易
- 網絡協議 15 - P2P 協議:小種子大學問
- 網絡協議 16 - DNS 協議:網絡世界的地址簿
全球統一的 DNS 是很權威,但是我們都知道“適合自己的,才是最好的”。很多時候,標准統一化的 DNS 並不能滿足我們定制的需求,這個時候就需要 HTTPDNS 了。
上一節我們知道了 DNS 可以根據名稱查地址,也可以針對多個地址做負載均衡。然而,我們信任的地址簿也會存在指錯路的情況。明明離你 500 米就有個吃飯的地方,非要把你推薦到 5 公里外。為什么會出現這樣的情況呢?
還記得嗎?由我們發出請求解析 DNS 的時候,首先會連接到運營商本地的 DNS 服務器,由這個服務器幫我們去整棵 “DNS 樹” 上進行解析,然后將解析的結果返回給客戶端。但是本地的 DNS 服務器,作為一個本地導游,往往會有自己的“小心思”。
傳統 DNS 存在的問題
1)域名緩存問題
它可以在本地做一個緩存。也就是說,不是每一個請求,它都會去訪問權威 DNS 服務器,而是把訪問過一次的結果緩存到本地,當其他人來問的時候,直接返回緩存的內容。
這就相當於導游去過一個飯店,自己記住了地址,當有一個游客問的時候,他就憑記憶回答了,不用再去查地址簿。這樣會存在一個問題,游客問的那個飯店如果已經搬走了,然而因為導游沒有刷新“記憶緩存”,導致游客白跑一趟。
另外,有的運營商會把一些靜態頁面,緩存到本運營商的服務器內,這樣用戶請求的時候,就不用跨運營商進行訪問,既加快了速度,也減少了運營商直接流量計算的成本。也就是說,在域名解析的時候,不會將用戶導向真正的網站,而是指向這個緩存的服務器。
緩存的問題,很多情況下是看不出問題的,但是當頁面更新,用戶訪問到老的頁面,問題就出來了。
再就是本地的緩存,往往使得全局負載均衡失敗。上次進行緩存的時候,緩存中的地址不一定是客戶此次訪問離客戶最近的地方,如果把這個地址返回給客戶,就會讓客戶繞遠路了。
2)域名轉發問題
還記得我們域名解析的過程嗎?捂臉是本地域名解析,還是去權威 DNS 服務器中查找,都可以認為是一種外包形式。有了請求,直接轉發給其他服務去解析。如果轉發的是權威 DNS 服務器還好說,但是如果因為“偷懶”轉發給了鄰居服務器去解析,就容易產生跨運營商訪問的問題。
這就好像,如果 A 運營商的客戶,訪問自己運營商的 DNS 服務器,A 運營商去權威 DNS 服務器查詢的話,會查到客戶的 A 運營商的,返回一個部署在 A 運營商的網站地址,這樣針對相同運營商的訪問,速度就會快很多。
但是如果 A 運營商偷懶,沒有轉發給權威 DNS ,而是轉發給了 B 運營商,讓 B 運營商再去權威 DNS 服務器查詢,這樣就會讓權威服務器誤認為客戶是 B 運營商的,返回一個 B 運營商的服務器地址,導致客戶每次都要跨運營商訪問,訪問速度就會慢下來。
3)出口 NAT 問題
前面了解網關的時候,我們知道,出口的時候,很多機房都會配置 NAT,也就是網絡地址轉換,使得從這個網關出去的包,都換成新的 IP 地址。
這種情況下,權威 DNS 服務器就沒辦法通過請求 IP 來判斷客戶到底是哪個運營商的,很有可能誤判運營商,導致跨運營商訪問。
4)域名更新問題
本地 DNS 服務器是由不同地區、不同運營商獨立部署的。對域名解析緩存的處理上,實現策略也有區別。有的會偷懶,忽略域名解析結構的 TTL 時間限制,在權威 DNS 服務器解析變更的時候,解析結果在全網生效的周期非常漫長。但是有的場景,在 DNS 的切換中,對生效時間要求比較高。
例如雙機房部署的是,跨機房的負載均衡和容災多使用 DNS 來做。當一個機房出問題之后,需要修改權威 DNS,將域名指向新的 IP 地址。但是如果更新太慢,很多用戶都會訪問一次。
5)解析延遲問題
從 DNS 的查詢過程來看,DNS 的查詢過程需要遞歸遍歷多個 DNS 服務器,才能獲得最終的解析結果,這帶來一定的延時,甚至會解析超時。
上面總結了 DNS 的五個問題。問題有了,總得有解決辦法,就像因為 HTTP 的安全問題,才火了 HTTPS 協議一樣,對應的,也有 HTTPDNS 來解決上述 DNS 出現的問題。
HTTPDNS
什么是 HTTPDNS ?其實很簡單:
HTTPDNS 是基於 HTTP 協議和域名解析的流量調度解決方案。它不走傳統的 DNS 解析,而是自己搭建基於 HTTP 協議的 DNS 服務器集群,分布在多個地點和多個運營商。當客戶端需要 DNS 解析的時候,直接通過 HTTP 請求這個服務器集群,得到就近的地址。
這就相當於每家基於 HTTP 協議,自己實現自己的域名解析,做一個自己的地址簿,而不使用統一的地址簿。但是我們知道,域名解析默認都是走 DNS 的,因而使用 HTTPDNS 需要繞過默認的 DNS 路徑,也就不能使用默認的客戶端。**使用 HTTPDNS 的,往往是手機應用,需要在手機端嵌入支持 HTTPDNS 的客戶端 SDK。
HTTPDNS 的工作流程
接下來,我們一起來認識下 HTTPDNS 的工作流程。
HTTPDNS 會在客戶端的 SDK 里動態請求服務端,獲取 HTTPDNS 服務器的 IP 列表,緩存在本地。隨着不斷地解析域名,SDK 也會在本地緩存 DNS 域名解析的結果。
當手機應用要訪問一個地址的時候,首先看是否有本地的緩存,如果有直接返回。這個緩存和本地 DNS 的緩存不一樣的是,這個是手機應用自己做的,而非整個運營商統一做。如何更新以及何時更新緩存,手機應用的客戶端可以和服務器協調來做這件事情。
如果本地沒有,就需要請求 HTTPDNS 的服務器,在本地 HTTPDNS 服務器的 IP 列表中,選擇一個發出 HTTP 請求,獲取一個要訪問的網站的 IP 列表。
請求的方式是這樣的:
手機客戶端之道手機在哪個運營商、哪個地址。由於是直接的 HTTP 通信,HTTPDNS 服務器能夠准確知道這些信息,因而可以做精准的全局負載均衡。
上面五個問題,歸結起來就兩大問題。一是解析速度和更新速度的平衡問題,二是智能調度的問題。HTTPDNS 對應的解決方案是 HTTPDNS 的緩存設計和調度設計。
HTTPDNS 的緩存設計
解析 DNS 過程復雜,通信此時多,對解析速度造成很大影響。為了加快解析,因而有了緩存,但是這又會產生緩存更新速度不及時的問題。最要命的是,這兩個方面都掌握在別人手中,也就是本地 DNS 服務器手中,它不會為你定制,作為客戶端干着急也沒辦法。
而 HTTPDNS 就是將解析速度和更新速度全部掌控在自己手中。
一方面,解析的過程,不需要本地 DNS 服務遞歸的調用一大圈,一個 HTTP 的請求直接搞定。要實時更新的時候,馬上就能起作用。
另一方面,為了提高解析速度,本地也有緩存,緩存是在客戶端 SDK 維護的,過期時間、更新時間,都可以自己控制。
HTTPDNS 的緩存設計策略也是咱們做應用架構中常用的緩存設計模式,也即分為客戶端、緩存、數據源三層。
- 對於應用架構來講,就是應用、緩存、數據庫。常見的是 Tomcat、Redis、Mysql;
- 對於 HTTPDNS 來講,就是手機客戶端、DNS 緩存、HTTPDNS 服務器。
只要是緩存模式,就存在緩存的過期、更新、不一致的問題,解決思路也是相似的。
例如,DNS 緩存在內存中,也可以持久化到存儲上,從而 APP 重啟之后,能夠盡快從存儲中加載上次累積的經常訪問的網站的解析結果,就不需要每次都全部解析一遍,再變成緩存。這有點像 Redis 是基於內存的緩存,但是同樣提供持久化的能力,使得重啟或者主備切換的時候,數據不會完全丟失。
SDK 中的緩存會嚴格按照緩存過期時間,如果緩存沒有命中,或者已經過期,而且客戶端不允許使用過期的幾率,則會發起一次解析,保證緩存記錄是更新的。
解析可以同步進行,也就是直接調用 HTTPDNS 的接口,返回最新的記錄,更新緩存。也可以異步進行,添加一個解析任務到后台,由后台任務調用 HTTPDNS 的接口。
同步更新的優點是實時性好,缺點是如果有多個請求都發現過期的時候,會同時請求 HTTPDNS 多次,造成資源浪費。
同步更新的方式對應到應用架構緩存的 Cache-Aside 機制,也就是先讀緩存,不命中讀數據庫,同時將結果寫入緩存。
異步更新的優點是,可以將多個請求都發現過期的情況,合並為一個對於 HTTPDNS 的請求任務,只執行一次,減少 HTTPDNS 的壓力。同時,可以在即將過期的時候,就創建一個任務進行預加載,防止過期之后再刷新,稱為預加載。
它的缺點是,當前請求拿到過期數據的時候,如果客戶端允許使用過期時間,需要冒一次風險。這次風險是指,如果過期的請求還能請求,就沒問題,如果不能請求,就會失敗一次,等下次緩存更新后,才能請求成功。
異步更新的機制,對應到應用架構緩存的 Refresh-Ahead 機制,即業務僅僅訪問緩存,當過期的時候定期刷新。在著名的應用緩存 Guava Cache 中,有個 RefreshAfterWrite 機制,對於並發情況下,多個緩存訪問不命中從而引發並發回源的請求,可以采取只有一個請求回源的模式。在應用架構的緩存中,也常常用數據預熱或者預加載的機制。
HTTPDNS 的調度設計
由於客戶端嵌入了 SDK,因而就不會因為本地 DNS 的各種緩存、轉發、NAT,讓權威 DNS 服務器誤會客戶端所在的位置和運營商,從而可以拿到第一手資料。
在客戶端,可以知道手機是哪個國家、哪個運營商、哪個省、甚至是哪個市,HTTPDNS 服務端可以根據這些信息,選擇最佳的服務節點返回。
如果有多個節點,還會考慮錯誤率、請求時間、服務器壓力、網絡狀態等,進行綜合選擇,而非僅僅考慮地理位置。當有一個節點宕機或者性能下降的時候,可以盡快進行切換。
要做到這一點,需要客戶端使用 HTTPDNS 返回的 IP 訪問業務應用。客戶端的 SDK 會收集網絡請求數據,如錯誤率、請求時間等網絡請求質量數據,並發送到統計后台,進行分析、聚合,以此查看不同 IP 的服務質量。
在服務端,應用可以通過調用 HTTPDNS 的管理接口,配置不同服務質量的優先級、權重。HTTPDNS 會根據這些策略綜合地理位置和線路狀況算出一個排序,優先訪問當前那些優質的、時延低的 IP 地址。
HTTPDNS 通過智能調度之后返回的結果,也會緩存在客戶端。為了不讓緩存使得調度失真,客戶端可以根據不同的移動網絡運營商的 SSID 來分維度緩存。不同的運營商解析出來的結果會不同。
小結
- 傳統 DNS 會因為緩存、轉發、NAT 等問題導致客戶端誤會自己所在的位置和運營商,從而影響流量的調度;
- HTTPDNS 通過客戶端 SDK 和服務端,通過 HTTP 直接調用解析 DNS 的方式,繞過了傳統 DNS 的缺點,實現了智能的調度。
參考:
- HTTPDNS 的原理;
- 劉超 - 趣談網絡協議系列課;