從理論到實踐,全方位認識DNS(理論篇)

 

對於 DNS(Domain Name System) 你們確定不陌生,不就是用來將一個網站的域名轉換爲對應的IP嗎。當咱們發現能夠上QQ但不能瀏覽網頁時,咱們會想到多是域名服務器掛掉了;當咱們用別人提供的hosts文件瀏覽到一個「不存在」的網頁時,咱們會了解到域名解析系統的脆弱。html

然而關於DNS還有一大堆故事值得咱們去傾聽,去思考。數據庫

DNS 源起

要想訪問網絡上的一臺計算機,咱們必需要知道它的IP地址,可是這些地址(好比243.185.187.39)只是一串數字,沒有規律,所以咱們很難記住。而且若是一臺計算機變動IP後,它必須通知全部的人。緩存

顯然,直接使用IP地址是一個愚蠢的方案。因而人們想出了一個替代的方法,即爲每一臺計算機起一個名字,而後創建計算機名字到地址的一個映射關係。咱們訪問計算機的名字,剩下的名字到地址的轉換過程則由計算機自動完成。服務器

hosts映射

早期,名字到地址的轉換過程十分簡單。每臺計算機保存一個hosts文件,裏面列出全部計算機名字和對應的IP地址,而後按期從一個維護此文件的站點更新裏面的記錄。當咱們訪問某個計算機名字時,先在hosts文件找到對應的IP,而後就能夠創建鏈接。網絡

 

早期的ARPANET就是這樣作的,可是隨着網絡規模的擴大,這種方法漸漸吃不消了。主要有如下三個緣由:分佈式

  1. hosts文件變得很是大;
  2. 主機名字會衝突;
  3. 集中的維護站點會不堪重負(須要給幾百萬機器提供hosts文件,想一想就可怕)。

域名系統

爲了解決上面的問題,1983年Paul Mockapetris提出了域名系統(DNS, Domain Name System),這是一種層次的、基於域的命名方案,而且用一個分佈式數據庫系統加以實現。當咱們須要訪問一個域名(其實就是前面說的計算機的名字)時,應用程序會向DNS服務器發起一個DNS請求,DNS服務器返回該域名對應的IP地址。經過下面三種手段解決了上面的問題:網站

  1. 用戶計算機上並無存儲全部的名字到IP的映射,這樣避免了hosts文件過於龐大(如今各操做系統中hosts文件默認都是空的)。
  2. 規定了域名的命名規則,保證主機名字不會重複。
  3. DNS服務器再也不是單一的一臺機器,而是一個層次的、合理組織的服務器集羣。

這樣訪問一個域名的過程能夠簡化爲下圖:google

DNS 協議

那麼如何具體實現這個所謂的域名系統呢,要知道管理一個超大型而且不斷變化的域名到IP的映射集合可不是一個簡單的事,何況還要去應付成千上萬的DNS查詢請求。人們最終想出了一套不錯的協議,規定如何來實現這個系統,下面咱們一塊兒來看看吧。spa

域名空間

首先咱們須要制定一套命名規則,防止域名出現重複。DNS關於域名的規則和咱們生活中的快遞系統相似,使用層次的地址結構。快遞系統中要給某人郵寄物品,地址多是這樣:中國、廣東省、廣州市、番禺區、中山西路12號 XXX。而一個域名看起來則是這樣的groups.google.com(爲何不是com.google.groups?我猜可能和老外寫地址的習慣有關)。操作系統

對於Internet來講,域名層次結構的頂級(至關於國際快遞地址中的國家部分)由ICANN(互聯網名稱與數字地址分配機構)負責管理。目前,已經有超過250個頂級域名,每一個頂級域名能夠進一步劃爲一些子域(二級域名),這些子域可被再次劃分(三級域名),依此類推。全部這些域名能夠組織成一棵樹,以下圖所示(圖片來自Computer Networks: 7-1 ):

域名資源記錄

DNS設計之初是用來創建域名到IP地址的映射,理論上對於每個域名咱們只須要在域名服務器上保存一條記錄便可。這裏的記錄通常叫做域名資源記錄,它是一個五元組,能夠用如下格式表示:

Domain_name Time_to_live Class Type Value

其中:

  1. Domain_name: 指出這條記錄適用於哪一個域名;
  2. Time_to_live: 用來代表記錄的生存週期,也就是說最多能夠緩存該記錄多長時間(後面會講到緩存機制);
  3. Class: 通常老是IN;
  4. Type: 記錄的類型;
  5. Value: 記錄的值,若是是A記錄,則value是一個IPv4地址。

