文档章节

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

豆花饭烧土豆
 豆花饭烧土豆
发布于 08/18 06:45
字数 1003
阅读 5
收藏 0

1.并发访问限制问题

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

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

伪代码如下:

if A(可以换领)

    B(执行换领)

    C(更新为已换领)

D(结束)

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

2.并发访问限制方法

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

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 
本文将使用其setnx方法实现分布式锁功能。setnxSet it Not eXists。 
当键值不存在时,插入成功(获取锁成功),如果键值已经存在,则插入失败(获取锁失败)

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>';
}

?>
//设置锁,防止多个用户并发操作连麦超出数量限制 
        $lock = $redis->lock($lockKey); 
        if(!$lock) { 
            for($i=0;$i<3;$i++){ //重试3次,如果3次还未获取倒锁提示繁忙 
                $lock = $redis->lock($lockKey); 
                if($lock){ 
                    break; 
                } 
                sleep(1); 
            } 
            if(!$lock){ 
                return; 
            } 
        } 
  
        doAction..... //获取到了锁,做自己的业务

测试方法: 
打开两个不同的浏览器,同时在A,B中访问demo.php 
如果先访问的会获取到锁 
输出 
get lock success 
do sth.. 
success

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

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

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

转载:https://blog.csdn.net/fdipzone/article/details/51793837

© 著作权归作者所有

共有 人打赏支持
豆花饭烧土豆
粉丝 15
博文 354
码字总数 93005
作品 0
深圳
私信 提问
Redis 的 8 大应用场景!

之前讲过Redis的介绍,及使用Redis带来的优势,这章整理了一下Redis的应用场景,也是非常重要的,学不学得好,能正常落地是关键。 下面一一来分析下Redis的应用场景都有哪些。 1、缓存 缓存现...

Java技术栈
08/29
0
0
redis分布式锁

关于分布式锁的概念网上太多了,这里就不罗嗦了。对于开发者来说,最关心的应该是什么情况下使用分布式锁。 使用分布式锁,一般要满足以下几个条件: · 分布式系统(关键是分布式) · 共享资...

明舞
2015/10/16
5.7K
3
redis学习笔记二

http://redisbook.readthedocs.io/en/latest/ redis为什么会有高并发问题 redis的出身决定 redis是一种单线程机制的nosql数据库,基于key-value,数据可持久化落盘。由于单线程所以redis本身...

writeademo
2016/09/14
26
0
jedisLock—redis分布式锁实现

搬运工:http://www.cnblogs.com/0201zcr/p/5942748.html jedisLock—redis分布式锁实现 一、使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以使用Reentrant...

北极之北
2017/01/06
849
2
php redis实现秒杀功能

主要针对并发情况下,通过redis的分布式锁和队列的方式进行处理的代码 Queue:{商品ID}: 数据类型是有序集合(zset),成员是用户ID,score是用户入队的时间戳 Lock:Queue:{商品ID}: 数据类型...

RitaChen
2016/11/17
77
0

没有更多内容

加载失败,请刷新页面

加载更多

Sentry使用

Sentry使用 以django为例.实际上sentry本身文档已经有介绍了.这里只是再总结 1、全局异常捕获 此方法可以全局捕获任何的异常(甚至包括你自己raise的异常),在实际使用过程中不太推荐.但胜在快...

_Change_
15分钟前
0
0
linux系统包管理工具详解 yum rpm apt-get pip wget

在Linux系统下,根据系统版本的不同会有各种各样的包管理工具,下面就简单的梳理一下这几种安装命令. 1、yum Yum(全称为 Yellow dog Updater, Modified)是一个在Fedora、RedHat、CentOS中的...

huoyoung
19分钟前
0
0
阿里巴巴Dubbo实现的源码分析

1. Dubbo概述 Dubbo是阿里巴巴开源出来的一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及作为SOA服务治理的方案。它的核心功能包括: #remoting:远程通讯基础,提...

别打我会飞
20分钟前
3
0
tomcat的maxThreads、acceptCount(最大线程数、最大排队数)

tomcat 6的Connector配置如下: <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxThreads......

为了美好的明天
23分钟前
1
0
阿里P9架构师谈:高并发网站的监控系统选型、比较、核心监控指标

在高并发分布式环境下,对于访问量大的业务、接口等,需要及时的监控网站的健康程度,防止网站出现访问缓慢,甚至在特殊情况出现应用服务器雪崩等场景,在高并发场景下网站无法正常访问的情况...

架构师springboot
23分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部