可能大家都知道或者被問過一個問題,那就是很經典的「從浏覽器輸入 URL 再到頁面展示,都發生了什麼」。這個問題雖然簡單,但是真的能夠從回答的各種細節上看出不同人之間的水準差距。
這篇文章主要是聊一聊輸入 URL 之後的第一步——域名解析
域名就類似于 www.google.com,而通過
ping
指令,就可以查詢到對應域名的 IP 位址了。 那為什麼又要有域名,又要有 IP 呢? 域名、IP 共存
首先還是解釋一下,為什麼會出現現在這種域名、IP 位址共存的情況。主要有兩個點:
- 提升使用者體驗
- 提高運作效率
分别解釋一下,IP 位址長度為 32 位,平時用十進制來表示的話,就長這樣——
192.168.1.0
,但是想象一下,如果我們要通路某個網站需要讓我們輸入這麼一長串數字,體驗肯定相當差,首先記憶這麼長串數字對很多人來說就很痛苦,更何況我們常用的網站肯定不止一個。
除此之外,如果你給其他人推廣你的網站,你吧啦吧啦說了一大堆,然後來個「如果你感興趣,請通路我們的網站 192.168.1.0」,然後就沒有然後了。
這也是為啥現在仍然在使用域名,友善人腦去記憶。
那為啥還需要 IP 位址呢?因為 IPv4 中的 IP 位址隻需要 4 個位元組,而用字元串表示的域名最少也需要幾十個位元組,長的甚至達到幾百位元組,而這會大大的增加底層路由器的負擔。
這也是為啥 IP 位址仍然在被使用。人來使用域名,而路由器層則使用 IP 位址,就跟我們書寫的是我們能認識的字元,而最終計算機認識的是一堆二進制一樣。
DNS 解析
知道了這個背景之後,我們就可以來看看「域名」是如果變成「IP 位址」的。
首先我們知道,會往 DNS 伺服器發送請求,那問題就來了,浏覽器怎麼知道 DNS 伺服器的位址是啥?
答案是提前配置好的。當然這不是唯一的方式,DNS 也有可能通過 DHCP(Dynamic Host Configuration Protocol) 動态配置設定的。
例如,MacOS 中的 DNS 配置就長下面這樣。
當然,你也可以通過指令行來檢視、修改,位址在
/etc/resolv.conf
。
有了 DNS 伺服器,那麼你可能會覺得,接下來的事情就很簡單了:
我給你傳個域名,你返給我對應的 IP 位址即可。那問題來了,現在網際網路中有數萬台的 DNS 伺服器,我怎麼知道資料在哪台伺服器上?難道要一台一台的周遊請求這數萬台伺服器嗎?
我相信你肯定沒有感覺到在浏覽器中輸入域名到頁面展示會花費那麼久,這也說明肯定不是一台一台伺服器進行周遊的。
域名的組成
要了解 DNS 是如何對其進行優化的,我們需要先知道域名的組成部分。看到這,很可能你會這麼想:
啥組成?不就是一堆字元串嗎?
實際上,域名是有由不同的域組成的,每個
.
隔開的部分就是一個域。
這裡舉個例子,假設我們分析的域名為
www.google.com
,從我們平時寫快遞的收貨位址的慣性思維來看,這個域的各個部分大小可能是這樣的:
www > google > com
但是實際上并不是這樣,而是:
. > com > google > www
你甚至發現,最大的還是個
.
。其實完整的域名應該是
www.google.com.
,
.
代表根域,因為根域對于所有的域名來說,意義都一樣,是以平時我們都把最後的點給省略了。
每個域都有自己的專屬名詞:
根域 | 一級級域|二級域名|(子域名)|主機名
當然,我們知道還可以針對二級域名再劃分子域名,類似于
mail.google.com
。
是以看到這,你應該能夠了解域名是由層次的這個概念了,我再舉個比較的通俗的例子。
DNS 的分層
了解完域名的分層之後,DNS 是如何優化域名解析的問題就迎刃而解了,那就是——分層。
DNS 伺服器會将域名的資料分布式的存儲在各個 DNS 伺服器上,但是同一個域的資料,會存儲在同一台 DNS 伺服器上,同一台 DNS 伺服器可以存儲多個域的資料。
這麼說可能會有些抽象,一圖勝千言,其實就是這樣:
有了對資料的分層,那麼查詢資料就會很有節奏感。
查詢域名資料
一圖勝千言,有了分層的機制,整個的查詢過程就會長這樣:
首先會去配置的 DNS 伺服器中查詢,這個其實一般都是本地或者内網中的 DNS 伺服器。如果沒有找到,就會去問根域要,說哥們,我這裡需要
www.google.com
的 IP 位址。
根域一看,我這裡沒有啊,但是我知道
com
域的 DNS 伺服器位址,他可能知道。
然後
com
域的 DNS 伺服器一看,
www.google.com
的 IP 位址我也不知道,但是我知道
google.com
域的 DNS 伺服器的位址,他可能知道,你再去問問他。
就這樣一路問下去,最終就能夠找到
www.google.com
所對應的 IP 位址了。
根域名伺服器
看了上面的流程,可能你還是會有點疑問。因為去找 DNS 伺服器查詢 IP 位址時,初始的 DNS 的伺服器的 IP 位址是走的本地計算機的配置的。那在分層查詢時,我怎麼知道有哪些根伺服器?以及我怎麼知道這些根伺服器的 IP 位址是啥?
答案是内置。
我們的裝置,或者說所有能上網的裝置都會内置根伺服器的清單。總共有 13 台根 DNS 伺服器,分别是
[a-m].root-servers.net
,這些根伺服器的位址根本不需要查詢就能直接擷取。
當然,稍微想想也知道,13 台伺服器是很難扛住全球網際網路使用者的請求的,實際上對于這 13 台伺服器有很多的鏡像伺服器。
眼見為實
說了這麼多虛的概念,接下來我們通過
dig
指令來實際操作一下。
可以看到,在
QUESTION SECTION
下的完整域名是
www.google.com.
是帶了根域的,那後面的這個
IN
和
A
又是啥意思呢?
這是因為,在向 DNS 伺服器查詢請求的時候,需要三個參數,分别是:
- 域名(例如 www.google.com)
- 網絡類型(Class 設計之初,考慮到了多種網絡并存的場景,但是目前實際上隻有一種網絡——網際網路,是以該參數的值一直都會為 ——
)IN
- 類型(例如
表示 IP 位址,而 A
則表示郵件伺服器的位址)MX
而在
ANSWER SECTION
中,則是 DNS 服務的響應結果,上圖中顯示了總有
6
條 DNS 記錄,并且在後面傳回了其對應的 IP 位址。
而其中的
69
則是 TTL,機關是秒,代表了在 69 之内都不用再次發送請求了。
最下面則是統計的資訊,本次 DNS 查詢所話費的時間,以及請求的 DNS 伺服器的位址和端口。這個伺服器位址是我們本機配置的 DNS 伺服器的位址。
眼尖的可能發現了,上圖中根本沒有設計到對根伺服器的請求。這是因為這個指令把這部分給省略掉了,我們可能通過加上
+trace
指令行參數來檢視詳細的分級查詢過程。
這次我們以
www.36kr.com
來作為例子。
可以看到,上圖中列出了所有的根域名伺服器,然後去找
com
域要,然後再找
36kr.com
域去要,最終是拿到了
www.36kr.com
緩存機制
當然,如果每次都從根伺服器開始往下找,明顯是不合理的,因為域名和 IP 位址的對應關系本來變動的就不頻繁,是以 DNS 伺服器是都會将結果緩存的。
并且,在下圖中: