我們來展開今天的話題。
DNS 是基于 UDP 的應用層協(xié)議嗎?
當我們執(zhí)行 dig www.baidu.com 時,操作系統(tǒng)會發(fā)出 dns 請求,去詢問 www.baidu.com 域名對應的 IP 是多少。
$ dig www.baidu.com ; DiG 9.10.6 www.baidu.com global options: +cmd Got answer: -HEADER- opcode: QUERY, status: NOERROR, id: 61559 flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4000 QUESTION SECTION: ;www.baidu.com. IN A ANSWER SECTION: www.baidu.com. 298 IN CNAME www.a.shifen.com. www.a.shifen.com. 298 IN A 180.101.49.12 www.a.shifen.com. 298 IN A 180.101.49.11
此時,從抓包上來看,DNS 作為應用層協(xié)議,在傳輸層確實是用了 UDP 協(xié)議。
傳輸層使用了 UDP 協(xié)議
但是,其實 RFC 5966 中提到。
# https://www.rfc-editor.org/rfc/rfc5966 This document updates the requirements for the support of TCP as a transport protocol for DNS implementations.
也就是說雖然我們大部分情況下看到 DNS 使用 UDP,但其實 DNS 也是支持 TCP 的。
當我們在 dig 命令里加上 + tcp 的選項時,就可以強制 DNS 查詢使用 TCP 協(xié)議進行數(shù)據(jù)傳輸。
$ dig +tcp www.baidu.com ; DiG 9.10.6 +tcp www.baidu.com global options: +cmd Got answer: -HEADER- opcode: QUERY, status: NOERROR, id: 28411 flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4000 QUESTION SECTION: ;www.baidu.com. IN A ANSWER SECTION: www.baidu.com. 600 IN CNAME www.a.shifen.com. www.a.shifen.com. 600 IN A 180.101.49.11 www.a.shifen.com. 600 IN A 180.101.49.12
此時再次抓包。
可以發(fā)現(xiàn),在傳輸層,DNS 使用了 TCP 協(xié)議。
那么問題就來了。
為什么有 UDP 了還要用到 TCP?
我們知道網(wǎng)絡傳輸就像是在某個管道里傳輸數(shù)據(jù)包,這個管道有一定的粗細,叫 MTU。超過 MTU 則會在發(fā)送端的網(wǎng)絡層進行切分,然后在接收端的網(wǎng)絡層進行重組。而重組是需要有個緩沖區(qū)的,這個緩沖區(qū)的大小有個最小值,是 576Byte。
IP 層分片后傳輸會加大丟包的概率,且 IP 層本身并不具備重傳的功能,因此需要盡量避免 IP 層分片。
如果傳輸過程中真的發(fā)生了分片,需要盡量確保能在接收端順利重組,于是在最保險的情況下,將 MTU 設置為 576。(有些過于謹慎,現(xiàn)在大部分場景下 MTU=1500)。
基于這樣的前提,這個 MTU 長度刨去 IP 頭和 UDP 頭,大約剩下 512Byte。
所以才有了 RFC1035 中提到的,在 UDP 場景下,DNS 報文長度不應該超過 512Byte。
超過則會被截斷。那數(shù)據(jù)包就不完整了,可能會導致下游沒法正常解析數(shù)據(jù)。
但不可避免的是,總會有需要傳大量數(shù)據(jù)的場景。
怎么辦呢?那就改用 TCP 吧。
因為 TCP 本身會分段,分段后的長度正好小于等于 MTU 的長度。并且丟包后還會重傳,因此可以確保數(shù)據(jù)正常傳輸。
所以說數(shù)據(jù)包長度大于 512 時,DNS 就需要使用 TCP 協(xié)議進行傳輸。
那既然 TCP 那么好,為什么不全用 TCP?
我們可以對比上面 UDP 和 TCP 的那兩張圖,會發(fā)現(xiàn),除了 DNS 的請求和響應兩個數(shù)據(jù)包,TCP 場景下還多了三次握手和四次揮手這幾個包。
咋一看好像也不算特別多。
我們再回去看下,通過 DNS 協(xié)議去查詢域名對應的 IP 的過程。
將查詢過程細分的話,是可以分為迭代查詢和遞歸查詢的。
迭代查詢和遞歸查詢是什么
迭代查詢是指,發(fā)出 DNS 后,對方如果不知道這個域名的 IP 是什么,會告訴我有可能知道這件事的機器的 IP,我自己再去問有可能知道的機器,不斷重復直到問到結果。
遞歸查詢是指,發(fā)出 DNS 請求后,要求對方查好后直接給出最終結果。
看起來遞歸查詢好像很方便,但其實是將查詢的過程轉嫁給了其他 DNS 服務器。所以很多時候,這兩者是同時存在的。
舉個例子。
比如還是查詢 www.baidu.com 對應的 IP。
那本機在發(fā)出 DNS 請求時,會要求最近的 DNS 服務器將結果查好了再給回本機(step1),所以這時候是要求的遞歸查詢。
本機是輕松了,然而最近的 DNS 服務器(有可能是你的家用路由器)卻需要忙活起來了,它需要采用迭代查詢的方式,最壞的情況下,它需要:
step2: 查詢根域名服務器
step3: 拿到根域名服務器返回的一級域名(com)服務器 IP,
step4: 再去查詢一級域(com)服務器
step5: 得到二級域(baidu)服務器的 IP
step6: 查詢二級域(baidu)服務器
step7: 得到三級域(www)服務器的 IP
step8: 查詢?nèi)売颍╳ww)服務器
step9: 得到 www.baidu.com 服務器的 IP
此時 DNS 服務器在將結果放入緩存后,會將結果給回本機(step10)。
可以看到,迭代查詢和遞歸查詢在這個場景中其實是同時存在的。
迭代查詢和遞歸查詢的報文特征
這在 DNS 的報頭里也有體現(xiàn)。
我們需要關注的是 Flags 字段中的 RD 和 RA 字段。
RD(Resursion Desired)是指客戶端期望的查詢方式。
? 0:表示迭代查詢
?1:表示遞歸查詢
RA(Recursion Available)是指服務端實際采用的查詢方式,它只會在響應包里出現(xiàn)。
? 0:表示迭代查詢
?1:表示遞歸查詢
迭代查詢和遞歸查詢帶來的影響
回到為什么 DNS 不全部改用 TCP 的問題上。
我們可以看到,DNS 請求中,涉及到的服務器其實非常多。
如果都用 TCP 的話,那就都需要三次握手建立連接,四次揮手斷開連接。
對于遞歸查詢的那一方,其實還好,因為只會建立一次連接,發(fā)出一次請求接收一次響應就完事了。
但對于迭代查詢的一方,就需要與眾多服務器重復建立和斷開連接。性能會有很大影響。
這時候估計大家也會想問。
那是不是不斷開 TCP 連接,下次復用就好了?
不太好。
因為大部分 URL 所涉及到的域名服務器都不太相同,比如 www.baidu.com 和 www.xiaobaidebug.top 涉及到的一、二、三級域名服務器就不一樣,因此也沒必要維護 TCP 長鏈接做復用。
所以相比之下,在數(shù)據(jù)量較小的場景下,使用 UDP 就可以省下握手揮手的消耗,因此 UDP 才是更優(yōu)解。
DNS 的 IPV4 根域只有 13 個嗎?
確實是的。
問題又來了。
為什么是 13 個 IP,不能再加嗎?
這個,單純是歷史原因了。上面提到基于 UDP 的 DNS 報文不應該超過 512Byte,刨去 DNS 本身的報頭信息,算下來大概能放 13 個 IP(IPV4)。
具體的計算過程不太重要,我就省略了,對計算過程感興趣的話,可以看下這篇文章最下面的參考文獻。
雖然現(xiàn)在大部分機器 MTU=1500 了,但由于還可能存在 MTU=576 的機器,需要向前兼容,因此也不建議隨意調(diào)整。
但問題叒來了。
退一萬步,就算所有機器的 MTU 都到 1500 了,是不是就沒這個限制了?
嗯,從這個角度來說,確實可以加,但沒必要。
我們需要思考下為什么要加?
是因為覺得 13 個 IP 對應 13 臺服務器,壓力太大了嗎?
還是說出于其他不可明說的因素考慮?
比如,很久以前看電視的時候,有位磚家提到 "全球 DNS 根服務器只有 13 臺,其中 x 臺部署在漂亮國,只要它們切斷訪問,那我們的網(wǎng)絡就會受影響 balabala"。
但其實,13 個 IP 不代表只有 13 臺服務器。準確點來說,應該說是 13 組服務器,每個組都可以無限擴展服務器的個數(shù),多個服務器共用同一個 IP。
這里面其實涉及到一個叫任播的技術。
任播是什么
我們知道,在傳輸?shù)倪^程中,一臺機器發(fā)消息給另一臺機器,這叫單播(unicast)。
一臺機器,發(fā)消息給本地網(wǎng)段的所有機器,那叫廣播(broadcast)。
這兩個都很常見,應該都沒問題。
一臺機器,發(fā)消息給的所有符合條件的目的機器里的其中一臺,那叫任播(anycast)。
我們知道,全世界的網(wǎng)絡設備,放在一起就形成了一個網(wǎng)狀結構,這也是網(wǎng)絡這個名稱的由來。
我們假設有這么一個路由器,它想要訪問某個 IP 的機器。從路由器到目的機器有非常多條路徑,路由器可以通過跳數(shù)等信息來計算每條路徑的成本,得到最優(yōu)的路徑。將最優(yōu)路徑匯成一張表,也就是我們常說的路由表。
比如下面的圖里,綠色的線和紅色的線都能到達同樣的目的地,但顯然,綠色的路徑更短,所以路由表記錄了成本更低的綠色路線。
那么現(xiàn)在假設我們將這個網(wǎng)狀結構里的兩個點的網(wǎng)絡 IP 設為一樣,路由器其實不知道這是兩個不同的機器,對它來說,這只是兩條不同的路徑,但都是通向同一個 IP。
這兩條路徑都能到同一個 IP,因此打到任意一個服務都能拿到想要的信息,從而實現(xiàn)了任播。
現(xiàn)在我們再加個條件,路由器和其中一臺機器都在國內(nèi),另一臺機器在國外。對路由器來說,由于國內(nèi)的機器離得近,傳輸成本低,而國外的機器遠,傳輸成本高,所以路由器生成的最優(yōu)路線是打到國內(nèi)的機器。
基于這樣的思路,我們只要鏡像一份國外的 DNS 域名服務器信息到國內(nèi)機房里。我們就不再需要請求國外服務器了。
所以,就算其他國家的根域名服務器掛了,也不會對我們有什么影響,事實上國內(nèi)已經(jīng)有非常多的鏡像服務器了,穩(wěn)得很。
那稍微擴展一下,假設在上海和廣東都設置了相同 IP 的鏡像服務,那對于上海的用戶來說,他們的路由器會優(yōu)先將請求打到上海的鏡像服務。而廣東的用戶則會優(yōu)先打到廣東的機器里,從而實現(xiàn)了就近訪問。
上海的鏡像服務掛了,那對應的上海用戶路由器里的路由表,就會將路徑更新為廣東的鏡像機器。上海用戶的請求就會打到廣東的鏡像服務中。從而實現(xiàn)高可用(或者說災備)。
看起來,利用任播既能做到負載均衡,還能實現(xiàn)高可用,這跟 nginx 很像啊。
那么,問題就來了。
既然有任播技術,那為什么還要用 nginx?
nginx 作為常見的反向代理服務器,背后可以連 N 個服務端。當客戶端想要請求后端時,客戶端根本不需要知道是哪個服務器在為它提供服務,只管拿 nginx 最后返回的結果就行了。像這種,屏蔽掉具體有哪些服務器的代理方式就是所謂的反向代理。
正因為不知道背后有哪些服務器,因此可以做到無限擴展,掛了一臺其他也能頂上,因此實現(xiàn)了負載均衡和高可用。
之前寫過一篇文章《為什么有 HTTP 協(xié)議,還要有 websocket 協(xié)議?》,提到過對于網(wǎng)絡游戲場景,需要有服務器主動推數(shù)據(jù)到客戶端。由于 nginx 與客戶端和服務端之間會建立 TCP 長鏈接,因此客戶端在收到服務端的消息之后,能沿著這條連接響應服務端。
而如果這時候不用 nginx,單純使用任播,那服務器將消息主動推給客戶端之后,客戶端響應時,消息不保證還能給回原來的服務器。畢竟“任播”的含義就是,只要能訪問任意一臺服務器就行了。
因此任播并不能代替 nginx。
當然這兩個本來也不是一個維度的東西,拿來比較其實并不合適,我只是舉了個反例來幫助大家捋一捋兩者之間的差異。
總結
?DNS 在傳輸層既能使用 UDP 也能使用 TCP 協(xié)議。當傳輸數(shù)據(jù)量小于 512Byte 時會使用 UDP,否則使用 TCP。
? 雖然根域只有 13 個 IP,但不代表只有 13 臺服務器,準確的說,應該是十三組服務器,每組服務器都共用同一個 IP,國內(nèi)已經(jīng)有非常多的鏡像服務器,利用任播技術,只要能就近訪問到其中一臺就行了。
? 國內(nèi)國外如果都有相同 IP 的目的機器,那對于路由器來說,無非就是有兩條路徑可以抵達相同的目的地,一個遠一些,一個近一些?;诔杀?,會將更近的路徑放到路由表中。
? 任播技術雖然也能在一定程度上實現(xiàn)負載均衡和高可用,但它跟 nginx 并不是一個維度的東西,不能替代 nginx。
參考資料
《Why 13 DNS root servers?》
https://miek.nl/2013/november/10/why-13-dns-root-servers/
本文來自微信公眾號:小白 debug (ID:xiaobaidebug),作者:小白
廣告聲明:文內(nèi)含有的對外跳轉鏈接(包括不限于超鏈接、二維碼、口令等形式),用于傳遞更多信息,節(jié)省甄選時間,結果僅供參考,IT之家所有文章均包含本聲明。