IP 協議的職責是「網際互連」,它在 MAC 層之上,使用 IP 地址把 MAC 編號轉換成了四位數字,這就對物理網卡的 MAC 地址作了一層抽象,發展出了許多的「新玩法」。mysql
例如,分爲 A、B、C、D、E 五種類型,公有地址和私有地址,掩碼分割子網等。只要每一個小網絡在 IP 地址這個概念上達成一致,無論它在 MAC 層有多大的差別,均可以接入 TCP/IP 協議棧,最終匯合進整個互聯網。算法
但接入互聯網的計算機愈來愈多,IP 地址的缺點也就暴露出來了,最主要的是它「對人不友好」,雖然比 MAC 的 16 進制數要好一點,但仍是難於記憶和輸入。sql
怎麼解決這個問題呢?數據庫
那就「以其人之道還治其人之身」,在 IP 地址之上再來一次抽象,把數字形式的 IP 地址轉換成更有意義更好記的名字,在字符串的層面上再增長「新玩法」。因而,DNS 域名系統就這麼出現了。瀏覽器
在第 4 講曾經說過,域名是一個有層次的結構,是一串用「.」分隔的多個單詞,最右邊的被稱爲「頂級域名」,而後是「二級域名」,層級關係向左依次下降。緩存
最左邊的是主機名,一般用來代表主機的用途,好比「www」表示提供萬維網服務、「mail」表示提供郵件服務,不過這也不是絕對的,名字的關鍵是要讓咱們容易記憶。服務器
看一下極客時間的域名「time.geekbang.org」,這裏的「org」就是頂級域名,「geekbang」是二級域名,「time」則是主機名。使用這個域名,DNS 就會把它轉換成相應的 IP 地址,你就能夠訪問極客時間的網站了。網絡
域名不只可以代替 IP 地址,還有許多其餘的用途。架構
在 Apache、Nginx 這樣的 Web 服務器裏,域名能夠用來標識虛擬主機,決定由哪一個虛擬主機來對外提供服務,好比在 Nginx 裏就會使用「server_name」指令:app
複製代碼
server {
|
|
listen 80; # 監聽 80 端口
|
|
server_name time.geekbang.org; # 主機名是 time.geekbang.org
|
|
...
|
|
}
|
域名本質上仍是個名字空間系統,使用多級域名就能夠劃分出不一樣的國家、地區、組織、公司、部門,每一個域名都是獨一無二的,能夠做爲一種身份的標識。
舉個例子吧,假設 A 公司裏有個小明,B 公司裏有個小強,因而他們就能夠分別說是「小明.A 公司」,「小強.B 公司」,即便 B 公司裏也有個小明也不怕,能夠標記爲「小明.B 公司」,很好地解決了重名問題。
由於這個特性,域名也被擴展到了其餘應用領域,好比 Java 的包機制就採用域名做爲命名空間,只是它使用了反序。若是極客時間要開發 Java 應用,那麼它的包名可能就是「org.geekbang.time」。
而 XML 裏使用 URI 做爲名字空間,也是間接使用了域名。
就像 IP 地址必須轉換成 MAC 地址才能訪問主機同樣,域名也必需要轉換成 IP 地址,這個過程就是「域名解析」。
目前全世界有幾億個站點,有幾十億網民,而天天網絡上發生的 HTTP 流量更是天文數字。這些請求絕大多數都是基於域名來訪問網站的,因此 DNS 就成了互聯網的重要基礎設施,必需要保證域名解析穩定可靠、快速高效。
DNS 的核心繫統是一個三層的樹狀、分佈式服務,基本對應域名的結構:
在這裏根域名服務器是關鍵,它必須是衆所周知的,不然下面的各級服務器就無從談起了。目前全世界共有 13 組根域名服務器,又有數百臺的鏡像,保證必定可以被訪問到。
有了這個系統之後,任何一個域名均可以在這個樹形結構裏從頂至下進行查詢,就好像是把域名從右到左順序走了一遍,最終就得到了域名對應的 IP 地址。
例如,你要訪問「www.apple.com」,就要進行下面的三次查詢:
雖然核心的 DNS 系統遍及全球,服務能力很強也很穩定,但若是全世界的網民都往這個系統裏擠,即便不擠癱瘓了,訪問速度也會很慢。
因此在覈心 DNS 系統以外,還有兩種手段用來減輕域名解析的壓力,而且可以更快地獲取結果,基本思路就是「緩存」。
首先,許多大公司、網絡運行商都會創建本身的 DNS 服務器,做爲用戶 DNS 查詢的代理,代替用戶訪問核心 DNS 系統。這些「野生」服務器被稱爲「非權威域名服務器」,能夠緩存以前的查詢結果,若是已經有了記錄,就無需再向根服務器發起查詢,直接返回對應的 IP 地址。
這些 DNS 服務器的數量要比核心系統的服務器多不少,並且大多部署在離用戶很近的地方。比較知名的 DNS 有 Google 的「8.8.8.8」,Microsoft 的「4.2.2.1」,還有 CloudFlare 的「1.1.1.1」等等。
其次,操做系統裏也會對 DNS 解析結果作緩存,若是你以前訪問過「www.apple.com」,那麼下一次在瀏覽器裏再輸入這個網址的時候就不會再跑到 DNS 那裏去問了,直接在操做系統裏就能夠拿到 IP 地址。
另外,操做系統裏還有一個特殊的「主機映射」文件,一般是一個可編輯的文本,在 Linux 裏是「/etc/hosts」,在 Windows 裏是「C:\WINDOWS\system32\drivers\etc\hosts」,若是操做系統在緩存裏找不到 DNS 記錄,就會找這個文件。
有了上面的「野生」DNS 服務器、操做系統緩存和 hosts 文件後,不少域名解析的工做就都不用「跋山涉水」了,直接在本地或本機就能解決,不只方便了用戶,也減輕了各級 DNS 服務器的壓力,效率就大大提高了。
下面的這張圖比較完整地表示瞭如今的 DNS 架構。
在 Nginx 裏有這麼一條配置指令「resolver」,它就是用來配置 DNS 服務器的,若是沒有它,那麼 Nginx 就沒法查詢域名對應的 IP,也就沒法反向代理到外部的網站。
複製代碼
resolver 8.8.8.8 valid=30s; # 指定 Google 的 DNS,緩存 30 秒
|
有了域名,又有了能夠穩定工做的解析系統,因而咱們就能夠實現比 IP 地址更多的「新玩法」了。
第一種,也是最簡單的,「重定向」。由於域名代替了 IP 地址,因此可讓對外服務的域名不變,而主機的 IP 地址任意變更。當主機有狀況須要下線、遷移時,能夠更改 DNS 記錄,讓域名指向其餘的機器。
好比,你有一臺「buy.tv」的服務器要臨時停機維護,那你就能夠通知 DNS 服務器:「我這個 buy.tv 域名的地址變了啊,原先是 1.2.3.4,如今是 5.6.7.8,麻煩你改一下。」DNS 因而就修改內部的 IP 地址映射關係,以後再有訪問 buy.tv 的請求就不走 1.2.3.4 這臺主機,改由 5.6.7.8 來處理,這樣就能夠保證業務服務不中斷。
第二種,由於域名是一個名字空間,因此可使用 bind9 等開源軟件搭建一個在內部使用的 DNS,做爲名字服務器。這樣咱們開發的各類內部服務就都用域名來標記,好比數據庫服務都用域名「mysql.inner.app」,商品服務都用「goods.inner.app」,發起網絡通訊時也就沒必要再使用寫死的 IP 地址了,能夠直接用域名,並且這種方式也兼具了第一種「玩法」的優點。
第三種「玩法」包含了前兩種,也就是基於域名實現的負載均衡。
這種「玩法」也有兩種方式,兩種方式能夠混用。
第一種方式,由於域名解析能夠返回多個 IP 地址,因此一個域名能夠對應多臺主機,客戶端收到多個 IP 地址後,就能夠本身使用輪詢算法依次向服務器發起請求,實現負載均衡。
第二種方式,域名解析能夠配置內部的策略,返回離客戶端最近的主機,或者返回當前服務質量最好的主機,這樣在 DNS 端把請求分發到不一樣的服務器,實現負載均衡。
前面咱們說的都是可信的 DNS,若是有一些不懷好意的 DNS,那麼它也能夠在域名這方面「作手腳」,弄一些比較「惡意」的「玩法」,舉兩個例子:
好在互聯網上仍是好人多,並且 DNS 又是互聯網的基礎設施,這些「惡意 DNS」並很少見,你上網的時候不須要太過擔憂。
此次咱們學習了與 HTTP 協議有重要關係的域名和 DNS,在這裏簡單小結一下今天的內容:
歡迎你把本身的答案寫在留言區,與我和其餘同窗一塊兒討論。若是你以爲有所收穫,也歡迎把文章分享給你的朋友。