品牌查询网站 优帮云wordpress 发短信
品牌查询网站 优帮云,wordpress 发短信,池州有哪些做网站的,怎么做网站竞价Redis SETNX 特性
当然#xff0c;让我们通过一个简单的例子#xff0c;使用 Redis CLI#xff08;命令行界面#xff09;来模拟获取锁和释放锁的过程。 在此示例中#xff0c;我将使用键“lock:tcaccount_[pk]”和“status:tcaccount_[pk]”分别表示锁定键和状态键。
获…Redis SETNX 特性
当然让我们通过一个简单的例子使用 Redis CLI命令行界面来模拟获取锁和释放锁的过程。 在此示例中我将使用键“lock:tcaccount_[pk]”和“status:tcaccount_[pk]”分别表示锁定键和状态键。
获取锁:
# 首先设置锁密钥的唯一值和过期时间(秒)
127.0.0.1:6379 SET lock:tcaccount_1234 unique_value NX EX 3
OK这里“unique_value”是与锁关联的唯一标识符的占位符(生产环境UUID,随字符串)“EX 3”将过期时间设置为 3 秒
在另一个会话或请求中检查并获取锁
# 其次检查锁key是否存在不存在则获取锁
127.0.0.1:6379 SET lock:tcaccount_1234 unique_value NX EX 3
(nil)第二次尝试返回 nil因为锁已经存在。 在真实的应用程序中您将检查结果如果结果为零您可能会转到下一个帐户或等待并重试。
释放锁:
# 通过删除锁定密钥来解除锁定
127.0.0.1:6379 DEL lock:tcaccount_1234
(integer) 1The DEL 命令用于删除锁键有效释放锁。 返回的整数值 1 表示删除了一个键。
请注意这是一个简化的示例在现实场景中您通常会使用脚本例如 Lua 脚本来使锁的获取和释放原子化从而防止竞争条件。 这里的示例旨在说明使用 Redis 命令进行锁定的基本原理。
Node.js 程序中集成
node -v # v16.20.2
npm install redis # 笔者版本redis: ^4.2.0client.eval() 方法lua脚本如何正确传参
let result await client.eval(return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}, {keys: [key1, key2],arguments: [first, second]
});
//result [ key1, key2, first, second ]加锁实现 const client await createClient().on(error, err console.log(Redis Client Error, err)).connect();async function lock(resourceKey, uniqueValue, expireTime 10) {// 锁的键和值const lockKey lock:${resourceKey};/* 这种方式不能实现const result await client.setEx(lockKey, expireTime, uniqueValue);if (result OK) {console.log([s] 已获取锁 ${resourceKey});return true;} else {console.log([x] 无法获取锁 ${resourceKey});return false;}
*/// Lua脚本用于原子获取锁const luaScript if redis.call(SET, KEYS[1], ARGV[1], NX, EX, ARGV[2]) thenreturn 1elsereturn 0end;// 执行Lua脚本const result await client.eval(luaScript, {keys: [lockKey],arguments: [uniqueValue, ${expireTime}]});if (result 1) {console.log([s] 已获取锁 ${resourceKey});return true;} else {console.log([x] 无法获取锁 ${resourceKey});return false;}} 释放锁的实现
释放锁时需要验证value值也就是说我们在获取锁的时候需要设置一个value不能直接用del key这种粗暴的方式因为直接del key任何客户端都可以进行解锁了所以解锁时我们需要判断锁是否是自己的基于value值来判断代码如下 /*** 释放锁* param resourceKey 资源键名* param uniqueValue 唯一值用于验证锁的所有者(建议:UUID)* returns 是否成功释放锁*/async function unlock(resource, uniqueValue) {const lockKey lock:${resource};const luaScript if redis.call(GET, KEYS[1]) ARGV[1] thenreturn redis.call(DEL, KEYS[1])elsereturn 0end;const result await client.eval(luaScript, {keys: [lockKey],arguments: [uniqueValue]});if (result 1) {console.log([s] 锁释放成功);} else {console.log([x] 锁释放失败可能锁已经被其他客户端更新);}}
应用场景 多台机器定时任务 订单超卖
完整脚本如下
const {createClient} require(redis);
const {generateUUID} require(../models/utl);(async () {const client await createClient().on(error, err console.log(Redis Client Error, err)).connect();async function lock(resourceKey, uniqueValue, expireTime 10) {// 锁的键和值const lockKey lock:${resourceKey};/* const result await client.setEx(lockKey, expireTime, uniqueValue);if (result OK) {console.log([s] 已获取锁 ${resourceKey});return true;} else {console.log([x] 无法获取锁 ${resourceKey});return false;}
*/// Lua脚本用于原子获取锁const luaScript if redis.call(SET, KEYS[1], ARGV[1], NX, EX, ARGV[2]) thenreturn 1elsereturn 0end;// 执行Lua脚本const result await client.eval(luaScript, {keys: [lockKey],arguments: [uniqueValue, ${expireTime}]});if (result 1) {console.log([s] 已获取锁 ${resourceKey});return true;} else {console.log([x] 无法获取锁 ${resourceKey});return false;}}async function unlock(resource, uniqueValue) {const lockKey lock:${resource};const luaScript if redis.call(GET, KEYS[1]) ARGV[1] thenreturn redis.call(DEL, KEYS[1])elsereturn 0end;const result await client.eval(luaScript, {keys: [lockKey],arguments: [uniqueValue]});if (result 1) {console.log([s] 锁释放成功);} else {console.log([x] 锁释放失败可能锁已经被其他客户端更新);}}async function exampleUsage(resource) {const uniqueValue generateUUID();const isLockAcquired await lock(resource, uniqueValue);if (isLockAcquired) {try {// 在这里执行受锁保护的代码// 模拟一些处理时间await new Promise(resolve setTimeout(resolve, 5000));} finally {// 最后释放锁unlock(resource, uniqueValue);}} else {console.log([x] 未获取锁。 另一个进程可能正在持有锁。);}}const resourcePk account_id123let taskList []for (let i 0; i 10; i) {taskList.push( exampleUsage(resourcePk))}//并发拿同一账号await Promise.all(taskList);await new Promise(resolve setTimeout(resolve, 6000));//测试重新获取锁await exampleUsage(resourcePk);})()
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/90355.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!