业务上的一些重要接口,比如提现,转账,支付等,很容易被人恶意访问此接口。
他们最常用的一种方法就是,同一时间内发送多次请求,造成瞬间高并发现象,以此来绕过金额的判断或者其他判断逻辑,即使使用事务也是不行的。
下面是我日常使用的并发锁和限流
<?php
namespace app\common\library;
class Lock
{
private static $_instance;
private $_redis;
private function __construct()
{
if (! extension_loaded('redis')) {
throw new \Exception('not support: redis');
}
$this->_redis = new \Redis();
$this->_redis->connect('127.0.0.1');
}
public static function getInstance()
{
if (self::$_instance instanceof self) {
return self::$_instance;
}
return self::$_instance = new self();
}
public static function limitRate($key, $limit, $second = 10)
{
$check = self::getInstance()->_redis->exists($key);
if ($check) {
self::getInstance()->_redis->incr($key);
$count = self::getInstance()->_redis->get($key);
if ($count > $limit) {
return false;
}
} else {
self::getInstance()->_redis->incr($key);
self::getInstance()->_redis->expire($key, $second);
}
return true;
}
public static function lock($key, $expire = 5)
{
$objRedisConn = self::getInstance();
$is_lock = $objRedisConn->_redis->setnx($key, time() + $expire);
if (! $is_lock) {
$lock_time = $objRedisConn->_redis->get($key);
if (time() > $lock_time) {
$objRedisConn->unlock($key);
$is_lock = $objRedisConn->_redis->setnx($key, time() + $expire);
}
}
return $is_lock ? false : true;
}
public static function unlock($key)
{
return self::getInstance()->_redis->del($key);
}
}