PHP使用Redis长连接的方法详解


Posted in PHP onFebruary 12, 2018

本文实例讲述了PHP使用Redis长连接的方法。分享给大家供大家参考,具体如下:

php-redis在github上的项目地址:https://github.com/phpredis/phpredis

pconnect函数声明

其中time_out表示客户端闲置多少秒后,就断开连接。函数连接成功返回true,失败返回false:

pconnect(host, port, time_out, persistent_id, retry_interval)
    host: string. can be a host, or the path to a unix domain socket
    port: int, optional
    timeout: float, value in seconds (optional, default is 0 meaning unlimited)
    persistent_id: string. identity for the requested persistent connection
    retry_interval: int, value in milliseconds (optional)

下面的例子详细介绍了pconnect连接的重用情况。

$redis->pconnect('127.0.0.1', 6379);
$redis->pconnect('127.0.0.1'); // 默认端口6379,跟上面的例子使用相同的连接。
$redis->pconnect('127.0.0.1', 6379, 2.5); // 设置了2.5秒的过期时间。将是不同于上面的新连接
$redis->pconnect('127.0.0.1', 6379, 2.5, 'x'); //设置了持久连接的id,将是不同于上面的新连接
$redis->pconnect('/tmp/redis.sock'); // unix domain socket - would be another connection than the four before.

pconnect使用介绍

对pconnect方法简单描述

使用该方法创建连接,连接不会在调用close方法之后关闭,只有在进程结束之后该连接才会被关闭。

[待验证]如果使用的是长连接,Redis配置文件中的timeout配置项需要设置为0,否则连接池中的连接会因为超时而失效

针对PHP-FPM来说明一下pconnect

长连接只会在PHP-FPM进程结束之后结束,连接的生命周期就是PHP-FPM进程的生命周期。
相比较短连接而言,在每一个PHP-FPM调用过程中都会产生一个redis的连接,在服务器上的表性形式就是过多的time_out连接状态。
而长连接相反,PHP-FPM调用的所有CGI都只会共用一个长连接,所以也就是只会产生固定数量的time_out。

关闭长连接

可以调用close和unset方法,但两则差异很大:

- close的作用仅仅是使当前PHP进程不能再进行redis请求,但无法真正关闭redis长连接,连接在后续请求中仍然会被重用,直FPM进程生命周期结束。所以close 并不会销毁redis对象,只是断开连接而已。

- unset 变量才会销毁。也需要注意并不是使用了 pconnect 就不要 close 了,如果当前脚本执行时间很长 那么也会一直占用一个连接的。

如何判断当前Redis是否处于连接状态

等效的问题是,在单例模式中,判断当前实例是否有效。

习惯上调用echo,判断是否正常返回字符串本身,或者调用ping,查看返回值是否为 +PONG。

但是需要特别小心的是,在redis断开连接之后,调用echo以及ping(返回'+POMG')时,均会抛出异常。所以要通过异常捕获机制来处理。

代码分析pconnect连接重用的问题

情况一:非单例模式。

说明:a实例和b实例共用了一条连接,b实例将a实例的连接修改了:
所以下面的例子导致最终$a实例得到的值变成了2,需要特别注意。

$a = pconnect(host, port, time_out);
select(3);
$a -> setex(id, 3);
echo $a -> get(id);
//之后执行下面的连接
$b = pconnect(host, port, time_out);
select(2);
$b->set(id,2)
echo $a->get(id);  //这个id操作的db变成了2,不再是之前的3了。因为这两个连接共用了一个连接通道。

情况二:单例模式。

将上述的代码修改,a和b都通过getInstance来生成。生成的前提是判断当前实例是否存在。单例模式的混淆点在于:

$a生成了一个实例,这时候生成$b, $b使用了$a的实例,然后修改了$a的连接,之后调用$a肯定是调用的$b修改之后的实例。跟情况二一致。
单例模式的代码如下:

public static function getInstance($db = 0)
{
  if (!isset(self::$_instance)) {
    self::$_instance = new Redis();
  }
  self::_connect();
  self::$_instance->select($db);
  return self::$_instance;
}

两种情况都说明了连接重用的问题。如何修复这个bug?两点:

1.为每一个db生成一个单例。
2.避免连接重用问题。

所以代码可以做调整为返回一个单例数组:

public static function getInstance($db = 0)
{
  try{
    if (isset(self::$_instance[$db]) && self::$_instance[$db]->Ping() == 'Pong') {
      return self::$_instance[$db];
    }
  } catch (Exception $e) {
  }
  self::$_instance[$db] = new Redis();
  self::_connect($db);
  return self::$_instance[$db];
}

