php 使用redis锁限制并发访问类示例


Posted in PHP onNovember 02, 2016

本文介绍了php 使用redis锁限制并发访问类,并详细的介绍了并发访问限制方法。

1.并发访问限制问题

对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功。

例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制的情况下,用户则可以使用同一个换领码同时兑换到多张优惠券。

伪代码如下:

if A(可以换领)
    B(执行换领)
    C(更新为已换领)
D(结束)

如果用户并发提交换领码,都能通过可以换领(A)的判断,因为必须有一个执行换领(B)后,才会更新为已换领(C)。因此如果用户在有一个更新为已换领之前,有多少次请求,这些请求都可以执行成功。

2.并发访问限制方法

使用文件锁可以实现并发访问限制,但对于分布式架构的环境,使用文件锁不能保证多台服务器的并发访问限制。

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

本文将使用其setnx方法实现分布式锁功能。setnx即Set it N**ot eX**ists。

当键值不存在时,插入成功(获取锁成功),如果键值已经存在,则插入失败(获取锁失败)

RedisLock.class.PHP

<?php
/**
 * Redis锁操作类
 * Date:  2016-06-30
 * Author: fdipzone
 * Ver:  1.0
 *
 * Func:
 * public lock  获取锁
 * public unlock 释放锁
 * private connect 连接
 */
class RedisLock { // class start

  private $_config;
  private $_redis;

  /**
   * 初始化
   * @param Array $config redis连接设定
   */
  public function __construct($config=array()){
    $this->_config = $config;
    $this->_redis = $this->connect();
  }

  /**
   * 获取锁
   * @param String $key  锁标识
   * @param Int   $expire 锁过期时间
   * @return Boolean
   */
  public function lock($key, $expire=5){
    $is_lock = $this->_redis->setnx($key, time()+$expire);

    // 不能获取锁
    if(!$is_lock){

      // 判断锁是否过期
      $lock_time = $this->_redis->get($key);

      // 锁已过期,删除锁,重新获取
      if(time()>$lock_time){
        $this->unlock($key);
        $is_lock = $this->_redis->setnx($key, time()+$expire);
      }
    }

    return $is_lock? true : false;
  }

  /**
   * 释放锁
   * @param String $key 锁标识
   * @return Boolean
   */
  public function unlock($key){
    return $this->_redis->del($key);
  }

  /**
   * 创建redis连接
   * @return Link
   */
  private function connect(){
    try{
      $redis = new Redis();
      $redis->connect($this->_config['host'],$this->_config['port'],$this->_config['timeout'],$this->_config['reserved'],$this->_config['retry_interval']);
      if(empty($this->_config['auth'])){
        $redis->auth($this->_config['auth']);
      }
      $redis->select($this->_config['index']);
    }catch(RedisException $e){
      throw new Exception($e->getMessage());
      return false;
    }
    return $redis;
  }

} // class end

?>

demo.php

<?php
require 'RedisLock.class.php';

$config = array(
  'host' => 'localhost',
  'port' => 6379,
  'index' => 0,
  'auth' => '',
  'timeout' => 1,
  'reserved' => NULL,
  'retry_interval' => 100,
);

// 创建redislock对象
$oRedisLock = new RedisLock($config);

// 定义锁标识
$key = 'mylock';

// 获取锁
$is_lock = $oRedisLock->lock($key, 10);

if($is_lock){
  echo 'get lock success<br>';
  echo 'do sth..<br>';
  sleep(5);
  echo 'success<br>';
  $oRedisLock->unlock($key);

// 获取锁失败
}else{
  echo 'request too frequently<br>';
}

?>

测试方法:

打开两个不同的浏览器,同时在A,B中访问demo.php

如果先访问的会获取到锁

输出

get lock success
do sth..
success

另一个获取锁失败则会输出request too frequently

保证同一时间只有一个访问有效,有效限制并发访问。

为了避免系统突然出错导致死锁,所以在获取锁的时候增加一个过期时间,如果已超过过期时间,即使是锁定状态都会释放锁,避免死锁导致的问题。
源码下载地址:点击查看

