广告位联系
返回顶部
分享到

用redis setNX命令来加锁的教程

Redis 来源:互联网 作者:佚名 发布时间:2023-01-11 20:57:25 人浏览
摘要

用redis setNX命令来加锁 加锁和释放锁,都需要原子操作,不然在中途中断就会发生异常, 删锁的时候也只能删除自己对应线程的锁。 下面是用sexNX命令加锁的模板 加锁失败后,休眠一

用redis setNX命令来加锁

加锁和释放锁,都需要原子操作,不然在中途中断就会发生异常,

删锁的时候也只能删除自己对应线程的锁。

下面是用sexNX命令加锁的模板

加锁失败后,休眠一段时候后,再次调用(自旋锁)

加锁失败后,可以

这个还是会有一个问题,

如果加锁的时间是30秒,业务执行的时候了40秒,这个其他的线程就能抢到锁,所以加锁的时间必须大于业务执行的时间

官方文档

http://redis.cn/commands/set.html

建议 使用redisson来用分布式锁

redis几种加锁的实现

1. redis加锁分类

redis能用的的加锁命令分表是INCR、SETNX、SET

2. 第一种锁命令INCR

这种加锁的思路是, key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作进行加一。 

然后其它用户在执行 INCR 操作进行加一时,如果返回的数大于 1 ,说明这个锁正在被使用当中。

  • 1、 客户端A请求服务器获取key的值为1表示获取了锁
  • 2、 客户端B也去请求服务器获取key的值为2表示获取锁失败
  • 3、 客户端A执行代码完成,删除锁
  • 4、 客户端B在等待一段时间后在去请求的时候获取key的值为1表示获取锁成功
  • 5、 客户端B执行代码完成,删除锁 

1

2

$redis->incr($key);

$redis->expire($key, $ttl); //设置生成时间为1秒

3. 第二种锁SETNX

这种加锁的思路是,如果 key 不存在,将 key 设置为 value 

如果 key 已存在,则 SETNX 不做任何动作

  • 1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功
  • 2、 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败
  • 3、 客户端A执行代码完成,删除锁
  • 4、 客户端B在等待一段时间后在去请求设置key的值,设置成功
  • 5、 客户端B执行代码完成,删除锁 

1

2

$redis->setNX($key, $value);

$redis->expire($key, $ttl);

4. 第三种锁SET

上面两种方法都有一个问题,会发现,都需要设置 key 过期。那么为什么要设置key过期呢?如果请求执行因为某些原因意外退出了,导致创建了锁但是没有删除锁,那么这个锁将一直存在,以至于以后缓存再也得不到更新。于是乎我们需要给锁加一个过期时间以防不测。 

但是借助 Expire 来设置就不是原子性操作了。所以还可以通过事务来确保原子性,但是还是有些问题,所以官方就引用了另外一个,使用 SET 命令本身已经从版本 2.6.12 开始包含了设置过期时间的功能。

  • 1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功
  • 2、 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败
  • 3、 客户端A执行代码完成,删除锁
  • 4、 客户端B在等待一段时间后在去请求设置key的值,设置成功
  • 5、 客户端B执行代码完成,删除锁 

1

$redis->set($key, $value, array('nx', 'ex' => $ttl));  //ex表示秒

5. 其它问题

虽然上面一步已经满足了我们的需求,但是还是要考虑其它问题? 

  • 1、 redis发现锁失败了要怎么办?中断请求还是循环请求? 
  • 2、 循环请求的话,如果有一个获取了锁,其它的在去获取锁的时候,是不是容易发生抢锁的可能? 
  • 3、 锁提前过期后,客户端A还没执行完,然后客户端B获取到了锁,这时候客户端A执行完了,会不会在删锁的时候把B的锁给删掉?

