今天要分析的具體問題是『為什么 DNS 使用 UDP 協(xié)議』,DNS 作為整個互聯(lián)網(wǎng)的電話簿,它能夠?qū)⒖梢员蝗死斫獾挠蛎g成可以被機(jī)器理解的 IP 地址,使得互聯(lián)網(wǎng)的使用者不再需要直接接觸很難閱讀和理解的 IP 地址。作者曾經(jīng)在 詳解 DNS 與 CoreDNS 的實(shí)現(xiàn)原理 一文中介紹過 DNS 的實(shí)現(xiàn)原理,這篇文章中就不會介紹 DNS 的實(shí)現(xiàn)原理了,感興趣的讀者可以看一下。 相信 DNS 使用 UDP 協(xié)議已經(jīng)成為了軟件工程師的常識,對計算機(jī)網(wǎng)絡(luò)稍有了解的人都知道 DNS 會使用 UDP 協(xié)議傳輸數(shù)據(jù),但是這一觀點(diǎn)其實(shí)不是完全正確的,我們在這里就會詳細(xì)分析『為什么 DNS 會使用 UDP 傳輸數(shù)據(jù)』以及『為什么 DNS 不止會使用 UDP 傳輸數(shù)據(jù)』兩個問題,希望能夠幫助各位讀者理解 DNS 協(xié)議的全貌。 概述我們將要討論的兩個問題其實(shí)并不沖突,在絕大多數(shù)情況下,DNS 都是使用 UDP 協(xié)議進(jìn)行通信的,DNS 協(xié)議在設(shè)計之初也推薦我們在進(jìn)行域名解析時首先使用 UDP,這確實(shí)能解決很多需求,但是不能解決全部的問題。 實(shí)際上,DNS 不僅使用了 UDP 協(xié)議,也使用了 TCP 協(xié)議,不過在具體介紹今天的問題之前,我們還是要對 DNS 協(xié)議進(jìn)行簡單的介紹:DNS 查詢的類型不止包含 A 記錄、CNAME 記錄等常見查詢,還包含 AXFR 類型的特殊查詢,這種特殊查詢主要用于 DNS 區(qū)域傳輸,它的作用就是在多個命名服務(wù)器之間快速遷移記錄,由于查詢返回的響應(yīng)比較大,所以會使用 TCP 協(xié)議來傳輸數(shù)據(jù)包。 作為被廣泛使用的協(xié)議,我們能夠找到非常多 DNS 相關(guān)的 RFC 文檔,DNS Camel Viewer 中列出了將近 300 個與 DNS 協(xié)議相關(guān)的 RFC 文檔,其中有 6 個是目前的互聯(lián)網(wǎng)標(biāo)準(zhǔn),有 102 個是 DNS 相關(guān)的提案,這些文檔共同構(gòu)成了我們目前對于 DNS 協(xié)議的設(shè)計理解,作者也沒有辦法去一一閱讀其中的內(nèi)容,只選擇了其中一些重要的文檔幫我們理解 DNS 的發(fā)展史以及它與 UDP/TCP 協(xié)議的關(guān)系,這里只會摘抄文檔中與 UDP/TCP 協(xié)議相關(guān)的內(nèi)容:
我們可以簡單總結(jié)一下 DNS 的發(fā)展史,1987 年的 RFC1034 和 RFC1035 定義了最初版本的 DNS 協(xié)議,剛被設(shè)計出來的 DNS 就會同時使用 UDP 和 TCP 協(xié)議,對于絕大多數(shù)的 DNS 查詢來說都會使用 UDP 數(shù)據(jù)報進(jìn)行傳輸,TCP 協(xié)議只會在區(qū)域傳輸?shù)膱鼍爸惺褂?,其?UDP 數(shù)據(jù)包只會傳輸最大 512 字節(jié)的數(shù)據(jù),多余的會被截斷;兩年后發(fā)布的 RFC1123 預(yù)測了 DNS 記錄中存儲的數(shù)據(jù)會越來越多,同時也第一次顯式的指出了發(fā)現(xiàn) UDP 包被截斷時應(yīng)該通過 TCP 協(xié)議重試。 過了將近 20 年的時間,由于互聯(lián)網(wǎng)的發(fā)展,人們發(fā)現(xiàn) IPv4 已經(jīng)不夠分配了,所以引入了更長的 IPv6,DNS 也在 2003 年發(fā)布的 RFC3596 中進(jìn)行了協(xié)議上的支持;隨后發(fā)布的 RFC5011 和 RFC6376 增加了在鑒權(quán)和安全方面的支持,但是也帶來了巨大的 DNS 記錄,UDP 數(shù)據(jù)包被截斷變得非常常見。 RFC6891 提供的 DNS 擴(kuò)展機(jī)制能夠幫助我們在一定程度上解決大數(shù)據(jù)包被截斷的問題,減少了使用 TCP 協(xié)議進(jìn)行重試的需要,但是由于最大傳輸單元的限制,這并不能解決所有問題。 DNS 出現(xiàn)之后的 30 多年,RFC7766 才終于提出了使用 TCP 協(xié)議作為主要協(xié)議來解決 UDP 無法解決的問題,TCP 協(xié)議也不再只是一種重試時使用的機(jī)制,隨后出現(xiàn)的 DNS over TLS 和 DNS over HTTP 也都是對 DNS 協(xié)議的一種補(bǔ)充。 從這段發(fā)展時來看,DNS 并不只是使用 UDP 數(shù)據(jù)包進(jìn)行通信,在 DNS 的標(biāo)準(zhǔn)中就一直能看到 TCP 協(xié)議的身影,我們在今天也是想要站在歷史的角度上分析 ——『為什么 DNS 查詢選擇使用 UDP/TCP 協(xié)議』。 設(shè)計在這一節(jié)中,我們將根據(jù) DNS 使用協(xié)議的不同,分兩個部分介紹 UDP 和 TCP 兩種不同的協(xié)議在支持 DNS 查詢和響應(yīng)時有哪些優(yōu)點(diǎn)和缺點(diǎn),在分析的過程中我們也會結(jié)合歷史上的上下文,還原做出設(shè)計決策時的場景。 UDPUDP 協(xié)議在過去的幾十年中其實(shí)都是 DNS 主要使用的協(xié)議,作為互聯(lián)網(wǎng)的標(biāo)準(zhǔn),目前的絕大多數(shù) DNS 請求和響應(yīng)都會使用 UDP 協(xié)議進(jìn)行數(shù)據(jù)的傳輸,我們通過抓包工具就能輕松獲得以 UDP 協(xié)議為載體的 DNS 請求和響應(yīng)。 DNS 請求的數(shù)據(jù)都會以二進(jìn)制的形式封裝成如下的所示的 UDP 數(shù)據(jù)包中,下面就是一個調(diào)用 DNS 服務(wù)器獲取 0000 b0 6e bf 6a 4c 40 38 f9 d3 ce 10 a6 08 00 45 00 .n.jL@8.......E. 雖然每一個 UDP 數(shù)據(jù)包中都包含了很多以太網(wǎng)、IP、UDP 以及 DNS 協(xié)議的相關(guān)內(nèi)容,但是上面的 DNS 請求大小只有 73 個字節(jié),上述 DNS 請求的響應(yīng)也只有 132 個字節(jié),這對于今天其他的常見請求來講都是非常小的數(shù)據(jù)包:
UDP 和 TCP 的通信機(jī)制非常不同,作為可靠的傳輸協(xié)議,TCP 協(xié)議需要通信的雙方通過 三次握手 建立 TCP 連接后才可以通信,但是在 30 年前的 DNS 查詢的場景中我們其實(shí)并不需要穩(wěn)定的連接(或者以為不需要),每一次 DNS 查詢都會直接向命名服務(wù)器發(fā)送 UDP 數(shù)據(jù)報,與此同時常見 DNS 查詢的數(shù)據(jù)包都非常小,TCP 建立連接會帶來以下的額外開銷:
假設(shè)網(wǎng)絡(luò)通信所消耗的時間是可以忽略的不計的,如果我們只考慮 TCP 建立連接時傳輸?shù)臄?shù)據(jù)的話,可以簡單來算一筆賬:
如果 DNS 查詢的請求體和響應(yīng)分別是 15 和 70 字節(jié),那么 TCP 相比于 UDP 協(xié)議會增加 ~250 字節(jié)和 ~145% 的額外開銷,所以當(dāng)請求體和響應(yīng)的大小比較小時,通過 TCP 協(xié)議進(jìn)行傳輸不僅需要傳輸更多的數(shù)據(jù),還會消耗更多的資源,多次通信以及信息傳輸帶來的時間成本在 DNS 查詢較小時是無法被忽視的,TCP 連接帶來的可靠性在 DNS 的場景中沒能發(fā)揮太大的作用。 TCP今天的網(wǎng)絡(luò)狀況其實(shí)沒有幾十年前設(shè)計的那么簡單,我們不僅遇到了 IPv4 即將無法分配的狀況,而且還需要引入 DNSSEC 等機(jī)制來保證 DNS 查詢和請求的完整性以及傳輸安全,總而言之,DNS 協(xié)議需要處理的數(shù)據(jù)包越來越大、數(shù)據(jù)也越來越多,但是『為什么當(dāng)需要傳輸?shù)臄?shù)據(jù)較多時我們就必須使用 TCP 協(xié)議呢?』,如果繼續(xù)使用 UDP 協(xié)議就不能完成 DNS 解析么。 從理論上來說,一個 UDP 數(shù)據(jù)包的大小最多可以達(dá)到 64KB,這對于一個常見的 DNS 查詢其實(shí)是一個非常大的數(shù)值;但是在實(shí)際生產(chǎn)中,一旦數(shù)據(jù)包中的數(shù)據(jù)超過了傳送鏈路的最大傳輸單元(MTU,也就是單個數(shù)據(jù)包大小的上限,一般為 1500 字節(jié)),當(dāng)前數(shù)據(jù)包就可能會被分片傳輸、丟棄,部分的網(wǎng)絡(luò)設(shè)備甚至?xí)苯泳芙^處理包含 EDNS(0) 選項(xiàng)的請求,這就會導(dǎo)致使用 UDP 協(xié)議的 DNS 不穩(wěn)定。 TCP 作為可靠的傳輸協(xié)議,可以非常好的解決這個問題,通過序列號、重傳等機(jī)制能夠保證消息的不重不漏,消息接受方的 TCP 棧會對分片的數(shù)據(jù)重新進(jìn)行拼裝,DNS 等應(yīng)用層協(xié)議可以直接使用處理好的完整數(shù)據(jù)。同時,當(dāng)數(shù)據(jù)包足夠大的時候,TCP 三次握手帶來的額外開銷比例就會越來越小,與整個包的大小相比就會趨近于 0:
所以,我們在 DNS 中存儲較多的內(nèi)容時,TCP 三次握手以及協(xié)議頭帶來的額外開銷就不是關(guān)鍵因素了,不過我們 TCP 三次握手帶來的三次網(wǎng)絡(luò)傳輸耗時還是沒有辦法避免的,這也是我們在目前的場景下不得不接受的問題。 總結(jié)很多人認(rèn)為 DNS 使用了 UDP 協(xié)議來獲取域名對應(yīng)的 IP 地址,這個觀點(diǎn)雖然沒錯,但是還是有一些片面,更加準(zhǔn)確的說法其實(shí)是 DNS 查詢在剛設(shè)計時主要使用 UDP 協(xié)議進(jìn)行通信,而 TCP 協(xié)議也是在 DNS 的演進(jìn)和發(fā)展中被加入到規(guī)范的:
這篇文章已經(jīng)詳細(xì)介紹了 DNS 的歷史以及選擇不同協(xié)議時考慮的關(guān)鍵點(diǎn),在這里我們重新回顧一下 DNS 查詢選擇 UDP 或者 TCP 兩種不同協(xié)議時的主要原因:
無論是選擇 UDP 還是 TCP,最核心的矛盾就在于需要傳輸?shù)臄?shù)據(jù)包大小,如果數(shù)據(jù)包小到一定程度,UDP 協(xié)議絕對最佳的選擇,但是當(dāng)數(shù)據(jù)包逐漸增大直到突破 512 字節(jié)以及 MTU 1500 字節(jié)的限制時,我們也只能選擇使用更可靠的 TCP 協(xié)議來傳輸 DNS 查詢和相應(yīng)。到最后,我們還是來看一些比較開放的相關(guān)問題,有興趣的讀者可以仔細(xì)思考一下下面的問題:
Reference
網(wǎng)絡(luò)通信技術(shù)分享 |
|
來自: 清風(fēng)劍舞 > 《知識文庫》