最近、私たちのサービスは PHP で使用される libcurl をアップグレードしています。新しいバージョンの libcurl はミリ秒のタイムアウトをサポートし、バックエンド インターフェイスのタイムアウトをより正確に制御できるようになり、全体的な応答時間が向上することが期待されています。
ただし、CentOS サーバーでは、タイムアウトを 1000 ミリ秒未満に設定すると、curl はリクエストを開始せず、直接タイムアウト エラー (タイムアウトが 28 に達しました) を返すことがわかりました。
ここに落とし穴があることがわかりました。Linux システムでは、システム標準の DNS 解決が使用される場合、SIGALARM がドメイン名解決のタイムアウトを制御する機能を使用します。ただし、SIGALARM はタイムアウトをサポートしません。 1 秒未満なので、libcurl 7.28.1 のコード内 (中国語のコメント行に注意してください):
int Curl_resolv_timeout(struct connectdata *conn,
-
const char *ホスト名,
-
int ポート、
-
struct Curl_dns_entry **エントリ,
-
長いタイムアウト)
-
{
-
......
-
......
-
#ifdef USE_ALARM_TIMEOUT
-
if(データ->set.no_signal)
-
/* シグナルが無効な場合はタイムアウトを無視します */
-
タイムアウト = 0;
-
それ以外
-
タイムアウト = timeoutms;
-
-
if(!タイムアウト)
-
/* USE_ALARM_TIMEOUT が定義されていますが、実際にはタイムアウトは要求されていません */
-
Return Curl_resolv(conn, ホスト名, ポート, エントリ);
-
-
if(timeout
-
/*alarm() 関数は整数の秒分解能のみを提供するため、if
-
1 秒以内に待機したいので、今すぐ救済する必要があります */
。
-
CURLRESOLV_TIMEDOUT を返します;
-
-
....
-
....
-
タイムアウトが 1000 ミリ秒未満の場合、名前分析は直接 CURLRESOLV_TIMEOUT を返し、最終的には CURLE_OPERATION_TIMEDOUT につながり、その後エラー、タイムアウトに達しました...
が表示されることがわかります。
これは不正すぎませんか? ミリ秒タイムアウトを使用できないのですか? では、なぜこの機能を提供するのでしょうか?
もう一度コードを見てみましょう。先ほどと同じコードです。ここ (中国語のコメント行) に注目してください:
リーリー
#ifdef USE_ALARM_TIMEOUT-
if(data->set.no_signal) //この行に注目してください-
/* シグナルが無効な場合はタイムアウトを無視します */-
タイムアウト = 0;-
それ以外-
タイムアウト = timeoutms;-
-
if(!タイムアウト)-
/* USE_ALARM_TIMEOUT が定義されていますが、実際にはタイムアウトは要求されていません */-
Return Curl_resolv(conn, ホスト名, ポート, エントリ);-
-
if(タイムアウト
/*alarm() 関数は整数の秒分解能のみを提供するため、if-
1 秒以内に待機したいので、今すぐ救済する必要があります */- 。
CURLRESOLV_TIMEDOUT を返します;-
set.no_signal が 1 であれば回避できるようですが… では、これは何でしょうか?
これは簡単です。コードを grep して見つけます:
リーリー
ケース CURLOPT_NOSIGNAL:-
/*-
* アプリケーションは、signal() ハンドラーまたは Alarm() ハンドラーを設定しないように要求します-
* タイムアウトを使用している場合でも。-
*/-
data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE;-
休憩-
ハハ、それはこの男であることが判明しました:
リーリー
curl_setopt($ch, CURLOPT_NOSIGNAL, 1);-
?>-
この OPT を追加した後、最終的にすべてが正常になりました!
追記:
このように、DNS 解決にはタイムアウト制限が適用されないという潜在的な危険が存在します。これは社内では通常問題になりませんが、DNS サーバーがハングするとアプリケーションのタイムアウトが発生する可能性があります。
それで、他に方法はありますか?
はい、Mike が思い出させてくれたように、名前解決に libcurl に c-ares (非同期 DNS リクエスト用の C ライブラリ) を使用させることができます。具体的には、curl を設定できます。
リーリー
./configure --enable-ares[=PATH]
-
この方法では、NOSIGNAL を設定する必要はありません
PS、なぜこれが「バグ」と呼ばれるのですか? ちょっと興味があるのですが、なぜ setitimer を使用しないのですか?
参照: http://stackoverflow.com/questions/7987584/curl-timeout-less-than-1000ms-always-fails
作者: ラルーエンス
この記事のURL:http://www.laruence.com/2014/01/21/2939.html
http://www.bkjia.com/PHPjc/735044.html
www.bkjia.comtruehttp://www.bkjia.com/PHPjc/735044.html技術記事最近、私たちのサービスは PHP で使用される libcurl をアップグレードしています。新しいバージョンの libcurl はミリ秒のタイムアウトをサポートし、バックエンド インターフェイスのタイムアウトをより正確に制御できるようになり、それによって全体的な応答が向上することが期待されています...