Temporary failure in name resolution - DNS引發的問題和思考

weixin_33935777發表於2017-12-12

問題描述

由於公司業務需要,將之前部署在阿里雲上的Spring Boot應用遷移到了華為雲的VPC上,之前在阿里雲上應用基本上都是10秒內啟動且看不到任何告警資訊,遷移之後,不僅啟動速度變慢到2到3分鐘,且時常能在日誌中看到Temporary failure in name resolution的告警資訊。

715787-61ed89fdb7732528.png
以下是當前正在使用的伺服器環境
  • 伺服器: 華為雲VPC
  • 作業系統:CentOS 7
  • JDK版本: 1.8.0_151
  • SpringBoot版本: 1.5.8.Rlease
  • 容器: Embedded Tomcat 8.5.23

一開始對這個問題,是忽略的,由於本身應用屬於內部開發階段,且每天更新和部署不是那麼頻繁等等因素,一直遲遲沒有想去解決這個問題。不過最近因為臨近專案上線,提交也比較多,而且因為應用拆分和前後端分離的問題,本地除錯比較麻煩,所以開始著手解決這個問題。

問題調查

  1. 首先看到這個異常,確實第一感覺是域名解析出的問題,於是考慮是不是Tomcat的域名解析服務出的問題,修改了EmbeddedTomcat的配置


    715787-f31551f6448985e5.png

    修改之後測試發現問題依舊,去官網查了資料


    715787-d5b1563141a8c7f4.png

    其實Tomcat 8以後預設這個配置就是關閉的,這樣看來自然就不是問題的根源了。
  2. 重新梳理了一下思路,Spring Boot的初始化肯定是先於Tomcat的,所以應該是Spring Boot的初始化過程中出現了阻塞導致應用啟動過慢的問題。(不過要說明的是,知道此時並不確信是因為域名解析導致的阻塞,因為Spring Boot在啟動過程中並沒有丟擲任何異常)

先做了個測試,啟動Spring Boot應用的同時檢查53埠,此時應用處於假死狀態,應用和遠端的DNS伺服器正在通訊,基本可以斷定是因為呼叫了Jdk的InetAddress類的方法導致的問題。


715787-aaf99e3b05d2f44d.png

於是通過jstack定位當前阻塞的程式碼


715787-e300581dd014d278.png

715787-4cd096287609218b.png

問題已經顯而易見,Spring Boot在初始化的時候,執行了InetAddress的getLocalHost方法導致程式阻塞而影響了應用的啟動時間。
715787-245d696d9d542b5b.png
SpringApplication

715787-7a837fb38ba6c8ca.png
LoggingApplicationListener

715787-9c1fc566ecce64fc.png
LoggingSystemProperties

715787-121d5dca8a2c1034.png
ApplicationPid

715787-71cd55d3c5ae103d.png
VMManagementImpl

又檢視了一下當前伺服器的DNS配置


715787-c4b7a0118a2fdc40.png

可以看到DNS伺服器的地址是公網的DNS地址,VPC訪問不到導致取主機名的方法發生阻塞,因此導致應用啟動時間非常長

問題解決

跟最初推測的差不多,確實是域名解析的問題,不過意外的是在Spring Boot初始化的時候獲取VMID的時候會獲取當前伺服器的主機名。於是在/etc/resolve.conf中新增了本地主機的解析記錄並刪除無法訪問的公網DNS配置,現在應用的啟動已經和本地一樣了

問題反思

雖然最開始就定位了問題是DNS,不過發生問題的根源一直沒有確定,也不想只是簡單的把DNS配置修改來立刻解決問題,畢竟希望究本溯源,不希望被表面的問題所迷惑。
於是又檢視了JDK的原始碼,發現InetAddress#getLocalHost是個本地方法


715787-f03c33cdb5630ebf.png
InetAddress

715787-8d032b2156f36fda.png
Inet4AddressImpl

本地方法也難不倒我們,下載了openjdk的原始碼找到對應的C原始碼


715787-a4f9db6ca900ea01.png

715787-ecf0864fe1ab9d51.png

這個方法來自於jvm.cpp裡面的方法
715787-ff4a4f1464f701a6.png

715787-20ebb6a1a236d2c6.png

雖然對C表示不熟,不過基本能看出來是呼叫系統庫的API來獲取的主機名,順便也查詢了一下是說這個系統庫本身設計的就不好,屬於同步呼叫,在網路不通的情況下會導致嚴重的超時問題。

同時不免想對華為雲吐槽幾句,伺服器裝個圖形介面版的CentOS就不說了,起碼給個內網的DNS伺服器啊,完全是沒有經過任何配置優化的作業系統,期待更進一步的改進。

相關文章