你的 CURL 請求超時了嗎?
背景:伺服器上線了一個事件推送的功能。即主伺服器系統產生的一些充值與下單的操作,會把這些動作訊息推送給指定的活動伺服器。我們採用的是 CURL 請求。但是,上線一段時間內發現訊息吞吐很小,有時間還伴隨請求超時。
一、一個再正常不過的 PHP CURL 程式碼示例:
<?php $data = ['code' => 'buy', 'userid' => '123456', 'money' => 30000]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://www.xxx.com/event.php"); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($ch, CURLOPT_POSTFIELDS , $data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); echo $output; curl_close($ch);
但是,在我們的線上出現了這樣一個錯誤:name lookup timed out
通過了解,發現這是一個與 DNS 解析有誤的錯誤。
DNS 解析時間耗時
curl -o /dev/null -s -w %{time_namelookup} www.baidu.com
二、DNS 與 IPV6 以及解決方案
因為,我們的伺服器採用的是 CentOS 7。而預設情況下 CentOS 系統是開啟了 IPV6 支援的。這就導致了 PHP 的 CURL 發起請求的時候,Linux 的 CURL 庫會首先嚐試 IPV6 網路去解析域名。但是,目前很多的 DNS 都不支援 IPV6。就導致瞭解析超慢或超時的情況。
既然,我們知道了是因為 DNS 不支援 IPV6 導致的問題。那麼,要解決這個問題有必須做如下操作:
- 換一個支援 IPV6 的 DNS
- 關閉 Linux 系統的 IPV6
- PHP 程式碼中強制使用 IPV4
(1) 換一個支援 IPV6 的 DNS
通過網路上的方案,是換成如下 DNS:
nameserver 114.114.114.114 nameserver 8.8.8.8
這個我沒有試驗過。我們採用的是關閉 Linux IPV6
(2) 關閉 Linux 系統的 IPV6
直接關閉 IPV6 是最容易的一件事情了。
編輯/etc/sysctl.conf
# vim /etc/sysctl.conf
新增
IPv6 disabled
net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1
使其生效
# sysctl -p
(3) PHP 程式碼中強制使用 IPV4
在 PHP 5.3 版本開始才支援。
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
即使你的 PHP 大於 5.3 版本,也要保證 Linux 系統的 CURL 版本大於等於 7.10.8 版本。
當然,超時除了 DNS 超時,有可能你的系統程式碼也會超時。這就需要你自己去解決了。