6. 解决办法

  • 针对问题1:使用循环请求,循环请求去获取锁 
  • 针对问题2:针对第二个问题,在循环请求获取锁的时候,加入睡眠功能,等待几毫秒在执行循环 
  • 针对问题3:在加锁的时候存入的key是随机的。这样的话,每次在删除key的时候判断下存入的key里的value和自己存的是否一样

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

        do {  //针对问题1,使用循环

            $timeout = 10;

            $roomid = 10001;

            $key = 'room_lock';

            $value = 'room_'.$roomid;  //分配一个随机的值针对问题3

            $isLock = Redis::set($key, $value, 'ex', $timeout, 'nx');//ex 秒

            if ($isLock) {

                if (Redis::get($key) == $value) {  //防止提前过期,误删其它请求创建的锁

                    //执行内部代码

                    Redis::del($key);

                    continue;//执行成功删除key并跳出循环

                }

            } else {

                usleep(5000); //睡眠,降低抢锁频率,缓解redis压力,针对问题2

            }

        } while(!$isLock);

7. 另外一个锁

以上的锁完全满足了需求,但是官方另外还提供了一套加锁的算法,这里以PHP为例

1

2

3

4

5

6

7

8

9

10

11

12

13

    $servers = [

        ['127.0.0.1', 6379, 0.01],

        ['127.0.0.1', 6389, 0.01],

        ['127.0.0.1', 6399, 0.01],

    ];

  

    $redLock = new RedLock($servers);

  

    //加锁

    $lock = $redLock->lock('my_resource_name', 1000);

  

    //删除锁

    $redLock->unlock($lock)


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/g3230863/article/details/127354710
相关文章
  • redis保存session信息的代码

    redis保存session信息的代码
    1、新建一个maven web 工程名为 session-redis 如下: 目录结构如下: 2、修改配置文件内容 pom.xml 中依赖如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1
  • 用redis setNX命令来加锁的教程

    用redis setNX命令来加锁的教程
    用redis setNX命令来加锁 加锁和释放锁,都需要原子操作,不然在中途中断就会发生异常, 删锁的时候也只能删除自己对应线程的锁。 下面是
  • spring boot集成redis基础入门实例介绍
    redis 支持持久化数据,不仅支持key-value类型的数据,还拥有list,set,zset,hash等数据结构的存储。 可以进行master-slave模式的数据备份 更多
  • redis批量操作pipeline管道操作方法

    redis批量操作pipeline管道操作方法
    redis | pipeline(管道) 背景 Redis是一种基于客户端-服务端模型以及请求/响应的TCP服务。这意味着通常情况下一个请求会遵循以下步骤: 客户
  • springboot整合使用云服务器上的Redis方法

    springboot整合使用云服务器上的Redis方法
    一、前提条件 修改redis.conf配置文件 1、protected-mode yes(默认的) 修改成 protected-mode no,解除保护模式 2、注释掉绑定ip ,绑定ip的话,使得
  • 阿里云服务器部署Redis并整合Spring Boot的介绍

    阿里云服务器部署Redis并整合Spring Boot的介绍
    一、什么是Redis redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zs
  • 生产redisson延时队列不消费问题排查解决

    生产redisson延时队列不消费问题排查解决
    问题描述 项目使用redisson延时队列功能,实现直播的开播提醒,突然有一天业务爆出问题,未触发开播提醒。 初步排查 首先通过查询生产日
  • Redis主从复制分步讲解使用

    Redis主从复制分步讲解使用
    主服务器(master)启用二进制日志 选择一个唯一的server-id 创建具有复制权限的用户 从服务器(slave)启用中继日志, 选择一个唯一的serv
  • Redis中HyperLogLog的使用介绍
    HyperLogLog,基数统计; 那什么是基数? 比如有两个数组 数组A = [1,2,3,4,5]; 数组B = [3,4,5,6,7]; 这时候基数就是[1,2,3,4,5,6,7],总共有7个数; 就是
  • Redis中的持久化介绍

    Redis中的持久化介绍
    1. 前言 为什么要进行持久化?:持久化功能有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化的文件即可实现数据
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计