需要注意的地方

避免在Task类成员变量中使用redis对象。

在redis的单例模式中,声明了time_out的过期时间。如果redis处理的场合是一个任务,而任务调用redis间隔时间又比较长。当间隔大于time_out时候,redis就会断开连接,这时候所有对redis的操作都会失效。解决的办法就是避免这种调用方式,通过在调用的地方动态声明redis类来执行。这种问题对于长连接和短链接是没有区分,属于调用的方式错误。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
用PHP连接Oracle for NT 远程数据库
Oct 09 PHP
PHP 命令行参数详解及应用
May 18 PHP
解析dedecms空间迁移步骤详解
May 15 PHP
PHP设计模式之迭代器模式的深入解析
Jun 13 PHP
浅析PHP Socket技术
Aug 02 PHP
php获取文件内容最后一行示例
Jan 09 PHP
php 判断字符串中是否包含html标签
Feb 17 PHP
详解PHP中的mb_detect_encoding函数使用方法
Aug 18 PHP
WordPress中访客登陆实现邮件提醒的PHP脚本实例分享
Dec 14 PHP
thinkPHP5框架auth权限控制类与用法示例
Jun 12 PHP
PHP+ajax实现二级联动菜单功能示例
Aug 10 PHP
php微信小程序解包过程实例详解
Mar 31 PHP
PHP长连接实现与使用方法详解
Feb 11 #PHP
搜索附近的人PHP实现代码
Feb 11 #PHP
PHP的RSA加密解密方法以及开发接口使用
Feb 11 #PHP
php+ajax实现无刷新文件上传功能(ajaxuploadfile)
Feb 11 #PHP
PHP实现的多维数组排序算法分析
Feb 10 #PHP
ThinkPHP整合datatables实现服务端分页的示例代码
Feb 10 #PHP
PHP实现APP微信支付的实例讲解
Feb 10 #PHP
You might like
PHP根据IP地址获取所在城市具体实现
2013/11/27 PHP
php抓取并保存网站图片的实现代码
2015/10/28 PHP
64位windows系统下安装Memcache缓存
2015/12/06 PHP
谈谈PHP中substr和substring的正确用法及相关参数的介绍
2015/12/16 PHP
laravel框架中路由设置,路由参数和路由命名实例分析
2019/11/23 PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
2020/02/28 PHP
JS原型对象通俗"唱法"
2012/12/27 Javascript
用JavaScript实现动画效果的方法
2013/07/20 Javascript
JavaScript实现文字与图片拖拽效果的方法
2015/02/16 Javascript
JavaScript中Math.SQRT2属性的使用详解
2015/06/14 Javascript
Web前端新人笔记之jquery入门心得(新手必看)
2016/05/17 Javascript
canvas绘制环形进度条
2017/02/23 Javascript
Node.js使用gm拼装sprite图片
2017/07/04 Javascript
通过js动态创建标签,并设置属性方法
2018/02/24 Javascript
微信小程序调用微信支付接口的实现方法
2019/04/29 Javascript
vue-i18n结合Element-ui的配置方法
2019/05/20 Javascript
vue.js iview打包上线后字体图标不显示解决办法
2020/01/20 Javascript
[04:09]2014DOTA2国际邀请赛Ti西雅图 历届冠军相继出局 BBC综述今日比赛
2014/07/20 DOTA
[47:39]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 LGD vs OPTIC
2018/03/31 DOTA
python自动格式化json文件的方法
2015/03/11 Python
简单易懂的python环境安装教程
2017/07/13 Python
基于pip install django失败时的解决方法
2018/06/12 Python
解决pycharm运行出错,代码正确结果不显示的问题
2018/11/30 Python
python感知机实现代码
2019/01/18 Python
详解使用python绘制混淆矩阵(confusion_matrix)
2019/07/14 Python
Python3.6 + TensorFlow 安装配置图文教程(Windows 64 bit)
2020/02/24 Python
小程序canvas中文字设置居中锚点
2019/04/16 HTML / CSS
政风行风整改报告
2014/11/06 职场文书
2014年银行客户经理工作总结
2014/11/12 职场文书
2015年师德表现自我评价
2015/03/05 职场文书
升职自荐信范文
2015/03/27 职场文书
送达通知书
2015/04/25 职场文书
2015年小学校长工作总结
2015/05/19 职场文书
合理缓解职场压力,让你随时保持最佳状态!
2019/06/21 职场文书
python lambda 表达式形式分析
2022/04/03 Python
Oracle 11g数据库使用expdp每周进行数据备份并上传到备份服务器
2022/06/28 Oracle