phpredis subscribeタイムアウト問題と解決

5684 ワード

問題の説明
redisはpub/sub機能を提供していますが、phpredisのsubscribeを使用すると、次のような問題が見つかりました(sub.php).

/*  demo  ,       */
function process($redis, $chan, $msg){
    var_dump($msg);
}

$redis = new Redis();
$res = $redis->connect('127.0.0.1', '7979');
$redis->subscribe(array('demo'), 'process');

コードが実行されると、demoチャンネルからのメッセージが一定期間受信されていない場合、次のエラーが表示されます.
PHP Fatal error:  Uncaught exception 'RedisException' with message 'read error on connection' in sub.php:11
Stack trace:
#0 /search/ballqiu/sub.php(11): Redis->subscribe(Array, 'process')
#1 {main}
  thrown in sub.php on line 11

原因分析
理由を調べるためにstraceを使用してコードを追跡しました.
strace php sub.php

切り取り部分の重要な出力は次のとおりです.
//  redis
connect(3, {sa_family=AF_INET, sin_port=htons(7979), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
//  subscribe  
sendto(3, "subscribe  demo\r
"
, 17, MSG_DONTWAIT, NULL, 0) = 17 // recvfrom(3, "*3\r
$9\r
subscribe\r
$4\r
demo\r
:1\r"
..., 8192, MSG_DONTWAIT, NULL, NULL) = 33 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout) // 60s poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 0 (Timeout) // , close(3) = 0 // write(2, "PHP Fatal error: Uncaught excep"..., 261PHP Fatal error: Uncaught exception 'RedisException' with message 'read error on connection'

エラーの本質はpoll設定受信タイムアウトによるものであり,starceの結果からこのタイムアウトのデフォルトは60 sであることが分かった.
解決する
タイムアウトを変更する方法は2つあります.方法1はコードの先頭で設定します.
ini_set('default_socket_timeout', -1);
  • メソッド2 redis connect後に
  • を実行
    $redis->setOption(Redis::OPT_READ_TIMEOUT, -1);

    どちらの方法の-1もタイムアウトしないことを示し、タイムアウトを自分の希望する時間に設定することもできます.いずれの方法を使用しても、再びstraceを使用すると、pollのタイムアウトが-1に設定されていることがわかります.
    recvfrom(3, "*3\r
    $9\r
    subscribe\r
    $4\r
    demo\r
    :1\r"
    ..., 8192, 0, NULL, NULL) = 33 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout) // -1, poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, -1

    個人的におすすめの方法2は、redis自体にのみ影響します.メソッド1は、file_などの他のメソッドに影響を与えます.get_contentsなど.
    まとめ
    phpredisのsubscribeを使用すると、デフォルト60でメッセージが受信されず、sub側はタイムアウト異常で終了します.タイムアウト時間を延長するか、タイムアウトしないかを自分で設定できます.