Redlock实践--非阻塞模式
本文主要介绍在琴房预约项目中所用到的资源访问加锁技术Redlock,以及如果实现将redlock转为非阻塞锁。
1. 背景简介
1.1 项目简介
本次实践项目是THU琴房预约小程序与web管理端,后端使用koa框架。主要功能有预约琴房(用户)、更改琴房可用时间(管理端)等。后端使用mysql存储琴房信息(包含琴房可用时间串)。
1.2 问题介绍
- 多个用户可能在同一时间对同一琴房的同一时间段进行预约
- 用户与管理员可能同时进行预约、更改琴房可用时间
2. 加锁实践 redlock是一个基于redis数据库的分布式锁。通过在redis数据库中设定键值来进行信号量的定义。
- 我们把“预约“和“更改琴房可用时间”定义为使用同一个键值。
- 在操作前首先获取此键值,如果获取不到,说明被占用。
2.1 给资源加锁
// 获取权限
let redis = require("redis");
let client = redis.createClient("to change: your redis port","to change: your server ip");
let redlock = new Redlock([client]);
// 设置时间
let totalTime = 5000;
let key = "to change: as you like";
// 加锁
redlock.lock(key, totalTime).then(async function(lock){
// to do
// your operation block
// release lock
lock.unlock().catch(function(err){})
}
}).catch(()=>{}) // 如果不加catch会直接报错终止程序
主要流程为:
- 获取redis的操作权限
- 设定键值,最长等待时间(防止一直被占用)
- 执行操作
- 释放锁
键值的设置非常自由,我们可以通过键值的设置,控制加锁覆盖的范围以及力度。2.2 阻塞锁与非阻塞锁
在完成加锁之后,我们进行压力测试,发现了一个非常坑的情况:Redlock是非阻塞锁。
这就意味着,当一个用户进行预约的时候,别的用户如果有请求就会直接失败,这样是非常用户不友好的。所以我们需要一些操作来将redlock转为非阻塞锁。有两个方案:
- 方案一:实现一个请求队列以及回调函数,在资源被释放的时候,进行回调。
- 方案二:设置最长等待时间,在此时间段内进行轮询,如果超过此时间,放弃请求。
我们这里说明方案二的实现(目前最常用的转阻塞锁的方案)
let redis = require("redis");
let client = redis.createClient(config.redisPort,config.serverIp);
let redlock = new Redlock([client]);
let totalTime = 5000;
let key = "to change: as you like";
let intervalTime = 50;
// 轮询时间间隔let sleep = function(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}let tag = 0;
for(let j = 0;
j<200;
j++){
redlock.lock(key, totalTime).then(async function(lock){
if(tag === 1){
lock.unlock().catch(function(err){})
}
else{
tag = 1
// to do
// your operation block
// release lock
lock.unlock().catch(function(err){})
}
}).catch(()=>{})
if(tag === 1){
break
}
await sleep(intervalTime) // 设置间隔时间
}
if(tag === 0){
errorMsg = "请求超时"
return ;
}
3. 效果检验
文章图片
加锁效果
在预约与检票单项测试的时候,1000个人中只有一个人成功,符合预期。
文章图片
加锁效果
【Redlock实践--非阻塞模式】在预约与更改琴房可用时间混合测试的时候,2000个人中只有一个人成功,符合预期。
以上,说明这样加锁,可以成功解决资源访问竞争情况。
4. 参考资料
- redlock 效果解析
- redlock git地址
推荐阅读
- 对称加密和非对称加密的区别
- 不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
- 六项精进20180530
- 病态与非病态的梦中人情结|病态与非病态的梦中人情结 - 草稿
- 「按键精灵安卓版」关于全分辨率脚本的一些理解(非游戏app)
- 勿说人是非
- 第十六天(请介绍一件让你非常自豪的事情,(不能是职业类的),什么原因感到自豪。)
- 数据库|SQL行转列方式优化查询性能实践
- 【Day31课后实践】
- 一定要幸福