@鄭昀匯總
一. 現象:
Java HttpClient 從主站機房發起對××××的 open.×××.com 域名下 WebService 接口的 HTTP 請求,極其緩慢。
經排查:
1.1. wget 實測結果
不
指定 IP協議,wget 訪問它的接口,時間為 4.163 秒,基本浪費在解析主機的過程上。
如指定 wget 的 IP協議為IPV4,wget 測試則僅需 0.096 秒。
1.2. wget 對比測試:
不指定IP協議,wget 訪問另一個電商的接口,時間為 0.798 秒。
1.3. dig 解析 open.×××.com:
發現在解析 open.×××.com 的時候,會 CNAME 到一個全局變量中,再由這個全局變量選擇最優的線路提供訪問。
二. 有可能導致 Slow-DNS-Resolution 的原因:
1)
瀏覽器對××××的接口瀏覽快,不能證明什么。譬如火狐默認禁用了 ipv6 dns lookup:

2)Ubuntu 從 10.4 開始引入一個問題:操作系統默認啟用了 ipv6,導致一些應用程序發出 HTTP 請求時,在 ipv4 介入之前,總是先等待 ipv6 DNS lookup 超時(常有人報告需約30秒),這也是一個 DNS lookup 過程緩慢的常見原因。
3)也有人報告:『某一天運維部宣告公司網絡已經全部 enable IPv6 了,在此之后在使用 php 的 curl 函數或使用 Linux 下的 wget 訪問一個內部域名時,均發現需要等待大概 5 秒才能得到結果。原因是,沒有為這個域名綁定一個 IPv6 的地址,wget 時必須等 ipv6 DNS lookup 超時。現在很多服務器都開啟了 IPv6 卻沒有路由,無法真正工作,反而導致一些不可預料的問題。』
總之,此事應該與 ipv6-dns-lookup 有關。
三. 原因:
××××在網絡接入設備上做了調整,解決了問題。
原因:
1)××××使用了 F5 的 GTM 設備(GSLB,全局負載均衡),即我們常說的智能DNS。
2)它把
需要讓不同區域用戶訪問不同IDC節點的域名
通過 F5 的 GTM 來做解析。
3)可能它的設備默認啟用了 ipv6,但對於不同域名卻又沒有配置 ipv6 地址。
四. ipv6-dns-lookup 背景知識:
4.1. Java 平台下 ipv6 是如何工作的?
並非所有操作系統都支持 ipv6 協議,即使 Java networking stack 優先嘗試檢測它,並在發現可用時透明地使用它,也還可以利用系統屬性禁用它。在 ipv6 不可用或被顯式禁用的情況下,
Inet6Address
對大多數網絡連接操作都不再是有效參數。
『
第一步,
Java networking stack
先確認底層操作系統是否支持 ipv6。如果支持 ipv6 ,Java 將嘗試使用
ipv6 stack。
第二步,在
雙堆棧(dual-stack,指ipv4 stack+ipv6 stack)系統上,將創建一個 ipv6 socket。在
separate-stack
系統上,事情要復雜得多,Java 將創建兩個 socket,一個給 ipv4 一個給 ipv6。
第三步,對於客戶端 TCP 應用,一旦 socket 連上了,那
internet-protocol family type
就固定了,多余的那個 socket 就關閉了。對於服務器端 TCP 應用,由於不知道下一個客戶端請求用什么 ip family type,所以這兩個 sockets 將繼續保留。對於 UDP 應用,這兩個 sockets 始終都需要保留。
』
4.2. ipv6 相關的系統參數
系統有兩個參數:
1)首選的
協議棧:ipv4還是ipv6;
2)首選的
地址族(address family type):inet4 還是 inet6。
4.2.1. 協議棧
由於在一個雙堆棧系統上, ipv6 socket 能與 ipv4 和 ipv6 對端交互,所以
ipv6 stack 是默認首選項。
你可以通過如下系統參數修改配置:
java.net.preferIPv4Stack=<true|false>
對應的 java 代碼是:
java.lang.System.setProperty("java.net.preferIPv4Stack", "true");
4.2.2. 地址族
默認我們首選 ipv4 地址族。
你可以通過如下系統參數修改配置:
java.net.preferIPv6Addresses=<true|false>
對應的 java 代碼是:
java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");
4.3. Linux 上禁用 ipv6 的辦法:
Edit /etc/sysconfig/network. (A reboot will be required)
# vi /etc/sysconfig/network
Change:
NETWORKING_IPV6=yes
To:
NETWORKING_IPV6=no
Disable IPv6 Protocol Stack for Kernel
禁止IPV6的內核模塊
Edit /etc/modprobe.conf.
# vi/etc/modprobe.conf
Add the following 2 lines: (A reboot will be required)
alias net-pf-10 off
alias ipv6 off
4.4. F5 上 ipv6 相關設置:
據說,通過如下命令可以設置 BIG-IP 禁用 ipv6 :
bigpipe db Ipv6.Enabled false
bigpipe save all
BIG-IP 與 ipv6 有關的參數默認值如下所示:
Ipv6.Enabled = true
Ipv6.Nbr.DelayTime = 1
Ipv6.Nbr.IncompleteTimeout = 5
Ipv6.Nbr.MaxEntries = 2048
Ipv6.Nbr.ReachableTimeout = 30
Ipv6.Nbr.ReapTimeout = 3600
Ipv6.Nbr.Retries = 2
Ipv6.Nbr.DelayTime = 1
Ipv6.Nbr.IncompleteTimeout = 5
Ipv6.Nbr.MaxEntries = 2048
Ipv6.Nbr.ReachableTimeout = 30
Ipv6.Nbr.ReapTimeout = 3600
Ipv6.Nbr.Retries = 2
附錄A:
‘
-4’‘
--inet4-only’‘
-6’‘
--inet6-only’Force connecting to IPv4 or IPv6 addresses. With ‘
--inet4-only’ or ‘
-4’, Wget will only connect to IPv4 hosts, ignoring AAAA records in DNS, and refusing to connect to IPv6 addresses specified in URLs. Conversely, with ‘
--inet6-only’ or ‘
-6’, Wget will only connect to IPv6 hosts and ignore A records and IPv4 addresses.
參考資源:
1)2012,
curl_exec和wget執行太慢,IPv6惹的禍