PHP 相关文章推荐
用PHP连接MySQL代码的参数说明
Jun 07 PHP
php 中英文语言转换类代码
Aug 11 PHP
用PHP实现小写金额转换大写金额的代码(精确到分)
Jan 10 PHP
php上传apk后自动提取apk包信息的使用(示例下载)
Apr 26 PHP
配置php网页显示各种语法错误
Sep 23 PHP
php实现数组筛选奇数和偶数示例
Apr 11 PHP
CentOS 6.3下安装PHP xcache扩展模块笔记
Sep 10 PHP
thinkphp模板赋值与替换实例简述
Nov 24 PHP
php生成数字字母的验证码图片
Jul 14 PHP
php根据命令行参数生成配置文件详解
Mar 15 PHP
PHP whois查询类定义与用法示例
Apr 03 PHP
Yii框架组件的事件机制原理与用法分析
Apr 07 PHP
Android AsyncTack 异步任务实例详解
Nov 02 #PHP
php array_pop 删除数组最后一个元素实例
Nov 02 #PHP
PHP设置images目录不充许http访问的方法
Nov 01 #PHP
PHP递归获取目录内所有文件的实现方法
Nov 01 #PHP
php获得文件夹下所有文件的递归算法的简单实例
Nov 01 #PHP
ecshop适应在PHP7的修改方法解决报错的实现
Nov 01 #PHP
遍历echsop的region表形成缓存的程序实例代码
Nov 01 #PHP
You might like
PHP音乐采集(部分代码)
2007/02/14 PHP
PHP的autoload自动加载机制使用说明
2010/12/28 PHP
PHP写的获取各搜索蜘蛛爬行记录代码
2012/08/21 PHP
php中的ini配置原理详解
2014/10/14 PHP
PHP调试函数和日志记录函数分享
2015/01/31 PHP
服务器迁移php版本不同可能诱发的问题
2015/12/22 PHP
PHP获取ttf格式文件字体名的方法示例
2019/03/06 PHP
用JavaScript脚本实现Web页面信息交互
2006/12/21 Javascript
单击按钮显示隐藏子菜单经典案例
2013/01/04 Javascript
网页整体变灰白色(兼容各浏览器)实例
2013/04/21 Javascript
Mac地址验证的javascript代码
2013/11/09 Javascript
JS不间断向上滚动效果代码
2013/12/25 Javascript
javascript为下拉列表动态添加数据项
2014/05/23 Javascript
Javascript学习笔记之函数篇(四):arguments 对象
2014/11/23 Javascript
cocos2dx骨骼动画Armature源码剖析(三)
2015/09/08 Javascript
基于JavaScript实现表单密码的隐藏和显示出来
2016/03/02 Javascript
基于原生js淡入淡出函数封装(兼容IE)
2016/10/20 Javascript
Angular JS数据的双向绑定详解及实例
2016/12/31 Javascript
Angularjs通过指令监听ng-repeat渲染完成后执行脚本的方法
2016/12/31 Javascript
详解Nodejs之npm&amp;package.json
2017/06/15 NodeJs
JavaScript基础心法 数据类型
2018/03/05 Javascript
详解JavaScript 事件流
2020/09/02 Javascript
原生JavaScript实现五子棋游戏
2020/11/09 Javascript
在Django框架中设置语言偏好的教程
2015/07/27 Python
python运行时强制刷新缓冲区的方法
2019/01/14 Python
Python使用贪婪算法解决问题
2019/10/22 Python
pandas中遍历dataframe的每一个元素的实现
2019/10/23 Python
Python小整数对象池和字符串intern实例解析
2020/03/21 Python
python 动态渲染 mysql 配置文件的示例
2020/11/20 Python
英国领先的电视购物零售商:Ideal World
2019/03/18 全球购物
奶茶专卖店创业计划书
2014/01/18 职场文书
甜品店创业计划书
2014/09/21 职场文书
2019年暑期安全广播稿!
2019/07/03 职场文书
SQL中的三种去重方法小结
2021/11/01 SQL Server
Javascript中async与await的捕捉错误详解
2022/03/03 Javascript
win10频率超出范围怎么办?win10老显示超出工作频率范围的解决方法
2022/07/07 数码科技