目錄
文章目錄
DNS
DNS(Domain Name System,域名系統)是互聯網的一項服務。它作為將 Domain 和 IP 地址相互映射的一個分布式數據庫,能夠使用戶更方便地訪問互聯網。
源起
要想訪問網絡上的一台計算機,我們必須要知道它的 I P地址,但是這些地址(e.g. 243.185.187.39)只是一串數字,沒有規律,因此我們很難記住。並且如果一台計算機變更 IP 后,它必須通知所有的人使用新的 IP 來找到它。
顯然,直接使用 IP 地址是一個愚蠢的方案。於是人們想出了一個替代的方法,即為每一台計算機起一個名字(Hostname),然后建立 Hostname 到 IP 地址的映射關系。我們訪問 Hostname,剩下的名字到地址的轉換過程則由專門的服務器自動完成。
早期,名字到地址的轉換過程十分簡單。每台計算機保存一個 hosts 文件(e.g. /etc/hosts),里面列出所有 Hostname 和對應的 IP 地址,然后定期從一個維護此文件的站點更新里面的記錄。當我們訪問某個 Hostname 時,先在 hosts 文件找到對應的 IP,然后就可以建立連接。
早期的 ARPANET 就是這樣做的,但是隨着網絡規模的擴大,這種方法漸漸吃不消了。主要有以下三個原因:
- hosts 文件變得非常大;
- Hostname 很可能沖突;
- 集中的維護站點會不堪重負(需要為幾百萬機器提供 hosts 文件)。
為了解決上面的問題,1983 年 Paul Mockapetris 提出了 DNS(Domain Name System,域名系統),這是一種層次的、基於域的命名方案,並且用一個分布式數據庫系統加以實現。當我們需要訪問一個 Domain(計算機的別名)時,應用程序會向 DNS 服務器發起一個 DNS Query Request,DNS 服務器返回該 Domain 對應的 IP 地址。
DNS 通過下面三種手段解決了上述的問題:
- 用戶計算機上並沒有存儲所有的 Hostname 到 IP 的映射,這樣避免了 hosts 文件過於龐大。
- 規定了 Domain 的命名規則,保證主機別名不會重復。
- DNS 服務器不再是單一的一台機器,而是一個層次的、合理組織的服務器集群。
域名結構
為了實現 DNS 首先需要制定一套命名規則,防止 Domain 出現重復。命名規則和我們生活中的郵寄系統類似,使用層次的地址結構。郵寄系統中要給某人郵寄物品,地址可能是這樣:中國、廣東省、廣州市、番禺區、中山西路 12 號 XXX。而一個 Domain 看起來則是 groups.google.com。
對於整個 Internet 來說,域名層次結構的頂級由 ICANN(互聯網名稱與數字地址分配機構)負責管理。目前,已經有超過 250 個頂級域名,每個頂級域名可以進一步划為一些子域(二級域名),這些子域可被再次划分(三級域名),依此類推。所有這些域名可以組織成一棵樹,如下圖所示:
DNS 設計之初是用來建立 Domain 到 IP 地址的映射,理論上對於每一個 Domain 我們只需要在域名服務器上保存一條記錄即可。這里的記錄一般叫作 域名資源記錄,它是一個五元組:
Domain_name Time_to_live Class Type Value
- Domain_name:指出這條記錄適用於哪個域名;
- Time_to_live:用來表明記錄的生存周期,也就是說最多可以緩存該記錄多長時間(后面會講到緩存機制);
- Class:一般總是 IN;
- Type:記錄的類型;
- Value:記錄的值,如果是 A 記錄,則 value 是一個 IPv4 地址;如果是 AAAA 記錄,則是一個 IPv6 地址。
因為對於一個域名來說,通常並非只記錄其 IP 地址,還可能需要一些其他種類的記錄,所以需要一個 Type 字段作為標識,一些常見的記錄類型如下:
域名服務器集群
我們知道不能只用一台域名服務器來響應所有的 DNS 查詢,因為沒有一台機器能夠給全球的用戶提供查詢服務,計算能力、存儲、帶寬都不允許。只能合理組織一個域名服務器集群,使他們協同工作,共同提供域名解析服務。
域名區域
接下來首先要面對的一個問題是如何合理地將所有的域名資源記錄存儲到不同的域名服務器上。前面說過域名的名字空間可以組織為一棵樹,這里我們可以進一步將其划分為不重疊的區域(DNS zone),針對上圖的域名空間,一種可能的域名划分如下圖:
然后將每個區域中的多個域名服務器(其中一個是 Master,其他 Slave 服務器則用來提供數據備份、加快解析速度、保證服務可用性)關聯起來,這些域名服務器統稱為該區域的 “權威域名服務器(Authoritative Name Servers)”,它保存兩類域名資源記錄:
- 該區域內所有域名的域名資源記錄。
- 父區域和子區域的域名服務器對應的域名資源記錄(主要是 NS 記錄)。
這樣,所有的域名資源記錄被分散保存在多個域名服務器中,並且所有的域名服務器也組成了一個層次的索引結構。
圖中域名空間划分為 A, B, C, D, E, F, G 七個 DNS 區域,每個 DNS 區域都有多個權威域名服務器,這些域名服務器里面保存了許多域名解析記錄。對於上圖的 DNS 區域 E 來說,它的權威域名服務器里面保存的記錄如圖中表格所示。
仔細觀察上圖你可能會發現區域 A、B 並沒有父區域,他們之間並沒有一條路徑連在一起。這將導致一個很麻煩的問題,那就是區域 A 的權威域名服務器可能根本不知道區域 B 的存在。於是引入了根域名服務器 “.”,它保存了所有頂級區域的權威域名服務器記錄。現在通過根域名服務器,我們可以找到所有的頂級區域的權威域名服務器,然后就可以往下一級一級找下去了。下圖為全球根域名服務器的分布圖:
域名服務器類型
由高向低進行層次划分,可分為以下幾大類:
-
根域名服務器:最高層次的域名服務器,也是最重要的域名服務器,本地域名服務器如果解析不了域名就會向根域名服務器求助。全球共有 13 個不同 IP 地址的根域名服務器,它們的名稱用一個英文字母命名,從 a 一直到 m。這些服務器由各種組織控制,並由 ICANN(互聯網名稱和數字地址分配公司)授權,由於每分鍾都要解析的名稱數量多得令人難以置信,所以實際上每個根服務器都有鏡像服務器,每個根服務器與它的鏡像服務器共享同一個 IP 地址,中國大陸地區內只有 6 組根服務器鏡像。當你對某個根服務器發出請求時,請求會被路由到該根服務器離你最近的鏡像服務器。所有的根域名服務器都知道所有的頂級域名服務器的域名和地址,如果向根服務器發出對 jocent.me 的請求,則根服務器是不能在它的記錄文件中找到與 jocent.me 匹配的記錄。但是它會找到 me 的頂級域名記錄,並把負責 me 地址的頂級域名服務器的地址發回給請求者。
-
頂級域名服務器:負責管理在該頂級域名服務器下注冊的二級域名。當根域名服務器告訴查詢者頂級域名服務器地址時,查詢者緊接着就會到頂級域名服務器進行查詢。比如還是查詢 jocent.me,根域名服務器已經告訴了查詢者 me 頂級域名服務器的地址,me 頂級域名服務器會找到 jocent.me 的域名服務器的記錄,域名服務器檢查其區域文件,並發現它有與 jocent.me 相關聯的區域文件。在此文件的內部,有該主機的記錄。此記錄說明此主機所在的 IP 地址,並向請求者返回最終答案。
-
權威域名服務器:負責一個 Domain Zone 的域名解析工作。
-
本地域名服務器:當一個主機發出 DNS 查詢請求的時候,這個查詢請求首先就是發給本地域名服務器的。
域名解析
我們已經有了一個域名服務器集群,該集群合理地保存了域名空間和域名資源記錄的對應關系。現在我們要做的就是發送一個 DNS 查詢請求給域名服務器,然后坐等它返回正確的域名資源記錄,這個過程叫作域名解析。
域名解析的過程最早要追溯到建立網絡連接。因為每當連接上網絡之后,計算機會自動獲得一個默認的 DNS 服務器,當然你也可以用自己信任的 DNS 服務器,比如:8.8.8.8、114.114.114.114。我們把這個域名服務器也叫作本地域名服務器。
接下來當我們需要知道一個域名對應的資源記錄時,會向本地域名服務器發起請求,如果該域名恰好在本地域名服務器所轄屬的域名區域(DNS Zone)內,那么可以直接返回記錄;如果在本地域名服務器沒有發現該域名的資源記錄,就需要在整個域名空間搜索該域名。而整個域名空間的資源記錄存儲在一個分層的、樹狀聯系的一系列域名服務器上,所以本地域名服務器首先要從根域名服務器開始往下搜索。
這里有一個問題就是本地域名服務器如何找到根域名服務器在哪里呢?其實域名服務器啟動的時候,就會加載一個配置文件,里面保存了根域名服務器的 NS 記錄(要知道根域名服務器地址一般非常穩定,不會輕易改變,並且數量很少,所以這個配置文件會很小)。找到根域名服務器之后,就可以一級一級地往下查找啦。
現在假設區域E內的某個用戶想訪問 math.sysu.edu.cn,那么請求的過程如下:
DNS 的協議
會話標識(2 字節):是 DNS 報文的 ID 標識,對於請求報文和其對應的應答報文,這個字段是相同的,通過它可以區分 DNS 應答報文是哪個請求的響應。
標志(2 字節):
數量字段(總共 8 字節):Questions、Answer RRs、Authority RRs、Additional RRs 各自表示后面的四個區域的數目。
- Questions 表示查詢問題區域節的數量
- Answers 表示回答區域的數量
- Authoritative namesversers 表示授權區域的數量
- Additional recoreds 表示附加區域的數量
Queries 區域:
查詢名:長度不固定,且不使用填充字節,一般該字段表示的就是需要查詢的域名(如果是反向查詢,則為 IP,反向查詢即由 IP 地址反查域名),一般的格式如下圖所示。
查詢類:通常為 1,表明是 Internet 數據。
資源記錄(RR)區域:該區域有三個,但格式都是一樣的,分別是:回答區域,授權區域和附加區域。
域名(2 字節或不定長):它的格式和 Queries 區域的查詢名字字段是一樣的。有一點不同就是,當報文中域名重復出現的時候,該字段使用 2 個字節的偏移指針來表示。比如:在資源記錄中,域名通常是查詢問題部分的域名的重復,因此用 2 字節的指針來表示,具體格式是最前面的兩個高位是 11,用於識別指針。其余的 14 位從 DNS 報文的開始處計數(從 0 開始),指出該報文中的相應字節數。一個典型的例子,C00C(1100000000001100,12 正好是頭部的長度,其正好指向 Queries 區域的查詢名字字段)。
查詢類型:表明資源紀錄的類型,見 1.2 節的查詢類型表格所示。
查詢類:對於 Internet 信息,總是 IN。
生存時間(TTL):以秒為單位,表示的是資源記錄的生命周期,一般用於當地址解析程序取出資源記錄后決定保存及使用緩存數據的時間,它同時也可以表明該資源記錄的穩定程度,極為穩定的信息會被分配一個很大的值(比如:86400,這是一天的秒數)。
資源數據:該字段是一個可變長字段,表示按照查詢段的要求返回的相關資源記錄的數據。可以是 Address(表明查詢報文想要的回應是一個 IP 地址)或者 CNAME(表明查詢報文想要的回應是一個規范主機名)等。
Wireshark 抓包分析
域名解析總體可分為兩大步驟,第一個步驟是本機向本地域名服務器發出一個 DNS 請求報文,報文里攜帶需要查詢的域名;第二個步驟是本地域名服務器向本機回應一個 DNS 響應報文,里面包含域名對應的 IP 地址。從下面對 jocent.me 進行域名解析的報文中可明顯看出這兩大步驟。注意:第二大步驟中采用的是迭代查詢,其實是包含了很多小步驟的,詳情見下面的流程分析。
其具體的流程可描述如下:
- 主機 10.74.36.90 先向本地域名服務器 10.74.1.11 進行遞歸查詢。
- 本地域名服務器采用迭代查詢,向一個根域名服務器進行查詢。
- 根域名服務器告訴本地域名服務器,下一次應該查詢的頂級域名服務器 dns.me 的 IP 地址。
- 本地域名服務器向頂級域名服務器 dns.me 進行查詢。
- 頂級域名服務器 me 告訴本地域名服務器,下一步查詢權限服務器 dns.jocent.me 的 IP 地址。
- 本地域名服務器向權限服務器 dns.jocent.me 進行查詢。
- 權限服務器 dns.jocent.me 告訴本地域名服務器所查詢的主機的 IP 地址。
- 本地域名服務器最后把查詢結果告訴 10.74.36.90。
其中有兩個概念遞歸查詢和迭代查詢,其實在整個描述的過程中已經體現的很明顯,這里再說明一下:
- 遞歸查詢:本機向本地域名服務器發出一次查詢請求,就靜待最終的結果。如果本地域名服務器無法解析,自己會以 DNS 客戶機的身份向其它域名服務器查詢,直到得到最終的 IP 地址告訴本機。
- 迭代查詢:本地域名服務器向根域名服務器查詢,根域名服務器告訴它下一步到哪里去查詢,然后它再去查,每次它都是以客戶機的身份去各個服務器查詢。
請求:
響應:
為什么 DNS 使用 UDP 協議
在絕大多數情況下,DNS 都是使用 UDP 協議進行通信的,DNS 協議在設計之初也推薦我們在進行域名解析時首先使用 UDP,這確實能解決很多需求,但是不能解決全部的問題。
實際上,DNS 不僅使用了 UDP 協議,也使用了 TCP 協議,不過在具體介紹今天的問題之前,我們還是要對 DNS 協議進行簡單的介紹:DNS 查詢的類型不止包含 A 記錄、CNAME 記錄等常見查詢,還包含 AXFR 類型的特殊查詢,這種特殊查詢主要用於 DNS 區域傳輸,它的作用就是在多個命名服務器之間快速遷移記錄,由於查詢返回的響應比較大,所以會使用 TCP 協議來傳輸數據包。
作為被廣泛使用的協議,我們能夠找到非常多 DNS 相關的 RFC 文檔,DNS Camel Viewer 中列出了將近 300 個與 DNS 協議相關的 RFC 文檔,其中有 6 個是目前的互聯網標准,有 102 個是 DNS 相關的提案,這些文檔共同構成了我們目前對於 DNS 協議的設計理解。
《RFC1034 · Domain Names - Concepts and Facilities Internet Standard, 1987-11》
- DNS 查詢可以通過 UDP 數據包或者 TCP 連接進行傳輸;
- 由於 DNS 區域傳輸的功能對於數據的准確有着較強的需求,所以我們必須使用 TCP 或者其他的可靠協議來處理 AXFR 類型的請求;
《RFC1035 · Domain Names - Implementation and Specification》
- 互聯網支持 DNS 通過 TCP 或者 UDP 協議進行訪問;
- UDP 協議攜帶的消息不應該超過 512 字節,超過的消息會被截斷並設置 DNS 協議的 TC 位,UDP 協議對於區域傳輸功能是不可接受的,不過是互聯網上標准查詢的推薦協議。通過 UDP 協議發送的查詢可能會丟失,所以需要重傳策略解決這個問題;
《RFC1123 · Requirements for Internet Hosts – Application and Support Internet Standard, 1989-10》
- 未來定義的新 DNS 記錄類型可能會包含超過 512 字節的信息,所以我們應該使用 TCP 協議來傳輸 DNS 記錄;因此解析器和命名服務需要使用 TCP 協議作為 UDP 無法滿足需求時的備份;
- DNS 解析器和遞歸服務器必須支持 UDP 協議,並且應該支持使用 TCP 協議發送非區域傳輸的查詢;也就是說,DNS 解析器或者服務器在發送非區域傳輸查詢時,必須先發送一個 UDP 查詢,如果該查詢的響應被截斷,它應該嘗試使用 TCP 協議重新請求;
《RFC3596 · DNS Extensions to Support IP Version 6 Internet Standard, 2003-10》
- 通過 DNS 擴展支持 IPv6 協議,每個 IPv6 占 16 個字節是 IPv4 的四倍;
《RFC5011 · Automated Updates of DNS Security (DNSSEC) Trust Anchors Independent, 2007-10》
- 新增多種資源記錄為 DNS 客戶端的 DNS 數據來源進行認證,記錄包含的數據往往較大;
《RFC6376 · DomainKeys Identified Mail (DKIM) Signatures Internet Standard, 2011-09》
- 選擇合適的鍵大小進行加密是需要在成本、性能和風險之間的權衡,然而大的鍵(4096-bit)可能沒有辦法直接放到 DNS UDP 響應包中直接返回;
《RFC6891 · Extension Mechanisms for DNS (EDNS(0)) Internet Standard, 2013-04》
- 使用 UDP 進行傳輸的 DNS 查詢和響應最大不能超過 512 字節,不能支持大量 IPv6 地址或者 DNS 安全簽名等記錄的傳輸;
- EDNS 為 DNS 提供了擴展功能,讓 DNS 通過 UDP 協議攜帶最多 4096 字節的數據;
《RFC7766 · DNS Transport over TCP - Implementation Requirements Proposed Standard, 2016-03》
- 當客戶端接收到一個被階段的 DNS 響應時,應該通過 TC 字段判斷是否需要通過 TCP 協議重復發出 DNS 查詢請求;
- NSSEC 的引入使得截斷的 UDP 數據包變得非常常見;
- 使用 UDP 傳輸 DNS 的數據包大小超過最大傳輸單元(MTU)時可能會導致 IP 數據包的分片,RFC1123 文檔中預測的未來已經到來了,唯一一個用於增加 UDP 能夠攜帶數據包大小的 EDNS 機制被認為不夠可靠;
- 所有通用 DNS 實現必須要同時支持 UDP 和 TCP 傳輸協議,其中包括權威服務器、遞歸服務器以及樁解析器;
- 樁解析器和遞歸解析器可以根據情況選擇使用 TCP 或者 UDP 查詢直接請求目標服務器,以 UDP 協議來開始發起 DNS 請求不再是強制性的,TCP 協議與 UDP 協議在 DNS 查詢中可以互相替代,而不是作為重試機制;
《Specification for DNS over Transport Layer Security (TLS) Proposed Standard, 2016-05》
- 在 DNS 協議中引入 TLS 來為用戶提供隱私,減少對 DNS 查詢的竊聽和篡改,但是 TLS 協議的引入會帶來一些性能方面的額外開銷;
《RFC8484 · DNS Queries over HTTPS (DoH) Proposed Standard, 2018-10》
- 義了一種通過 HTTPS 發送 DNS 查詢和獲取 DNS 響應的協議;
簡單總結一下 DNS 的發展史,1987 年的 RFC1034 和 RFC1035 定義了最初版本的 DNS 協議,剛被設計出來的 DNS 就會同時使用 UDP 和 TCP 協議,對於絕大多數的 DNS 查詢來說都會使用 UDP 數據報進行傳輸,TCP 協議只會在區域傳輸的場景中使用,其中 UDP 數據包只會傳輸最大 512 字節的數據,多余的會被截斷;兩年后發布的 RFC1123 預測了 DNS 記錄中存儲的數據會越來越多,同時也第一次顯式的指出了發現 UDP 包被截斷時應該通過 TCP 協議重試。
過了將近 20 年的時間,由於互聯網的發展,人們發現 IPv4 已經不夠分配了,所以引入了更長的 IPv6,DNS 也在 2003 年發布的 RFC3596 中進行了協議上的支持;隨后發布的 RFC5011 和 RFC6376 增加了在鑒權和安全方面的支持,但是也帶來了巨大的 DNS 記錄,UDP 數據包被截斷變得非常常見。
RFC6891 提供的 DNS 擴展機制能夠幫助我們在一定程度上解決大數據包被截斷的問題,減少了使用 TCP 協議進行重試的需要,但是由於最大傳輸單元的限制,這並不能解決所有問題。
DNS 出現之后的 30 多年,RFC7766 才終於提出了使用 TCP 協議作為主要協議來解決 UDP 無法解決的問題,TCP 協議也不再只是一種重試時使用的機制,隨后出現的 DNS over TLS 和 DNS over HTTP 也都是對 DNS 協議的一種補充。
從這段發展時來看,DNS 並不只是使用 UDP 數據包進行通信,在 DNS 的標准中就一直能看到 TCP 協議的身影。
使用 UDP
UDP 協議在過去的幾十年中其實都是 DNS 主要使用的協議,作為互聯網的標准,目前的絕大多數 DNS 請求和響應都會使用 UDP 協議進行數據的傳輸,我們通過抓包工具就能輕松獲得以 UDP 協議為載體的 DNS 請求和響應。
DNS 請求的數據都會以二進制的形式封裝成如下的所示的 UDP 數據包中,下面就是一個調用 DNS 服務器獲取 www.baidu.com 域名 IP 地址的請求,從第四行的 05 字節開始到最后就是 DNS 請求的內容,整個數據包中除了 DNS 協議相關的內容之外,還包含以太網、IP 和 UDP 的協議頭:
0000 b0 6e bf 6a 4c 40 38 f9 d3 ce 10 a6 08 00 45 00 .n.jL@8.......E.
0010 00 3b 97 ae 00 00 40 11 0b 0a c0 a8 32 6d 72 72 .;....@.....2mrr
0020 72 72 f3 27 00 35 00 27 6b ee 0c 5a 01 00 00 01 rr.'.5.'k..Z....
0030 00 00 00 00 00 00 03 77 77 77→05 62 61 69 64 75 .......www.baidu
0040 03 63 6f 6d 00 00 01 00 01 .com.....
雖然每一個 UDP 數據包中都包含了很多以太網、IP、UDP 以及 DNS 協議的相關內容,但是上面的 DNS 請求大小只有 73 個字節,上述 DNS 請求的響應也只有 132 個字節,這對於今天其他的常見請求來講都是非常小的數據包:
0000 38 f9 d3 ce 10 a6 b0 6e bf 6a 4c 40 08 00 45 00 8......n.jL@..E.
0010 00 76 00 00 00 00 96 11 4c 7d 72 72 72 72 c0 a8 .v......L}rrrr..
0020 32 6d 00 35 f3 27 00 62 5b c2 0c 5a 81 80 00 01 2m.5.'.b[..Z....
0030 00 03 00 00 00 00 03 77 77 77 05 62 61 69 64 75 .......www.baidu
0040 03 63 6f 6d 00 00 01 00 01 c0 0c 00 05 00 01 00 .com............
0050 00 02 cb 00 0f 03 77 77 77 01 61 06 73 68 69 66 ......www.a.shif
0060 65 6e c0 16 c0 2b 00 01 00 01 00 00 01 18 00 04 en...+..........
0070 3d 87 a9 7d c0 2b 00 01 00 01 00 00 01 18 00 04 =..}.+..........
0080 3d 87 a9 79 =..y
UDP 和 TCP 的通信機制非常不同,作為可靠的傳輸協議,TCP 協議需要通信的雙方通過 三次握手 建立 TCP 連接后才可以通信,但是在 30 年前的 DNS 查詢的場景中我們其實並不需要穩定的連接(或者以為不需要),每一次 DNS 查詢都會直接向命名服務器發送 UDP 數據報,與此同時常見 DNS 查詢的數據包都非常小,TCP 建立連接會帶來以下的額外開銷:
- TCP 建立連接需要進行三次網絡通信;
- TCP 建立連接需要傳輸 ~130 字節的數據;
- TCP 銷毀連接需要進行四次網絡通信;
- TCP 銷毀連接需要傳輸 ~160 字節的數據;
假設網絡通信所消耗的時間是可以忽略的不計的,如果我們只考慮 TCP 建立連接時傳輸的數據的話,可以簡單來算一筆賬:
- 使用 TCP 協(共 330 字節)
- 三次握手 — 14x3(Ethernet) + 20x3(IP) + 44 + 44 + 32 字節
- 查詢協議頭 — 14(Ethernet) + 20(IP) + 20(TCP) 字節
- 響應協議頭 — 14(Ethernet) + 20(IP) + 20(TCP) 字節
- 使用 UDP 協議(共 84 字節)
- 查詢協議頭 — 14(Ethernet) + 20(IP) + 8(UDP) 字節
- 響應協議頭 — 14(Ethernet) + 20(IP) + 8(UDP) 字節
需要注意的是,我們在這里計算結果的前提是 DNS 解析器只需要與一個命名服務器或者權威服務器進行通信就可以獲得 DNS 響應,但是在實際場景中,DNS 解析器可能會遞歸地與多個命名服務器進行通信,這也加倍地放大了 TCP 協議在額外開銷上的劣勢。
如果 DNS 查詢的請求體和響應分別是 15 和 70 字節,那么 TCP 相比於 UDP 協議會增加 ~250 字節和 ~145% 的額外開銷,所以當請求體和響應的大小比較小時,通過 TCP 協議進行傳輸不僅需要傳輸更多的數據,還會消耗更多的資源,多次通信以及信息傳輸帶來的時間成本在 DNS 查詢較小時是無法被忽視的,TCP 連接帶來的可靠性在 DNS 的場景中沒能發揮太大的作用。
使用 TCP
今天的網絡狀況其實沒有幾十年前設計的那么簡單,我們不僅遇到了 IPv4 即將無法分配的狀況,而且還需要引入 DNSSEC 等機制來保證 DNS 查詢和請求的完整性以及傳輸安全,總而言之,DNS 協議需要處理的數據包越來越大、數據也越來越多。
從理論上來說,一個 UDP 數據包的大小最多可以達到 64KB,這對於一個常見的 DNS 查詢其實是一個非常大的數值;但是在實際生產中,一旦數據包中的數據超過了傳送鏈路的最大傳輸單元(MTU,也就是單個數據包大小的上限,一般為 1500 字節),當前數據包就可能會被分片傳輸、丟棄,部分的網絡設備甚至會直接拒絕處理包含 EDNS(0) 選項的請求,這就會導致使用 UDP 協議的 DNS 不穩定。
TCP 作為可靠的傳輸協議,可以非常好的解決這個問題,通過序列號、重傳等機制能夠保證消息的不重不漏,消息接受方的 TCP 棧會對分片的數據重新進行拼裝,DNS 等應用層協議可以直接使用處理好的完整數據。同時,當數據包足夠大的時候,TCP 三次握手帶來的額外開銷比例就會越來越小,與整個包的大小相比就會趨近於 0:
- 當 DNS 數據包大小為 500 字節時,TCP 協議的額外開銷為 ~41.2%;
- 當 DNS 數據包大小為 1100 字節時,TCP 協議的額外開銷為 ~20.7%;
- 當 DNS 數據包大小為 2300 字節時,TCP 協議的額外開銷為 ~10.3%;
- 當 DNS 數據包大小為 4800 字節時,TCP 協議的額外開銷為 ~5.0%;
所以,我們在 DNS 中存儲較多的內容時,TCP 三次握手以及協議頭帶來的額外開銷就不是關鍵因素了,不過我們 TCP 三次握手帶來的三次網絡傳輸耗時還是沒有辦法避免的,這也是我們在目前的場景下不得不接受的問題。
總結
很多人認為 DNS 使用了 UDP 協議來獲取域名對應的 IP 地址,這個觀點雖然沒錯,但是還是有一些片面,更加准確的說法其實是 DNS 查詢在剛設計時主要使用 UDP 協議進行通信,而 TCP 協議也是在 DNS 的演進和發展中被加入到規范的:
- DNS 在設計之初就在區域傳輸中引入了 TCP 協議,在查詢中使用 UDP 協議;
- 當 DNS 超過了 512 字節的限制,我們第一次在 DNS 協議中明確了『當 DNS 查詢被截斷時,應該使用 TCP 協議進行重試』這一規范;
- 隨后引入的 EDNS 機制允許我們使用 UDP 最多傳輸 4096 字節的數據,但是由於 MTU 的限制導致的數據分片以及丟失,使得這一特性不夠可靠;
- 在最近的幾年,我們重新規定了 DNS 應該同時支持 UDP 和 TCP 協議,TCP 協議也不再只是重試時的選擇;
在這里我們重新回顧一下 DNS 查詢選擇 UDP 或者 TCP 兩種不同協議時的主要原因:
- UDP 協議
- DNS 查詢的數據包較小、機制簡單;
- UDP 協議的額外開銷小、有着更好的性能表現;
- TCP 協議
- DNS 查詢由於 DNSSEC 和 IPv6 的引入迅速膨脹,導致 DNS 響應經常超過 MTU 造成數據的分片和丟失,我們需要依靠更加可靠的 TCP 協議完成數據的傳輸;
- 隨着 DNS 查詢中包含的數據不斷增加,TCP 協議頭以及三次握手帶來的額外開銷比例逐漸降低,不再是占據總傳輸數據大小的主要部分;
無論是選擇 UDP 還是 TCP,最核心的矛盾就在於需要傳輸的數據包大小,如果數據包小到一定程度,UDP 協議絕對最佳的選擇,但是當數據包逐漸增大直到突破 512 字節以及 MTU 1500 字節的限制時,我們也只能選擇使用更可靠的 TCP 協議來傳輸 DNS 查詢和相應。
DNS 緩存機制
回顧一下平時瀏覽網站的情況,我們會發現兩個比較有意思的現象:
- 80% 的時間我們都在看那些 20% 的網站;
- 我們會在一個網站的不同網頁之間跳轉,也就是不斷地訪問同一個域名,類似程序訪問的局部性原理。
另外,DNS 域名系統給應用訪問帶來了額外的時延,另外由於 DNS 域名解析采用不可靠的 UDP 協議通訊,受內外部網絡環境的影響較大,特別是在有丟包的情況下,導致的時延可能達到數秒。為緩解此問題,DNS 解析采用了緩存(Cache)機制。DNS 緩存可極大提升 DNS 域名解析的效率,一定程度上減少了客戶端到用戶之間環境對 DNS 域名解析的影響。
DNS 緩存為 DNS 技術中普遍使用的功能,在提升客戶訪問體驗中發揮了重要作用,在實際配置使用過程中,DNS緩存使用不合理,可能會對客戶體驗及訪問帶來嚴重的影響。
高速緩存的缺點在於它需要消耗一定的系統資源,並增加了域名系統的復雜性。決定解析結果在高速緩存中保留多長時間是在 DNS 域名建設和維護時需要重點考慮的問題。如果緩存時間過短,則可能會導致產生多余的不必要的解析請求,如果緩存時間過長,則可能導致域名變更時客戶訪問恢復時間過長。
基於緩存的 DNS 域名解析流程
企業的 DNS 域名解析系統一般分為 互聯網域名解析系統 和 企業內網域名解析系統。
- 互聯網域名解析系統主要實現互聯網用戶對企業系統的訪問,如:企業官方網站、電子商務平台、手機銀行等,互聯網域名解析系統需要企業自己的權威域名系統與運營商多級域名解析節點配合使用,以實現域名的解析功能。
- 企業內網域名解析系統一般由企業自行搭建和維護,實現企業內部用戶對企業內部系統的域名解析或企業內部系統間互訪的域名解析功能。
針對具體某一具體域名的訪問,DNS域名解析過程實際上是一個相當復雜的過程,需要經過多級迭代查詢才能成功獲取業務地址,以用戶通過互聯網訪問民生銀行官方網站系統 www.cmbc.com.cn 為例,其詳細過程如下圖所示:
- 當用戶訪問民生網站時,在WEB瀏覽器里輸入 www.cmbc.com.cn 時,瀏覽器先檢查是否有該網站的緩存(域名與 IP 的映射關系),有則直接使用訪問,如果沒有 DNS 請求發送到客戶端解析器。
- 假設后續環節都沒有緩存,解析器將 DNS 請求發送給運營商的 Local DNS 服務器處理,運營商 Local DNS 依次向
cn.
、com.cn.
、cmbc.com.cn.
域名服務器發起迭代查詢,並緩存查詢結果,同時將結果返回給用戶,實現業務訪問。 - 在高速緩存未超時的時間內,客戶瀏覽器再次發送到域名 www.cmbc.com.cn 的訪問將不再需要經過以上迭代查詢過程,將直接由客戶本地電腦解析器緩存或本地 DNS 服務器緩存直接返回域名對應的 IP 地址。企業內網域名解析系統一般設計為一級(僅權威 DNS 服務器)或兩級架構(包含本地 DNS 服務器和權威 DNS 服務器),不需要經過上述運營商多級域名迭代查詢過程,其它解析過程與上述過程基本一致,客戶端和本地 DNS 服務器同樣可提供高速緩功能。
DNS 緩存使用面臨的問題
緩存技術在用戶業務訪問過程中起到了加速訪問、提升用戶體驗的重要作用,若緩存設置使用不當,則可能給用戶訪問體驗帶來負面影響,甚至影響用戶正常業務訪問。緩存被使用在互聯網非受控環境和內網相對可控環境,在不同的環境會面臨不同的使用問題,下面來看看緩存在互聯網和內網環境使用中可能會面臨哪些問題。
互聯網環境緩存應用面臨的問題
在互聯網環境,緩存存在於瀏覽器、操作系統、運營商 Local DNS 服務器,其中運營商 Local DNS 是最重要且最不受用戶和網站管理員控制的一個環節,如果緩存值設置不合理,將直接影響用戶訪問,會給企業形象帶來負面影響。對於網站管理員來說,互聯網環境的緩存面臨兩大方面問題:
-
緩存刷新不受控:一般企業為實現線路冗余都會使用多家運營商,因此域名就會被緩存在多家運營商 Local DNS 服務器,當企業域名發生改變時,涉及 Local DNS 服務器眾多,在當前環境下,管理員無法刷新運營商 Local DNS 服務器緩存,在緩存未超時的情況下,客戶無法獲取到正確的域名進行業務訪問,只能等待 Local DNS 服務器緩存超時后才能解析到正確的域名,正常訪問業務,此種情況可能嚴重影響客戶體驗,導致大量的客戶投訴。
-
解析權和緩存值被修改:一些小運營商出於規模、節約成本的考慮,將域名轉發到其他運營商進行解析,並把收到的域名緩存值更改為較長的值,這會帶來兩個方面的問題:1)權威DNS接收到的請求IP地址不是客戶所在運營商IP地址,客戶的請求可能會被引導至錯誤的線路,導致客戶訪問慢;2)企業域名發生改變后將等待更長的超時時間才能正常訪問業務;同樣會給客戶帶來較差的體驗。
企業內網緩存應用面臨的問題
企業內網環境相對簡單,通常情況下用戶會直接向權威服務器發起域名解析請求,內網域名解析路徑較互聯網可控且環境穩定,無運營商遞歸查詢環節,因此基本不存在不可控的三方服務器和緩存被修改的問題。
企業內網環境包括兩類用戶,一類為終端用戶,例如櫃員、業務管理人員、辦公人員,這類用戶使用電腦通過瀏覽器訪問目標業務;另一類為生產系統,這類用戶為服務器,通過應用軟件訪問目標業務。兩類用戶涉及的基礎運行環境各不相同,緩存在使用中面臨的問題也會有所不同。
-
終端用戶面臨的問題:內網終端用戶與互聯網用戶類似,差異是內網無中間運營商,它的緩存存在於瀏覽器、終端操作系統,若緩存值設置過長,當出現業務地址變更的時候,用戶將無法訪問業務,可能會影響辦公或者影響客戶辦理業務,須等待本地緩存超時方可恢復。在終端用戶層面,目標業務域名改變一般為單個系統,不會出現大面積變更的情況,且對象為內網用戶,可建立統一的標准規范,因此影響范圍相對較小。
-
生產系統面臨的問題:為實現業務快速切換以及運維便利,企業生產系統之間也開始大力推廣通過域名方式訪問,但生產系統使用的操作系統、編程語言等各不相同。
DNS 緩存在實際應用中的考慮
DNS 緩存在使用中會面臨緩存無法刷新、被修改以及緩存控制復雜等問題,無論在互聯網還是內網,緩存設置不合理都將導致用戶無法訪問業務,影響用戶體驗,那么緩存設置就顯得尤為重要,它在實際應用中應該如何考慮?
首先,哪些情況下域名會發生改變,從而出現影響用戶訪問的情況:
- 主動操作:由於系統新建遷移、災備切換等有計划的變更操作。
- 被動操作:當出現故障需要緊急更改域名對應的服務地址恢復業務。
不同場景產生的影響時間以及緊迫程度有所不同,就有不同的考慮因素,下面針對不同的場景分別進行介紹。
主動操作之緩存考慮因素
針對主動操作的情況,有計划性,會有充足的時間准備,內網和互聯網環境均可提前將域名對應的緩存值更改為更小的值,操作等待時間大於設置的緩存值即可,以確保遞歸服務器緩存了設置較小的 TTL 值,待操作完成后再更改回原有 TTL 值,無需人工干預。
另外,避免緩存帶來影響,還可以規范架構部署,例如通過負載均衡或者虛地址方式對外提供服務,可減少域名變化的情況,負載均衡或者虛地址方式可把操作隱藏在服務端,不會傳達到客戶端,可直接避免緩存時間給用戶帶來的影響。
被動操作之互聯網緩存考慮因素
互聯網用戶直接面向運營商,面臨的問題是無法刷新緩存和緩存值被修改,要解決域名更改后無法快速生效的問題,需要從運營商入手:
- 刷新運營商 Local DNS 緩存:當我行一條運營商線路故障時,這條線路對應業務 DNS 記錄被用戶及對應運營商 Local DNS 服務器緩存,經了解,三大運營商正在開發刷新緩存的功能,電信和聯通支持基於單個域名自助刷新全國對應 Local DNS 緩存,目前正處於測試階段,預計三分鍾可以完成全國 Local DNS 緩存強制刷新;移動目前支持北京地區 Local DNS 緩存記錄刷新,其他地區正在計划開發中。三大運營商都支持刷新緩存的情況下,將很大程度解決緩存生效慢的問題。但是一些小運營商不在合作范圍內,目前仍然沒有辦法更新他們的緩存,可能會有少量地區客戶仍然會有所影響。
- 避免緩存被修改:使用 HTTP DNS。
被動操作之內網緩存考慮因素
內網生產環境的域名訪問在推廣初期,從無到有,看似簡單的域名請求,需要增加到JDK、操作系統等環節的訪問,這些環節緩存開啟情況不同,要實施域名訪問需重點考慮是否要開啟緩存,緩存時間配置為多少合適。
如何設置 TTL 值
緩存超時間(TTL)是緩存技術中的一個重要參數,對緩存效果起着決定性的作用。TTL 時間設置較長,域名就能緩存更長時間,用戶就能更快實現訪問,TTL 時間設置較短,域名就更快超時,用戶就需要等待域名解析才能正常訪問。因此,TTL 時間設置的長短將直接影響用戶的體驗效果。TTL 值設置大小需要根據業務特性、業務環境、DNS 服務器性能等因素綜合考慮,針對不同應用場景的緩存值設置規則可參考如下建議:
- 互聯網環境:互聯網環境由於運營商 Local DNS 緩存服務器的存在,具有不可控性,因此不適宜配置較長的緩存時間,建議參考 DNS 性能配置較小緩存值,例如設置為分鍾級。
- 內網終端環境:內網終端環境相對可控,且大部分業務都是通過標准模式虛服務方式對外提供服務,域名變更概率較小,為減少終端訪問頻率,緩存值建議配置稍長時間,例如設置為小時級。
- 內網生產環境:生產系統變更的概率較大,且若緩存更新不及時可能會帶來重大的業務影響,因此生產系統不適宜配置較長的緩存超時時間,建議參考 DNS 性能配置為秒到分鍾級。
HTTP DNS 解析流程
互聯網環境最大的問題是 Local DNS 緩存,緩存時間被修改,有沒有方式可以避開 Local DNS?近幾年 HTTP DNS 技術出現了,它是基於 HTTP 協議向 HTTP DNS 服務器發送域名解析請求,替代了基於 DNS 協議向運營商 Local DNS 發起解析請求的傳統方式,有效的避開了運營商 Local DNS,就避免了緩存值被第三方修改。
- 客戶端通過 HTTP/HTTPs 協議向 HTTP DNS 集群發起查詢請求,攜帶用戶域名和終端 IP。
- 服務集群查詢 CDN 內部調度系統,將域名最佳訪問節點 IP 響應給客戶端。
- 客戶端收到響應結果向節點發起請求。
- 客戶端拿到最優 IP 后,發起業務訪問。
- 若客戶端訪問 HTTP DNS 集群失敗,可自動切換為傳統方式通過運營商 Local DNS 進行解析查詢。
HTTP DNS 優點
- 繞過運營商 Local DNS,防劫持。
- 能直接獲取到客戶端 IP 地址,更精准的返回結果,避免跨運營商。
- 無運營商緩存,域名變更快速生效。
- HTTP DNS 可以在終端 APP DNS 緩存超時之前提前進行解析,規避了緩存再解析導致延時的問題。
- 與傳統方式互備,當 HTTP DNS 不可用時可選擇傳統方式備份訪問。
HTTP DNS 適用場景
HTTP DNS 主要是為 APP 類或桌面應用提供服務,如:游戲、電商、金融、音視頻、社交類 APP。HTTP DNS 需要在 APP 加載相應的 SDK 對默認的 DNS 請求方式進行修改,因此 HTTP DNS 的實現需要開發配合和深度介入,另外一般一個 APP 的訪問會涉及多個域名,每個域名都使用 HTTP DNS 還是只是部分域名訪問使用 HTTP DNS 需要評估。更細節的實現如緩存規則、更新規則、監控及切換規則也需要進行詳細的考慮和設計。
參考文檔
https://mp.weixin.qq.com/s/G8iTlYj5b5Lw4fJDo9O-xA
https://mp.weixin.qq.com/s/owtl7hQYcz5Um2RS_5sUHw
https://mp.weixin.qq.com/s/x_lE2zhvD8pZjmHdWEZXEQ
https://blog.csdn.net/tianxuhong/article/details/74922454