咱們看到域名資源記錄有一個Type字段,用來代表記錄的類型。這是爲何呢?由於對於一個域名來講,一般並不是只記錄其IP地址,還可能須要一些其餘種類的記錄,一些常見的記錄類型以下:

記錄類型 含義
A 主機的IPv4地址
AAAA 主機的IPv6地址
NS 該域名所在域的權威域名服務器
MX 接受特定域名電子郵件的服務器域名
CNAME 當前域名的一個別名

關於這些域名資源記錄的實例咱們將在下一篇文章(實踐篇)看到。

域名服務器

咱們知道不能只用一臺域名服務器來響應全部的DNS查詢,由於沒有一臺機器可以給全球的用戶提供查詢服務,計算能力、存儲、帶寬都不容許。只能合理組織一個域名服務器集羣,使他們協同工做,共同提供域名解析服務。接下來首先要面對的一個問題是如何合理地將全部的域名資源記錄存儲到不一樣的域名服務器上。

前面說過域名的名字空間能夠組織爲一棵樹,這裏咱們能夠進一步將其劃分爲不重疊的區域(DNS zone),針對上圖的域名空間,一種可能的域名劃分以下圖:

而後將每一個區域與多個域名服務器(其中一個是master,其餘slave服務器則用來提供數據備份、加快解析速度、保證服務可用性)關聯起來,稱這些域名服務器爲該區域的權威域名服務器(Authoritative Name Servers ),它保存兩類域名資源記錄:

  1. 該區域內全部域名的域名資源記錄。
  2. 父區域和子區域的域名服務器對應的域名資源記錄(主要是NS記錄)。

這樣,全部的域名資源記錄都保存在多個域名服務器中,而且全部的域名服務器也組成了一個層次的索引結構,便於咱們後面進行域名解析。下面以一個簡化的域名空間爲例子,說明域名資源記錄是如何保存在域名服務器中的,以下圖a:

圖中域名空間劃分爲A, B, C, D, E, F, G七個DNS區域,每一個DNS區域都有多個權威域名服務器,這些域名服務器裏面保存了許多域名解析記錄。對於上圖的NDS區域E來講,它的權威域名服務器裏面保存的記錄如圖中表格所示。

仔細觀察上圖你可能會發現區域A、B並無父區域,他們之間並無一條路徑連在一塊兒。這將致使一個很麻煩的問題,那就是區域A的權威域名服務器可能根本不知道區域B的存在。認識到這一點後,你可能會想出一個很天然的解決方案,就是在A中記錄B域名服務器的地址,同時在B中記錄A的,這樣它們兩個就聯繫起來了。可是考慮到咱們有超過250個頂級域名,這樣作並非很恰當。

而咱們使用的域名系統則採用了一種更加聰明的方法,那就是引入根域名服務器,它保存了全部頂級區域的權威域名服務器記錄。如今經過根域名服務器,咱們能夠找到全部的頂級區域的權威域名服務器,而後就能夠往下一級一級找下去了。下圖爲全球根域名服務器的分佈圖,能夠在這裏找到。

如今爲止,咱們的權威域名服務器和根域名服務器其實組成了一個樹,樹根爲根域名服務器,下面每一個節點都是一個區域的權威域名服務器,對於圖a中各個DNS區域的權威域名服務器,它們組成了下面這棵樹(實際中,一個權威域名服務器可能保存有多個DNS區域的記錄,所以權威域名服務器之間的聯繫並不構成一棵樹。這部分的詳細內容能夠參考RFC 1034: 4. NAME SERVERS。下面爲了容易理解,將其簡化爲一棵樹):

域名解析

咱們已經有了一個域名服務器集羣,該集羣合理地保存了域名空間和域名資源記錄的對應關係。如今咱們要作的就是發送一個DNS請求給域名服務器,而後坐等它返回正確的域名資源記錄,這個過程叫做域名解析。

嚴格來講,域名解析的過程最先要追溯到創建網絡鏈接。由於每當鏈接上網絡以後,計算機會自動得到一個默認的DNS服務器,固然你也能夠用本身信任的DNS服務器,好比8.8.8.8(DNS服務器也有信任不信任之分,是的,實踐篇會講到),咱們把這個域名服務器也叫做本地域名服務器。接下來當咱們須要知道一個域名對應的資源記錄時,會向本地域名服務器發起請求,若是該域名剛好在本地域名服務器所轄屬的域名區域(DNS zone)內,那麼能夠直接返回記錄。

