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 使用redis锁限制并发访问类的更多相关文章
- (实例篇)php 使用redis锁限制并发访问类示例
1.并发访问限制问题 对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功. 例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制 ...
- PHP进阶与redis锁限制并发访问功能示例
<?php /** * Redis锁操作类 * Date: 2017-06-30 * Author: fdipzone * Ver: 1.0 * * Func: * public lock 获取 ...
- redis锁处理并发问题
redis锁处理并发问题 redis锁处理高并发问题十分常见,使用的时候常见有几种错误,和对应的解决办法. set方式 setnx方式 setnx+getset方式 set方式 加锁:redis中se ...
- [转]高并发访问下避免对象缓存失效引发Dogpile效应
避免Redis/Memcached缓存失效引发Dogpile效应 Redis/Memcached高并发访问下的缓存失效时可能产生Dogpile效应(Cache Stampede效应). 推荐阅读:高并 ...
- 对象及变量的并发访问(同步方法、同步代码块、对class进行加锁、线程死锁)&内部类的基本用法
主要学习多线程的并发访问,也就是使得线程安全. 同步的单词为synchronized,异步的单词为asynchronized 同步主要就是通过锁的方式实现,一种就是隐式锁,另一种是显示锁Lock,本节 ...
- 【重学Java】多线程进阶(线程池、原子性、并发工具类)
线程池 线程状态介绍 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.线程对象在不同的时期有不同的状态.那么Java中的线程存在哪几种状态呢?Java中的线程 状态被定 ...
- oracle的锁与并发机制
锁是并发访问的时候用于保护不共享资源不被同时并发修改的机制.oracle锁分为DML锁,DDL锁,内部锁和latch DML锁确保一次只能只有一个人修改某一行(TX锁),而且正在处理一个表时别人不能删 ...
- java 多线程: Thread 并发访问-代码块同步synchronized {};String作为被锁的对象
方法同步的弊端 方法同步的时候,如果一个方法需要线程安全控制的代码速度其实很快,但是还有其他的业务逻辑代码耗时非常长(比如网络请求),这样所有的线程就在这一块就等待着了,这样造成了极大的资源浪费如果并 ...
- redis 初步认识四(redis锁,防并发)
using System; namespace ConsoleAppRedis { class Program { static void Main(string[] args) { //第一种,无登 ...
随机推荐
- Redis学习——环境搭建以及基础命令使用
0. 前言: 这篇文章旨在对redis环境的搭建以及对redis有个大概的认识. 一.redis搭建: 环境:ubuntu 14 软件包:redis-3.0.3.tar.gz 安装步骤: 1. 首先解 ...
- Ubuntu如何以root身份登陆-(基于14.04版本)
1.打开terminal,输入命令 $ sudo passwd root 键入密码, 重复确认, 2.然后再次在终端模式下进入root, $ sudo -s -H 键入密码 # vi /usr/sh ...
- C#使用百度API通过IP获取地理位置和坐标
百度接口相关说明:http://developer.baidu.com/map/ip-location-api.htm 返回是json格式,首先构建相关反系列化类: #region AddressFo ...
- salt stack 工具之一——远程命令
salt stack 远程命令 salt stack是一种自动化的运维工具,可以同时对N台服务器进行配置管理.远程命令执行等操作. salt stack分为两个部分: salt-master,部署在控 ...
- Python之路【第十六篇续】Django进阶篇
Django请求生命周期 首先:对于所有的web框架来说本质就是一个socket服务端,浏览器是socket客户端 路由系统 在Django的urls中我们可以根据一个URL对应一个函数名来定义路由规 ...
- Apache日志配置详解(rotatelogs LogFormat)
logs/error_logCustomLog logs/access_log common--默认为以上部分 修改为如下: ErrorLog "|/usr/sbin/rotatelogs ...
- Java多线程编程核心技术---对象及变量的并发访问(一)
synchronized同步方法 "非线程安全"其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是"脏读",也就是渠道的数据其实是被更改 ...
- APACHE POI教程 --java应用程序用POI与Excel交互
POI报表 --用POI与Excel交互 AURISOFT 第一章 POI简介 --Jakata Poi HSSF:纯java的Excel解决方案 在我们实际的开发中,表现层的解决方案虽然有多样,但是 ...
- 关于在windows上的wamp集成环境和xampp上安装mongo扩展
今天来学习下mongodb,在装PHP扩展的时候本来是一个很轻松的事情,结果并不是我想想的那么简单. 我的集成环境是xampp的php版本是5.6的x86.我开启了安全模式,所以我需要mongo时ts ...
- php开发总结
./configure --prefix=/usr/local/php --with-apxs2=/usr/local/apache2/bin/apxs --with-mysql=shared,mys ...