今天在使用 php 的 curl 函數時,發現需要等待大概 5 秒才能得到結果,實在是太慢了。而同樣一個 url 使用浏覽器訪問,則立刻可以獲得頁面。後來又發現,即使不用 php,使用 Linux 下的原生命令 wget 去獲取網頁,也很慢。這真是太奇怪了,看上去不是程序的原因,而是網絡設置的問題了。
執行 wget 時可以明顯看到,阻塞發生在 DNS 域名解析的部分。
$ wget www.myproject.com
--2012-06-18 12:17:30-- http://www.myproject.com/
Resolving www.myproject.com... # 此處停滯約 5 秒
192.168.1.187
Connecting to www.myproject.com|192.168.1.187|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: index.html?
[ <=> ] 5,200 --.-K/s in 0s
2012-06-18 12:17:35 (264 MB/s) - index.html saved [5200]
我使用的是開發環境,域名解析到一個內部 IP 上。奇怪的是,我使用 ping www.myproject.com 卻很快可以獲得 IP 地址並返回 ICMP 報文。為什麼 wget 的 DNS 解析會這麼慢呢?www.2cto.com
Google 到 StackOverflow 上面也有很多人提這個問題,有說是 reverse DNS 反向域名解析的問題,有說要在 host 文件中添加那個域名……都無法解決我的問題。百思不得其解之際,突然想到上周是 IPv6 日,我們運維發過一封郵件說公司網絡已經全部 enable IPv6 了。會不會是這個原因呢?按照這個線索去查,果然,豁然開朗了。
$ wget -4 www.myproject.com
瞬間就返回了結果。看來是運維沒有幫我們為這個域名綁定一個 IPv6 的地址,整個網絡升級後,默認會優先解析 IPv6,在那個 domain 沒有 IPv6 的情況下,會等待 IPv6 解析失敗 timeout 之後才按以前的正常流程去找 IPv4。
對於 PHP curl 來講,只需要加上下面一句即可解決延遲問題:
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
現在很多服務器都開啟了 IPv6 卻沒有路由,無法真正工作,反而導致一些不可預料的問題。深切地體會到 IPv6 路漫漫啊……