1. 程式人生 > >網路協議 17 - HTTPDNS:私人定製的 DNS 服務

網路協議 17 - HTTPDNS:私人定製的 DNS 服務

【前五篇】系列文章傳送門:

  1. 網路協議 12 - HTTP 協議:常用而不簡單
  2. 網路協議 13 - HTTPS 協議:加密路上無盡頭
  3. 網路協議 14 - 流媒體協議:要說愛你不容易
  4. 網路協議 15 - DNS 協議:網路世界的地址簿
  5. 網路協議 16 - HTTPDNS:私人定製的 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 列表。

請求的方式是這樣的:

curl http://123.4.5.6/d?dn=c.m.cnb.com

    手機客戶端之道手機在哪個運營商、哪個地址。由於是直接的 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 的缺點,實現了智慧的排程。

參考:

  1. HTTPDNS 的原理
  2. 劉超 - 趣談網路協議系列課;