NS中有哪些值得學習的優秀設計
NS中有哪些值得學習的優秀設計
我曾經也當過學生,現在回想起來,會發現,學生時代的男生記憶力賊好,他們總能記住一串複雜神秘的字母數字串域名,有些大神甚至能直接敲IP上網。
在每個翻校牆去網吧的夜晚,你總能發現他們會在某個論壇裡尋找開源學習資料,完事還不忘在頁面底下祝樓主好人一生平安。
原來那時候,他們就已經在學習互聯網最重要的開源和分享精神。
每每想起,感動不已。
感動之餘。
我們會發現這裡面有幾個值得一聊的技術性問題。
比如,為什麼用域名和IP都能上網。
他們之間是什麼關係。
往深了聊,我們可以聊到DNS的原理,以及它的設計有哪些是值得我們學習的。
今天的話題,我們從為什麼要有DNS聊起。
為什麼要有DNS
如果我們想要訪問某度,你可以在瀏覽器上的搜索欄裡輸入112.80.248.76這個IP地址,直達頁面。
通過IP訪問網頁
這樣的行為,合法,但有病。
大部分人,連自己對象的電話號碼都記不住,又怎麼可能記得住這麼一串IP地址呢。
哦,不好意思,傷害到兄弟們了,你們沒對象。
但我假設你們有。
回想一下,雖然你記不住對象的電話號碼,但卻不影響你給她打電話。你的操作過程是不是打開通訊錄,輸入"富婆",然後就彈出一個電話號碼。點擊即撥打。
在計算機領域,你大概率也記不住IP,所以也需要有類似的通訊錄的功能。比如,你只需要輸入www.baidu.com,它就能幫你找到對應的 112.80.248.76,然後進行訪問。
用域名訪問
其中www.baidu.com 是域名,通過這個域名可以獲得它背後的IP是112.80.248.76。
就像一個人可以有多個電話號碼一樣,一個域名也可以對應有多個IP地址。
而將域名解析為IP的過程,也就是查"通訊錄"的過程,其實就是DNS(Domain Name System,域名系統)協議需要做的事情。
另外需要注意的是,上面的這個IP地址,我寫這篇文章的時候能訪問,不代表大家看文章的時候能訪問。因為這背後的IP地址是有可能變更的。可以通過使用 ping www.baidu.com獲得最新的IP地址。
ping獲得IP
但問題就來了。
普通人的通訊錄,一般有一千個電話號碼就算是社交小達人了,放在通訊錄裡綽綽有餘。
然而網站域名,卻不一樣,據說2015年的時候就已經超過3億了。
如果將這3億條記錄都放在一個服務器裡,會有兩個問題。
• 超過3億條域名數據,數據量過大,並且數據量持續增加
• 需要承受大量的讀請求。每個網站域名都可能會有成千的訪問。這加起來,四捨五入也有千億qps了。
顯然,如果將DNS做成類似手機通訊錄這樣的單點服務,那是不可能實現這樣的能力的,必須得是分佈式系統。
於是,問題就變成了,如何設計一個支持千億+qps請求的大型分佈式系統。
我知道肯定有人要說:"這是服務只有10qps的人該考慮的事情嗎?"
雖然我們做的服務可能只有10qps,但這並不妨礙我們學習DNS裡優秀的設計。
我們就從URL的層次結構聊起。
URL的層次結構
舉個例子。一個常見的域名,比如 www.baidu.com。
可以看到,這個域名中間用了兩個句點。通過句點符號,可以將域名分為三部分。
其中com被稱為一級域或頂級域,其他常見的頂級域還有cn,co等,baidu是二級域,www則是三級域。
除此之後,在com後面,其實還有一個被省略掉的句點號。它叫根域。
域名的層次結構
當域名多起來了之後,將它們相同的部分抽取出來,多個域名就可以變成這樣的樹狀層級結構。
層次結構
這時候我們就可以看到,這些域之間其實是一種層級關係,就像是學校,年級,班級那樣。
當你想要去定位一個具體域名的時候,你就可以通過這樣的層級找到對應的域名。
舉個例子。大家應該還記得那句廣告詞,"三年級2班的李小明同學,你媽媽拿了兩罐旺仔牛奶給你",其實李小明的媽媽,就是通過,學校、年級、班級的層級形式,一層層找到人。
DNS的原理
我們重新回來看下大佬們是怎麼設計DNS。
先直接說最重要的結論。
- 利用層級結構去拆分服務
- 加入多級緩存
接下來展開。
利用URL層級結構去拆分服務
DNS承載的流量壓力非常大,必須要做成分佈式服務,於是問題的關鍵就變成瞭如何拆分服務。
既然URL是樹狀的層級結構,那保存它們的服務,也可以依據這個,非常自然的拆成樹狀的形式。
一台服務器維護一個或多個域的信息。於是服務就變成了下面這樣的層級形式。
當我們需要訪問www.baidu.com。
查詢過程就跟下圖一樣。
DNS查詢過程
請求會先打到最近的DNS服務器(比如你家的家用路由器)中,如果在DNS服務器中找不到,則DNS服務器會直接詢問根域服務器,在根域服務器中雖然沒有www.baidu.com這條記錄的,但它可以知道這個URL屬於com域,於是就找到com域服務器的IP地址,然後訪問com域服務器,重複上面的操作,再找到放了baidu域的服務器是哪個,繼續往下,直到找到www.baidu.com的那條記錄,最後返回對應的IP地址。
可以看到,原理比較簡單,但這裡涉及到兩個問題。
• 本機怎麼知道最近的DNS服務器IP是什麼?
• 最近的DNS服務器怎麼知道根域的IP是多少?
我們一個個來回答。
本機怎麼知道最近的DNS服務器的IP是什麼?
這個在之前寫過的《剛插上網線,電腦怎麼知道自己的IP是什麼?》 提到過,插上網線時,機子會通過DHCP協議獲得本機的IP地址,子網掩碼,路由器地址,以及DNS服務器的IP地址。
DHCP協議
下面是我的mac機子,第二階段DHCP Offer中的抓包截圖。可以看到,這裡面返回的信息裡包含了DNS服務器的IP。
offer階段
同時也可以在左上角的點左上角的蘋果圖標->系統表偏好設置->網絡->高級->DNS中查看到DNS服務器的IP地址。
這裡有個小細節,從上面的抓包圖裡可以看到路由器地址和DNS服務器地址,以及DHCP服務器地址,其實都是192.168.31.1,這個其實是我這邊的家用路由器的IP地址,也就是說一般家用路由器自帶這幾個功能。
而在某裡雲服務器裡,DNS服務器也是一樣,是通過dhcp協議獲得。查看DNS服務器的IP地址也很方便,執行cat /etc/resolv.conf就好了。
這上面的nameserver中,可以看出有兩台DNS服務器,機子會按照文件中出現的順序來發起請求,如果第一台服務器沒反應,就會去請求第二台。
最近的DNS服務器怎麼知道根域的IP是多少?
我們也知道根域,就是域名樹的頂層,既然是頂層,那信息一般也就相對少一些。對應的IPV4地址只有13個,IPV6地址只有25個。
我們可以通過dig命令的+trace選項來查看一個域名的dns解析過程。
而前面提到的傳說中的13個根域,從字母am,就都在上圖中。
但這又引發了一個問題,上面看到的都是域名。
這。。。
"我本來是想通過域名去找IP的,你又讓我去找其他域名的IP?"
聽起來不科學,這不就死循環了嗎。
是的,所以這些根域名對應的IP會以配置文件的形式,放在每個域名服務器中。
也就是說並不需要再去請求根域名對應的IP,直接在配置裡能讀出來就好了。
下面這個截圖是域名服務器裡的配置內容。
可以看到A開頭的根域,它的IPV4地址是198.41.0.4。
加入多級緩存
對於高並發讀多寫少的場景,加入緩存幾乎就是標配。
DNS也不例外,它加了緩存,而且不止一層。
從在瀏覽器的搜索框中輸入URL。它會先後訪問瀏覽器緩存、操作系統的緩存/etc/hosts、最近的DNS服務器緩存。如果都找不到,才是到根域,頂級(一級)域,二級域等DNS服務器進行查詢請求。
加入緩存後的DNS查詢順序
於是請求過程就成了下圖這樣。可以看到上面提到的好幾有緩存的地方我都加了個綠色的小文件圖標,優先在緩存裡做查詢。
加入緩存後的DNS查詢過程
由於緩存了上面樹狀結構的信息,最近的DNS服務器也不再需要每次都從根域開始查起。比如在緩存裡能找到baidu.com的服務器IP,就直接跳到二級域服務器上做查找就好了。
正因為多級緩存的存在,每一層實際接收到的請求都大大減少了。並且每個人日常訪問的網站也就那麼幾個,所以大部分時候都能命中緩存直接返回IP地址。
簡單小結下。
DNS的設計中,通過層次結構將服務進行拆分,流量分散到多個服務器中。
又通過加入多級緩存,讓每個層級實際接收到的請求大大減少,因此大大提高了系統的性能。
這兩點,是我們做業務開發的過程中可以參考的優秀設計。
但還有一點,是我們大概率學不來的,叫任播,它也為DNS實現高並發處理能力提供了重要支持,我會把它放到放到下一篇文章展開聊聊。
協議格式
DNS是個域名解析系統,而運行在這套系統上的協議,就叫DNS協議。
和HTTP類似,DNS協議也是個應用層協議。
DNS是應用層協議
下圖是它的報文格式。
DNS報文
字段太多,很暈?這就對了。
我們就挑幾個重點的說說。
Transsaction ID是事務ID,對於一次請求和這個請求對應的應答,他們的事務ID是一樣的,類似於微服務系統中的log_id。
flag字段是指標誌位,有2個Byte,16個bit,需要關注的是QR,OpCode, RCode。
•QR用來標誌這是個查詢還是響應報文,0是查詢,1是響應。
•OpCode用來標誌操作碼,正常查詢都是0,不管是域名查ip,還是ip查域名,都屬於正常查詢。可以粗暴的認為我們平時只會看到0。
•RCode是響應碼,類似於HTTP裡的404, 502 這樣的status code。用來表示這次請求的結果是否正常。0是指一切正常。1是指報文格式錯誤,2服務域名服務器內部錯誤。
Queries字段,是指你實際查詢的內容。這裡其實包含三部分信息,Name, Type, Class。
查詢的內容分成三部分信息
•Name可以放域名或者IP。比如你要查的是baidu.com這個域名對應的IP,那裡面放的就是域名,反過來通過IP查對應的域名,那Name字段裡放的就是IP。
•Type是指你想查哪種信息,比如你想查這個域名對應的IP地址是什麼,那就是填A(address),如果你想查這個域名有沒有其他別名,就填CNAME(Canonical Name)。如果你想查xiaobaidebug@gmail.com對應的郵箱服務器地址是什麼(比如gmail.com),那就填MX(Mail Exchanger)。除此之外還有很多類型,下面是常見的Type表格。
• Class字段就比較有意思了,你可以簡單的認為,我們只會看到它填IN (Internet)。其實DNS協議本來設計出來是考慮到可能會有更多的應用場景的,比如這裡還能填CH,HS。大家甚至都不需要知道它們是什麼含義,因為隨著時間的發展,這些都已經成化石了,我們知道這個字段的唯一作用,可能就是可以在面試的時候可以隨意裝個x,深藏功與名。
Answers字段,從名字可以看出,跟Queries對應,一問一答。作用是返回查詢結果,比如通過域名查對應的IP地址,這個字段裡就會放入具體的IP信息。
抓包
原理看完了,來抓個包吧。
我們打開wireshark。然後執行
dig www.baidu.com
- 1.
此時操作系統會發出DNS請求,查詢 www.baidu.com對應的IP地址。
DNS_Query
上面的圖裡是DNS查詢(request)的內容,可以看到它是應用層的協議,傳輸層用的是UDP協議進行數據傳輸。截圖裡標紅的部分,也就是上面提到的需要重點關注的報文字段內容。其中flag字段是按bit展示的,因此抓包裡進行了分行展示。
接下來再看下響應(response)的數據包內容。
DNS_Response
可以看到事務ID(Transaction ID)跟DNS請求報文是一致的。並且Answers字段裡帶有兩個IP地址。試了下,兩個IP地址都是可以正常訪問的。
總結
• DNS是非常優秀的高並發分佈式系統,通過層次結構將服務進行拆分,流量分散到多個服務器中。又通過加入多級緩存,讓每個層級實際接收到的緩存大大減小,因此大大提高了系統的性能。這兩點在做業務開發的過程中是可以藉鑑的。
• 插上網線通網時,本機通過DHCP協議獲得DNS服務器的地址。
• 根域服務器的IP會以配置的形式加載到每一台DNS服務器當中。因此訪問任意一台DNS服務器都能輕鬆找到根域對應的IP地址。
最後
最後給大家留下兩個問題。
DNS基於UDP協議
• 從抓包可以看出,DNS在傳輸層上使用了UDP協議,那它只用UDP嗎?
• 上面提到,DNS的IPV4根域名只有13個,這裡面其實有不少都部署在漂亮國,那是不是意味著,只要他們不高興了,切斷我們的訪問,我們的網絡就得癱瘓了呢?
離開廣東好長時間了,好久沒人叫我靚仔了。
大家可以在評論區裡,叫我一靚仔嗎?
最近評論區裡叫我diao毛的兄弟越來越多了。
so emo. 哪有什麼diao毛,在你面前的,不過是一個漂泊在外,思念故鄉的可憐打工人而已。
所以。
我這麼善良質樸的願望,能被滿足嗎?