1.redis 分布式锁 (RedisLuckService)
<?php
namespace App\Models\service;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Log;
class RedisLuckService
{
const LUCK_SUCCESS = "OK";
const IF_NOT_EXISTS = "NX";
const MILLISECOND_EXPIRE_TIME = "EX";
const EXPIRE_TIME = 50; //50秒
/**
* 加锁
* @param $key
* @param $uid
* @param $expire_time
* @return bool
*/
public function lock($key,$uid,$expire_time= '')
{
if(empty($expire_time)){
$expire_time = self::EXPIRE_TIME;
}
$result = Redis::set($key,$uid,self::MILLISECOND_EXPIRE_TIME,$expire_time,self::IF_NOT_EXISTS);
if($result == self::LUCK_SUCCESS){
return true;
}else{
return false;
}
}
/**
* 释放锁
* @param $key
* @param $uid
* @return bool
*/
public function unlock( $key, $uid)
{
$lua =<<<LUA_SCRIPT
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
LUA_SCRIPT;
$result = Redis::eval($lua,1,$key,$uid);
return $result;
}
}
2.模拟并发数据
function redisLuck()
{
$redisLuck = new RedisLuckService();
$uid = $this->userGroup[array_rand($this->userGroup, 1)];
$key = 'redisLuck';
try {
if (!$redisLuck->lock($key, $uid, 4)) {
$this->setLogs("当前业务繁忙,请稍后==>" . time());
return "当前业务繁忙,请稍后";
} else {
$shopInfo = $this->getShopInfo(1);
if ($shopInfo->number > 0) {
DB::beginTransaction();
$this->updateShopInfo($shopInfo->id);
$this->addSeckillLog($uid, $shopInfo->id);
Db::commit();
$this->setLogs("{$uid}抢购成功");
} else {
$this->setLogs("库存不足");
}
$redisLuck->unlock($key, $uid);
$this->setLogs("{$uid}锁已经释放");
}
} catch (\Exception $exception) {
$redisLuck->unlock($key, $uid);
$this->setLogs("异常:" . $exception->getMessage());
}
}
3.采用 ab 测试对接口模拟
ab -n 1000 -c 900 http://域名/seckill/redisLuck