域名系統的前世今生:一文讀懂互聯網的“門牌號”
IP 協議的責任是網絡互聯,它在 MAC 層之上運行,使用 IP 地址將 MAC 地址轉換為四位數,抽象出物理網卡的 MAC 地址,從而開發出許多“新玩法”。
例如,它被分為五種類型:A、B、C、D 和 E;公共和私有地址;子網掩碼分段。只要每個小網絡都同意 IP 地址的概念,無論它們在 MAC 層有多么不同,它們都可以訪問 TCP/IP 協議棧,并最終匯聚到整個互聯網中。
然而,隨著越來越多的計算機連接到互聯網,IP 地址的缺點暴露出來。主要問題是它“不夠用戶友好”。盡管它比 MAC 地址的十六進制數稍好,但仍然難以記住和輸入。
如何解決這個問題?
解決方案在于“以火攻火”,在 IP 地址之上添加另一層抽象,將數值 IP 地址轉換為更有意義且易于記住的名稱。這引入了一種字符串級別的新玩法。于是,DNS(域名系統)應運而生。
域名的形式
域名是一個分層結構,由多個用‘.’分隔的單詞組成。最右邊的單詞是頂級域名,其次是二級域名,層級從右向左遞減。
最左邊的部分是主機名,通常用于指示主機的用途。例如,“www”表示 Web 服務,“mail”表示郵件服務。不過,這并不是絕對的,關鍵是讓我們容易記住。
域名不僅是 IP 地址的替代品,還有許多其他用途。
在像 Apache 和 Nginx 這樣的 Web 服務器中,域名可以用來識別虛擬主機,并確定哪個虛擬主機提供外部服務。例如,在 Nginx 中可以使用 server_name 指令:
server {
listen 80;
server_name time.geekbang.org;
...
}
域名本質上是一個命名空間系統,使用多級域名來劃分不同的國家、地區、組織、公司和部門。每個域名都是唯一的,可以作為身份標識。
例如,假設公司 A 有一個名叫 Garb 的人,公司 B 也有一個名叫 Joe 的人。他們可以分別稱為 “Garb.Company A” 和 “Joe.Company B”。即使公司 B 也有一個名叫 Garb 的人,他們也可以被標記為 “Garb.Company B”,從而有效解決重復命名的問題。
由于這個特性,域名已擴展到其他應用領域。例如,Java 的包機制使用域名作為命名空間,但順序相反。如果極客時間要開發一個 Java 應用程序,其包名可能是 org.geekbang.time。
在 XML 中,URI 被用作命名空間,這間接涉及域名的使用。
域名解析
就像訪問主機需要將 IP 地址轉換為 MAC 地址一樣,域名也需要轉換為 IP 地址。這個過程稱為域名解析。
目前,全球有數十億個網站,數十億的互聯網用戶,每天在網絡上發生的 HTTP 流量是天文數字。大多數請求在訪問網站時是基于域名的,這使得 DNS 成為互聯網的一個重要基礎設施,必須確保穩定、可靠、快速和高效的域名解析。
DNS 的核心系統是一個三層樹狀分布式服務,對應域名的結構:
- 根域名服務器:管理頂級域名服務器并返回諸如 com、net、cn 等服務器的 IP 地址;
- 頂級域名服務器:管理其各自域下的權威域名服務器;例如,com 頂級域名服務器可以返回 apple.com 服務器的 IP 地址;
- 權威域名服務器:管理其域下主機的 IP 地址;例如,apple.com 的權威域名服務器可以返回 www.apple.com 的 IP 地址。
圖片
其中,根域名服務器至關重要。它必須是眾所周知的,否則對下層服務器的討論是不可能的。目前,全球共有 13 組根域名服務器,擁有數百個鏡像以確保可訪問性。
有了這個系統,任何域名都可以在這個樹結構中從上到下查詢。就像從右到左順序遍歷域名,最終獲得相應的 IP 地址。
例如,如果你想訪問 www.apple.com,你需要進行三次查詢:
- 訪問根域名服務器,它會提供 com 頂級域名服務器的地址。
- 訪問 com 頂級域名服務器,然后它會提供 apple.com 域名服務器的地址。
- 最后,訪問 apple.com 的域名服務器以獲得 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 時,不會回到更高層次查詢,而是直接從操作系統本地獲取其 IP 地址。
此外,操作系統中有一個特殊的主機映射文件,通常是一個可編輯的文本文件。在 Linux 中,它位于“/etc/hosts”,在 Windows 中,它位于 C:\WINDOWS\system32\drivers\etc\hosts。如果操作系統無法在緩存中找到 DNS 記錄,它會查找此文件。
有了上述野生 DNS 服務器、操作系統緩存和 hosts 文件,許多域名解析工作可以輕松地在本地或本地計算機上解決。這不僅方便了用戶,還減輕了各級 DNS 服務器的壓力,大大提高了效率。
下圖提供了當前 DNS 架構的一個相當全面的表示。
111111111111
在 Nginx 中,有一個名為“resolver”的配置指令,用于配置 DNS 服務器。如果沒有它,Nginx 將無法查詢域名對應的 IP,因此無法反向代理到外部網站。
resolver 8.8.8.8 valid=30s; # 指定 Google's 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 處理,確保業務服務不間斷。
內部 DNS
第二種方法涉及利用 bind9 或其他開源軟件設置內部 DNS 作為名稱服務器,因為域名是命名空間。這樣,我們可以對所有內部開發的服務使用域名;例如,數據庫服務可以使用 mysql.inner.app,產品服務可以表示為 goods.inner.app。當啟動網絡通信時,不再需要硬編碼 IP 地址,而是可以直接使用域名,這也結合了第一種方法的優點。
負載均衡
第三種方法結合了前兩種方法——基于域名實現負載均衡。
這有兩種方法可以實現,可以結合使用:
- 第一種方法是因為域名解析可以返回多個 IP 地址,所以一個域名可以對應多臺主機。客戶端接收到多個 IP 地址后,可以使用輪詢算法將請求順序發送到服務器,從而實現負載均衡。
- 第二種方法是配置域名解析的內部策略,返回離客戶端最近的主機或當前服務質量最好的主機。這樣,DNS 端將請求分配到不同的服務器,實現負載均衡。
上述所有內容都是關于可信賴的 DNS。如果存在一些惡意 DNS 服務器,它們還可以篡改域名,進行更多的惡意活動。這里有兩個例子:
- 域名屏蔽,域名不解析,直接返回錯誤,阻止你獲取 IP 地址,從而無法訪問網站;
- 域名劫持,又稱域名污染,當你想訪問網站 A 時,DNS 返回給你的是網站 B。
幸運的是,互聯網有許多好人,DNS 是互聯網的基礎設施。惡意 DNS 并不常見,所以你在瀏覽互聯網時不需要過于擔心。
這些是域名中的一些技巧和知識,了解這些有助于更好地使用和管理域名,提高互聯網的使用體驗。