php之redis短線重連案例講解
redis斷線重連,pconnect連線失敗問題
介紹
在swoole,workerman等cli長連線模式下,遇到Redis異常斷開,後面又開啟的情況,一般得重新啟動程式才能正常使用,
本文介紹在不重啟服務,實現原來的Redis斷線重連
原理
Redis 斷開的情況下呼叫
$Redis->ping()會觸發Notice錯誤,Notice: Redis::ping(): send of 14 bytes failed with errno=10054
當獲取redis例項時,如果ping不通或者出現異常,就重新連線
實現1
因為try catch 捕捉不到notice異常,所以ping不通直接重新連線,catch捕捉新連線的例項沒有連線上,下次執行ping觸發
Redis server went away 異常
public static function getInstance( ) { try { if (!self::$_instance) { new self(); http://www.cppcns.com } else { if (!self::$_instance->ping()) new self(); } } catch (\Exception $e) { // 斷線重連 new self(); } return self::$_instance; }
實現2
1.呼叫ping之前先丟擲個notice異常,
2.呼叫ping
3.用error_get_last獲取最後一個錯誤,如果錯誤資訊跟我們丟擲的一樣,說明ping通了,否則丟擲個異常 ,讓catch捕捉到執行重連,
當重連一次沒連上再次呼叫$_instance->ping()會直接丟擲Redis server went away異常讓catch捕捉到
public static function getInstance( ) { if (!self::$_instance) { new self(); } else{ try { @trigger_error('flag',E_USER_NOTICE); self::$_instance->ping(); $error = error_get_last(); if($error['message'] != 'flag') throw new \Exception('Redis server went away'); } catch (\Exception $e) { // 斷線重連 new self(); } } rehttp://www.cppcns.comturn self::$_instance; }
Redis類完整程式碼
<?php
namespace lib;
class Redis
{
private static $_instance; //儲存物件
private function __construct( ){
$config = Config::get('redis');
self::$_instance = new \Redis();
//從配置讀取
self::$_instance->pconnect($config['host'],$config['port']);
if ('' != $config['password']) {
self::$_instance->auth($config['password']);
}
}
public static function getInstance( )
{
if (!self::$_instance) {
new self();
}
else{
try {
@trigger_error('flag',E_USER_NOTICE);
self::$_instance->piYOfRpZsNAng();
$error = error_get_last();
if($error['message'] != 'flag')
throw new \Exception('Redis server went away');
} catch (\Exception $e) {
// 斷線重連
new self();
}
}
return self::$_instance;
}
// public static function getInstance( )
// {
// try {
// if (!self::$_instance) {
// new self();
// } else {
// if (!self::$_instance->ping())
// new self();
// }
// } catch (\Exception $e) {
// // 斷線重連
// new self();
// }
// return self::$_instance;
// }
/**
* 禁止clone
*/
private function __clone(){}
/**
* 其他方法自動呼叫
* @param $method
* @param $args
* @return mixed
*/
public function __call($method,$args)
{
return call_user_func_array([self::$_instance,$method],$args);
}
/**
* 靜態呼叫
* @param $method
* @param $args
* @return mixed
*/
public static function __callStatic($method,$args)
{
self::getInstance();
return call_user_func_array([self::$_instance,$args);
}
}
呼叫
$this->handler = Redis::getInstance(); $key = $this->getCacheKey($name); $value = $this->handler->get($key);
補充
pconnect建立連線後重連失敗問題
經測試長連線下使用pconnect建立連線後,redis超時被動斷開了連結,
$res = self::$_instance->pconnect($config['host'],$config['port']);
$res 會返回true,但不是新建的連結,呼叫$res-get()會報錯
原因
研究發現
使用pconnect,連結在php程序的整個生命週期內被重用, close的作用僅是使當前php不能再進行redis請求,但無法真正關閉redis長連線,連線在後續請求中仍然會被重用,直至fpm程序生命週期結束。
長連線中只有程序被停止,連線才會斷開,所以連線斷開時new不起作用,返回連線成功,而事實上已經斷了,還是最早的那個連線,從而導致不能進行後續讀取資料操作
所以長連線中請使用connhttp://www.cppcns.comect
到此這篇關於php之redis短線重連案例講解的文章就介紹到這了,更多相關php之redis短線重連內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!