php使用redis简单实现分布式锁加排队队列用于秒杀等场景

百度了几天自己总结了下写了一个类,里面有加锁、解锁和入队的操作,异步的减库存出队等的操作还没有写,写好了我再重新编辑

用apache的ab测试-n 500 -c  100测试了下没有出现超卖的情况

这段代码没有在项目里使用过,所以大家有觉得哪里有问题请指出,我们一起讨论完善这个代码

 

<?php
class RedisLock{
	function __construct(){
		$r = new \Redis();
    	$r->pconnect('127.0.0.1', '6379');
    	$this->redis = $r;

    	$this->timeout = 3;

    	$this->good_stock_queue = "good_stock_queue_";
    	$this->joined_queue = "joined_queue_";
    	$this->uid_queue = "uid_queue";

	}
	function get_set_by_name($name,$type=''){
		$rs = $this->redis;
		if($type == 'zset'){
			return $rs->zrange($name,0,-1);
		}
		return $rs->get($name);
	}
	//初始化库存队列
	function init_goodstock_queue($num,$gid){
		$rs = $this->redis;
		$rs->del($this->good_stock_queue.$gid);
		for ($i=0; $i < $num; $i++) { 
			$rs->lpush($this->good_stock_queue.$gid,1);
		}
		$result = $rs->llen($this->good_stock_queue.$gid);
		if($result){
			return true;
		}
		return false;
	}
	//加锁操作
	function add_lock($key,$timeout=null,$waitsec = 100000){
		
		$rr = $this->redis;

		$lock_name = $this->get_lock_name($key);
		$timeout = $timeout ? $timeout : $this->timeout;
		$time = time();
		$expire_time = $time + $timeout;
		
		$get_lock = $rr->setnx($lock_name,$expire_time);
		if($get_lock){
			return $expire_time;
		}

		while(1){
			usleep($waitsec);

			$old_expire_time = $rr->get($lock_name);
			//如果锁的生存时间未过期,继续获取
			if($old_expire_time >= time()){
				continue;
			}

			$new_expire_time = time() + $timeout;
			$last_expire_time = $rr->getset($lock_name,$new_expire_time);
			//继续尝试获取,如果与上一个锁的score不一致,可能是其他请求获取到了锁,则继续
			if($last_expire_time != $old_expire_time){
				continue;
			}
			$get_lock = $new_expire_time;
			break;
		}

		return $get_lock;
		
		// dump($rr->get('ok'));
	}

	//释放锁
	function release_lock($key,$score){

		$rr = $this->redis;
		$lock_name = $this->get_lock_name($key);

		if($score < time()){
			if($rr->del($lock_name)){
				return true;
			}
		}
		return false;
	}


	//获取锁名
	function get_lock_name($key){
		return "lock_".$key;
	}

	//入队
	function enqueue($uid,$gid){

		$rr = $this->redis;

		//判断是否再已参与的队列中
		$is_joined = $rr->get($this->joined_queue.$gid, $uid);
		// dump($is_joined);
		if(!$is_joined){
			//判断库存队列
			$stock_num = $rr->llen($this->good_stock_queue.$gid);
			// dump($stock_num);
			if($stock_num){
				//入队
				$time_score = time();
				$uid_queue_len = $rr->zcard($this->uid_queue);
                //这里为了测试假定只接受10个人参加秒杀
                
                
				if($uid_queue_len < 10){
					$se = $rr->zadd($this->uid_queue, $time_score,$uid);
				}
				
				
				// $rr->lpop($this->good_stock_queue.$gid);
				return true;
			}
		}
		return false;
	}

	//出队
	function dequeue(){

	}
}


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值