当前位置:首页 > PHP教程 > php高级应用 > 列表

php之redis短线重连案例讲解

发布:smiling 来源: PHP粉丝网  添加日期:2022-05-11 10:35:00 浏览: 评论:0 

这篇文章主要介绍了php之redis短线重连案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下。

php 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 异常

  1. public static function getInstance( ) 
  2. { 
  3.     try { 
  4.         if (!self::$_instance) { 
  5.             new self(); 
  6.         } else { 
  7.             if (!self::$_instance->ping()) 
  8.                 new self(); 
  9.         } 
  10.     } catch (\Exception $e) { 
  11.         // 断线重连 
  12.         new self(); 
  13.     } 
  14.     return self::$_instance; 
  15. } 

实现2

1.调用ping之前先抛出个notice异常,

2.调用ping

3.用error_get_last获取最后一个错误,如果错误信息跟我们抛出的一样,说明ping通了,否则抛出个异常 ,让catch捕捉到执行重连,

当重连一次没连上再次调用$_instance->ping()会直接抛出Redis server went away异常让catch捕捉到

  1. public static function getInstance( ) 
  2. { 
  3.     if (!self::$_instance) { 
  4.         new self(); 
  5.     } 
  6.     else{ 
  7.         try { 
  8.             @trigger_error('flag', E_USER_NOTICE); 
  9.             self::$_instance->ping(); 
  10.             $error = error_get_last(); 
  11.             if($error['message'] != 'flag') 
  12.                 throw new \Exception('Redis server went away'); 
  13.         } catch (\Exception $e) { 
  14.             // 断线重连 
  15.             new self(); 
  16.         } 
  17.     } 
  18.     return self::$_instance; 
  19. } 

Redis类完整代码

  1. <?php 
  2. namespace lib; 
  3. class Redis 
  4. { 
  5.    
  6.     private static $_instance; //存储对象 
  7.     private function __construct( ){ 
  8.         $config = Config::get('redis'); 
  9.         self::$_instance = new \Redis(); 
  10.         //从配置读取 
  11.         self::$_instance->pconnect($config['host'], $config['port']); 
  12.         if ('' != $config['password']) { 
  13.             self::$_instance->auth($config['password']); 
  14.         } 
  15.    
  16.     } 
  17.     public static function getInstance( ) 
  18.     { 
  19.         if (!self::$_instance) { 
  20.             new self(); 
  21.         } 
  22.         else{ 
  23.             try { 
  24.                 @trigger_error('flag', E_USER_NOTICE); 
  25.                 self::$_instance->ping(); 
  26.                 $error = error_get_last(); 
  27.                 if($error['message'] != 'flag') 
  28.                     throw new \Exception('Redis server went away'); 
  29.             } catch (\Exception $e) { 
  30.                 // 断线重连 
  31.                 new self(); 
  32.             } 
  33.         } 
  34.         return self::$_instance; 
  35.     } 
  36.    
  37. //    public static function getInstance( ) 
  38. //    { 
  39. //        try { 
  40. //            if (!self::$_instance) { 
  41. //                new self(); 
  42. //            } else { 
  43. //                if (!self::$_instance->ping()) 
  44. //                    new self(); 
  45. //            } 
  46. //        } catch (\Exception $e) { 
  47. //            // 断线重连 
  48. //            new self(); 
  49. //        } 
  50. //        return self::$_instance; 
  51. //    } 
  52.  
  53.     /** 
  54.     * 禁止clone 
  55.     */ 
  56.     private function __clone(){} 
  57.    
  58.     /** 
  59.      * 其他方法自动调用 
  60.      * @param $method 
  61.      * @param $args 
  62.      * @return mixed 
  63.      */ 
  64.     public function __call($method,$args) 
  65.     { 
  66.         return call_user_func_array([self::$_instance, $method], $args); 
  67.     } 
  68.    
  69.     /** 
  70.      * 静态调用 
  71.      * @param $method 
  72.      * @param $args 
  73.      * @return mixed 
  74.      */ 
  75.     public static function __callStatic($method,$args) 
  76.     { 
  77.         self::getInstance(); 
  78.         return call_user_func_array([self::$_instance, $method], $args); 
  79.     } 
  80.  
  81. } 

调用

  1. $this->handler = Redis::getInstance(); 
  2.         $key    = $this->getCacheKey($name); 
  3.         $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不起作用,返回连接成功,而事实上已经断了,还是最早的那个连接,从而导致不能进行后续读取数据操作

所以长连接中请使用connect

Tags: redis短线重连

分享到: