分布式锁
代码实现:
加锁与解锁:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Redis;
class RedisLockService
{
const LOCK_SUCCESS = 'OK';
const IF_NOT_EXISTS = 'NX'; //代表只在键不存在时,才对键进行设置操作。键存在不能设置值
const MILLISECOND_EXPIRE_TIME = 'EX'; //过期时间
const EXPIRE_TIME = 50; // millisecond => 50s
/**
* @param $key
* 加锁
*/
public function lock($key,$uuid,$expire_time = '')
{
if (empty($expire_time)){
$expire_time = self::EXPIRE_TIME;
}
$ret = Redis::set($key,$uuid,self::MILLISECOND_EXPIRE_TIME , $expire_time,self::IF_NOT_EXISTS); //不用setnx 避免死锁,setnx不能设置过期时间
if ($ret == self::LOCK_SUCCESS){
return true;
}else{
return false;
}
}
/**
* 释放锁
*/
public function unlock($key,$uuid)
{
$lua =<<<LUA_SCRIPT
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
LUA_SCRIPT;
$restful = Redis::eval($lua,1,$key,$uuid);
return $restful;
}
}
?>
<?php
public function DistributedLock($id)
{
$RedisLock = new RedisLockService();
$key = "product_".$id;
$uuid = Uuid::uuid1($id);
$uuid = $uuid->getHex();
$return = "";
try{
if (!$RedisLock->lock($key,$uuid)){
return "当前业务繁忙,请稍后";
}else{
$ret = DB::table("fm_products")->where("id",$id)->first();
if ($ret->store >0){
$ret = DB::table("fm_products")->where("id",$id)->decrement("store");
if ($ret){
$return = "下单成功";
}else{
$return = "下单失败";
}
}else{
$return = "库存不足";
}
$RedisLock->unlock($key,$uuid);
return $return;
}
}catch (\Exception $exception){
$RedisLock->unlock($key,$uuid);
return $exception->getMessage();
}
}
?>
内存淘汰策略
定期删除,指的是redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除
惰性删除,获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。
其他
volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。
allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
no-enviction(驱逐):禁止驱逐数据,这也是默认策略
多级缓存
Openresty安装
安装依赖
yum install readline-devel pcre-devel openssl-devel
获取安装包解压
wget https://openresty.org/download/ngx_openresty-1.9.7.1.tar.gz # 下载
tar xzvf ngx_openresty-1.9.7.1.tar.gz # 解压
进入安装目录,编译安装
cd ngx_openresty-1.9.7.1/
./configure
make
make install
使用Openresty-创建lua脚本
ngx.header.content_type="application/json;charset=utf8"
local cjson = require("cjson") --引入模块
local mysql = require("resty.mysql") --引入mysql模块
local uri_args = ngx.req.get_uri_args()
local product_id = uri_args['product_id']
local db = mysql:new() --初始化数据库
db:set_timeout(1000) --设置超时时间
local props = {
host = "192.168.29.108", --mysql ip地址
port = 3306, --mysql 端口
database = "starsky", --mysql 数据库
user = "starsky", password = "root" --用户名密码
}
local res = db:connect(props) --获得mysql连接
local select_sql = "select id,store from fm_products where id ='"..product_id.."'" --一条查询语句
res = db:query(select_sql) db:close() --执行
local redis = require("resty.redis") --引入redis
local red = redis:new() red:set_timeout(2000) --初始化 设置超时时间
local ip ="192.168.29.108"
local port = 6379
red:connect(ip,port)
red:auth("root")
red:set("product_"..product_id,cjson.encode(res)) --存储到redis
red:close()
ngx.say("{flag:true}")
ngx.header.content_type="application/json;charset=utf8"
local uri_args = ngx.req.get_uri_args()
local product_id = uri_args['product_id']
local cache_ngx = ngx.shared.dis_cache;
local adCache = cache_ngx:get('productcache'..product_id);
if adCache == "" or adCache == nil then
local redis = require("resty.redis") --引入redis
local red = redis:new() red:set_timeout(2000) --初始化 设置超时时间
local ip ="192.168.29.108"
local port = 6379
red:connect(ip,port)
red:auth("root")
local rescontent=red:get("product_"..product_id)
ngx.say(rescontent)
red:close()
cache_ngx:set('productcache'..product_id, rescontent, 10*60);
else
ngx.say(adCache)
end