当前位置:首页 > 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.     try { 
  3.         if (!self::$_instance) { 
  4.             new self(); 
  5.         } else { 
  6.             if (!self::$_instance->ping()) 
  7.                 new self(); 
  8.         } 
  9.     } catch (\Exception $e) { 
  10.         // 断线重连 
  11.         new self(); 
  12.     } 
  13.     return self::$_instance

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

Redis类完整代码

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

调用

  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短线重连

分享到: