DNS 故障集錦
當我第一次知道 DNS 時,我想它應該不會很複雜。不就是一些存儲在伺服器上的 DNS 記錄罷了。有什麼大不了的?
但是教科書上只是介紹了 DNS 的原理,並沒有告訴你實際使用中 DNS 可能會以多少種方式破壞你的系統。這可不僅僅是緩存問題!
所以我 在 Twitter 上發起了一個提問,徵集人們遇到的 DNS 問題,尤其是那些一開始看起來與 DNS 沒什麼關係的問題。(「總是 DNS 問題」這個梗)
我不打算在這篇文章中討論如何解決或避免這些問題,但我會放一些討論這些問題的鏈接,在那裡可以找到解決問題的方法。
問題:網路請求緩慢
如果你的網路比預期的要慢,這是因為某些原因導致 DNS 解析器變慢了。這可能是解析器負載過大或者存在內存泄漏等原因導致的。
我的路由器的 DNS 轉發器曾遇到過這個問題,導致我的所有 DNS 請求很慢。我通過重啟路由器解決了這個問題。
問題:DNS 超時
一些網友提到由於 DNS 查詢超時,他們的網路請求需要耗時 2 秒多甚至 30 秒。這跟「網路請求緩慢」問題類似,但情況要更糟糕,因為 DNS 請求就會消耗掉幾秒鐘時間。
Sophie Haskins 有一篇關於 Kubernete DNS 超時的博客文章 一次 Kube DNS 踩坑經歷。
問題:ndots 設置
一些網友提到在 /etc/resolv.conf
中設置 ndots:5
時會出現問題。
下面是從 這篇《Kubernetes 容器莢中 /etc/resolv.conf
里設置 ndots:5
為什麼會拖慢你的程序性能》中引用的 /etc/resolv.conf
文件。
nameserver 100.64.0.10
search namespace.svc.cluster.local svc.cluster.local cluster.local eu-west-1.compute.internal
options ndots:5
如果你用上面的配置文件,想要查詢得域名是 google.com
,那麼你的程序會調用 getaddrinfo
函數,而它會依次查詢以下域名:
google.com.namespace.svc.cluster.local.
google.com.svc.cluster.local.
google.com.cluster.local.
google.com.eu-west-1.compute.internal.
google.com.
簡單來說,它會檢查 google.com
是不是 search
這一行中的某個子域名。
所以每發起一次 DNS 查詢,你都得先等待前 4 次查詢失敗後才能獲取到最終查詢結果。
問題:難以判斷系統使用的 DNS 解析器
這本身並不是一個問題,但當你遇到 DNS 問題時,一般都會跟 DNS 解析器有關。我沒有一種判斷 DNS 解析器的萬能方法。
下面是我知道的方法:
- 在 Linux 系統上,最常見的是通過
/etc/resolv.conf
來選擇 DNS 解析器。但是也有例外,比如瀏覽器可能會忽略/etc/resolv.conf
,而是使用 基於 HTTPS 的 DNS 服務。 - 如果你使用的是 UDP DNS,你可以通過
sudo tcpdump port 53
來查看 DNS 請求被發送到了哪裡。但如果你使用的是基於 HTTPS 的 DNS 或 基於 TLS 的 DNS ,這個方法就不行了。
我依稀記得這在 MacOS 系統上會更加令人迷惑,我也不清楚原因。
問題:DNS 伺服器返回 NXDOMAIN 而不是 NOERROR
這是我曾經遇到過的一個 Nginx 不能解析域名的問題。
- 我設置 Nginx 使用一個特定的 DNS 伺服器來解析 DNS 查詢
- 當訪問這個域名時,Nginx 做了兩次查詢,第一次是對
A
的,第二次是對AAAA
的 - 對於
A
的查詢,DNS 伺服器返回NXDOMAIN
- Nginx 認為這個域名不存在,然後放棄查詢
- 對於
AAAA
的查詢 DNS 伺服器返回了成功 - 但 Nginx 忽略了對
AAAA
返回的查詢結果,因為它前面已經放棄查詢了
問題出在 DNS 伺服器本應該返回 NOERROR
的——那個域名確實存在,只是沒有關於 A
的記錄罷了。我報告了這個問題,然後他們修復了這個問題。
我自己也寫出過這個問題,所以我理解為什麼會發生這種情況——很容易想當然地認為「沒有要查詢的記錄,就應該返回 NXDOMAIN
錯誤碼」。
問題:自動生效的 DNS 緩存
如果你在生成一個域名的 DNS 記錄之前就訪問這個域名,那麼這個記錄的缺失會被緩存起來。當你第一次遇到這個問題時一定會非常吃驚——我也是去年才知道有這個問題。
緩存的 TTL 就是域名的 起始許可權記錄 (SOA) 記錄的 TTL ——比如對於 jvns.ca
,這個值是一個小時。
問題:Nginx 永久緩存 DNS 記錄
如果你在 Nginx 中使用下面的配置:
location / {
proxy_pass https://some.domain.com;
}
Nginx 只會在啟動的時候解析一次 some.domain.com
,以後不會再對其進行解析。這是非常危險的操作,尤其是對於那些 IP 地址經常變動的域名。它可能平安無事地運行幾個月,然後突然在某個凌晨兩點把你從床上糾起來。
針對這個問題已經有很多眾所周知的方法了,但由於本文不是關於 Nginx 的,所以我不打算深入探討它。但你第一次遇到它時一定會很驚訝。
這是一篇關於這個問題發生在 AWS 負載均衡器上的 博客文章。
問題:Java 永久緩存 DNS 記錄
跟上面類似的問題,只是出現在 Java 上:據說 這與你 Java 的配置有關。「JVM 的默認 TTL 設置可能會導致只有 JVM 重啟時才會刷新 DNS 記錄。」
我還沒有遇到過這個問題,不過我那些經常寫 Java 的朋友遇到過這個問題。
當然,任何軟體都可能存在永久緩存 DNS 的問題,但據我所知它經常出現在 Nginx 和 Java 上。
問題:被遺忘的 /etc/hosts 記錄
這是另一種緩存問題:/etc/hosts
中的記錄會覆蓋你的常規 DNS 設置!
讓人迷惑的是 dig
命令會忽略 /etc/hosts
文件。所以當你使用 dig whatever.com
來查詢 DNS 信息時,它會告訴你一切正常。
問題:電子郵件未發送 / 將成為垃圾郵件
電子郵件是通過 DNS(MX 記錄, SPF 記錄, DKIM 記錄)來發送和驗證的,所以有些電子郵件問題其實是 DNS 問題。
問題:對國際化域名無效
你可以使用非 ASCII 字元甚至是表情符來註冊域名,比如 拉屎網 https://?.la。
DNS 能夠處理國際化域名是因為 ?.la
會被用 punycode 編碼將轉換為 xn--ls8h.la
。
儘管已經有了 DNS 處理國際化域名的標準,很多軟體並不能很好地處理國際化域名。Julian Squires 的 幹掉 Chrome 瀏覽器的表情符!! 就是一個非常有趣的例子。
問題:TCP DNS 被防火牆攔截
有人提到一些防火牆會允許在 53 埠上使用 UDP 協議,但是禁止 TCP 協議。然而很多 DNS 查詢需要在 53 埠上使用 TCP,這可能會導致很難排查的間歇性的問題。
問題:musl 不支持 TCP DNS
很多應用程序使用 libc
的 getaddrinfo
來做 DNS 查詢。musl
是用在 Alpine Docker 容器上的 glibc
替代品。而它不支持 TCP DNS。如果你的 DNS 查詢的響應數據超過 DNS UDP 數據包的大小(512 位元組)就會出現問題。
我對此仍然不太清楚,我下面我的理解也可能是錯的:
musl
的getaddrinfo
發起一個 DNS 請求- DNS 伺服器發現請求的響應數據太大了,沒法放入一個 DNS 數據包中
- DNS 伺服器返回一個 空截斷響應 ,並期望客戶端通過 TCP DNS 重新用發起查詢
- 但
musl
不支持 TCP DNS,所以根本不會重試
關於這個問題的文章:在 Alpine Linux 上的 DNS 解析問題。
問題:getaddrinfo 不支持輪詢 DNS
輪詢 DNS 是一種 負載均衡 技術,每次 DNS 查詢都會獲得一個不同的 IP 地址。顯然如果你使用 gethostbyname
做 DNS 查詢不會有任何問題,但是用 getaddrinfo
就不行了。因為 getaddrinfo
會對獲得的 IP 地址進行排序。
在你從 gethostbyname
切換到 getaddrinfo
時可能完全不會意識到這可能會引起負載均衡問題。
這個問題可能會非常隱蔽,如果你不是用 C 語言編程的話,這些函數調用被隱藏在各種調用庫背後,你可能完全意識不到發生了這種改變。所以某次看似人畜無害的升級就可能導致你的 DNS 負載均衡失效。
下面是討論這個的一些文章:
問題:啟動服務時的競爭條件
有人 提到 使用 Kubernete DNS 時遇到的問題:他們有兩個同時啟動的容器,一旦啟動就會立即嘗試解析對方的地址。由於 Kubernete DNS 還沒有改變,所以 DNS 查詢會失敗。這個失敗會被緩存起來,所以後續的查詢會一直失敗。
寫在最後
我所列舉的不過是 DNS 問題的冰山一角,期待大家告訴我那些我沒有提到的問題和相關鏈接。我希望了解這些問題在實際中是如何發生的以及如何被解決的。
(題圖:MJ/f512f18e-2e1d-4614-bed1-b0a0c373e14d)
via: https://jvns.ca/blog/2022/01/15/some-ways-dns-can-break/
作者:Julia Evans 選題:lujun9972 譯者:toknow-gh 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive