PHP项目中redis断线重连怎样实现?

PHP 来源:KNOWSAFE 2023-03-24 18:51:54

在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();            } 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();            }        }        return 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->ping();                $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, $method], $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不起作用,返回连接成功,而事实上已经断了,还是最早的那个连接,从而导致不能进行后续读取数据操作,所以长连接中请使用connect。

    关于PHP项目中redis短线重连的实现就介绍到这,本文方法有一定的参考价值,感兴趣的朋友可以参考,希望能对大家有帮助,想要了解更多PHP的内容,大家可以关注其它的相关文章。


关注公众号:拾黑(shiheibook)了解更多

友情链接:

下软件就上简单下载站:https://www.jdsec.com/
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接