若是在本地域名服務器沒有發現該域名的資源記錄,就須要在整個域名空間搜索該域名。而整個域名空間的資源記錄存儲在一個分層的、樹狀聯繫的一系列域名服務器上,因此本地域名服務器首先要從根域名服務器開始往下搜索。這裏有一個問題就是本地域名服務器如何找到根域名服務器在哪裏呢?其實域名服務器啓動的時候,就會加載一個配置文件,裏面保存了根域名服務器的NS記錄(要知道根域名服務器地址通常很是穩定,不會輕易改變,而且數量不多,因此這個配置文件會很小)。找到根域名服務器以後,就能夠一級一級地往下查找啦。

仍然以咱們的圖a爲例,如今假設區域E內的某個用戶想訪問math.sysu.edu.cn,那麼請求的過程以下:

用語言簡單描述以下:

  1. 用戶:喂,本地域名服務器,告訴我math.sysu.edu.cn的地址;
  2. 本地域名服務器:哎呀,我不知道啊,不在個人轄區,容我去問問老大哥吧。root老大,能告訴我math.sysu.edu.cn的地址嗎;
  3. 根域名服務器:忙着呢,你去問B(.cn);
  4. 本地域名服務器:喂,B,告訴我math.sysu.edu.cn的地址;
  5. B:你去問D(.edu.cn);
  6. 本地域名服務器:喂,D,告訴我math.sysu.edu.cn的地址;
  7. D:你去問F(sysu.edu.cn);
  8. 本地域名服務器:喂,F,告訴我math.sysu.edu.cn的地址;
  9. F:容老衲看看,哎呀,找到了,是X.X.X.X;
  10. 本地域名服務器:踏破鐵鞋終於找到啦,喂用戶,出來啊,我找到了,是X.X.X.X

仔細想一想,這和咱們郵寄快遞實在是一模一樣啊,假設你從美國郵東西到廣州市番禺區,首先快遞送到中國(不過這裏沒有一個相似根域名服務器的中轉站而已),而後往下到廣東省,接下來是廣州市,再往下是番禺了。

上面的是本地域名服務器的迭代解析過程,其實也能夠遞歸查詢,這裏就不說了,道理差很少。

緩存機制

如今整個域名系統已經能夠爲咱們提供域名解析服務了,當咱們輸入域名,計算機發送DNS請求,而後DNS服務器返回給咱們解析的結果,一切看起來很完美。然而是否是能夠更完美呢?

回顧一下平時瀏覽網站的狀況,咱們會發現兩個比較有意思的結論:

  1. 80%的時間咱們都在看那些20%的網站,這就是大名鼎鼎的80/20 Rule
  2. 咱們會在一個網站的不一樣網頁之間跳轉,也就是不斷地訪問同一個域名,相似程序訪問的局部性原理。

這兩條結論很容易讓咱們聯想到緩存機制。若是咱們將已經訪問過的那些域名的解析結果緩存在本身的計算機上,那麼下次訪問的時候能夠直接讀取結果,不用再次重複DNS查詢過程,給本身和域名服務器都節省了麻煩。

固然,這樣作的一個前提是要緩存的解析結果不會頻繁更改,也就是說我十分鐘後解析一個域名的結果和如今解析的結果是同樣的。對大多數域名來講,這都是一個不爭的事實。可是不免有一些「善變」的域名,他們可能會頻繁更改本身的解析結果。爲了使緩存機制適應這兩類狀況,咱們在域名資源記錄裏面添加一個Time_to_live字段,代表這條記錄最多能夠緩存多久。對於那些「穩如泰山」的域名,給一個比較大的值,而那些「朝秦暮楚」的域名,則能夠給定一個小的值。

咱們既然能夠在本機利用緩存,那麼可不能夠在域名服務器上也利用緩存機制呢,答案固然是能夠的。由於對於域名服務器來講,上面的兩條有意思的結論仍然有效。因此,域名服務器能夠將那些訪問過的域名資源記錄緩存,用戶再次發起請求時,能夠直接返回緩存結果,不用去迭代或者遞歸解析。

關於DNS理論部分,更多內容還能夠參考這兩個文本:

並無結束

上面一大堆理論,看上去有點不明因此是吧,沒事,接下來會結合實踐來更加清晰地認識DNS這一最基礎的系統。

其實不止是DNS,還有HTTPS、TCP、UDP這些很基礎的協議,都值得咱們靜下心去好好認識它們。由於,寫DNS以前,我覺得我已經徹底搞明白了它,可是寫的過程發現好多地方本身根本就不知道,以前徹底是停留在一個很浮誇的層面上。因此,是時候找時間好好把這些協議過一遍,用本身的語言,從解決問題的角度,記錄下這些經典協議的故事了。

相關文章
相關標籤/搜索