redis分布式锁优化的实现

对于单机的应用来说,可以直接使用synchronized关键字或着Lock工具类来加锁;但是对于分布式应用我们需要凭借一些工具来实现加锁;

加锁流程通俗来解释就是:
        1. 占坑
        2. 执行逻辑
        3. 填坑

我们可以使用redis来完成占坑这个操作;

基础版加锁

//通过占坑的方式获取锁
boolean lock = redis.setIfAbsent(key, value);
if (lock) {
//业务逻辑

//填坑
redis.delete(lock)
}

如果获取锁之后,应用宕机导致未释放锁,会造成死锁

获取锁的时候需要给锁添加过期时间

redis.setIfAbsent(key, value);
redis.expire(key, value);

如果在获取锁的时候,意外导致过期时间没设置成功,也会导致死锁

通过lua脚本将set、expire两个操作合并成原子操作,确保过期时间能设置成功

如果锁过期了,但是当前任务未执行结束,此时锁就可能被其他应用获取到,并更新锁的key。如果此时当前任务执行结束去释放锁,会将别人的锁给释放掉

释放锁:

  • 判断当前锁的值和自己上锁的值是不是吻合的;
  • 如果不吻合则不释放;
  • 如果值吻合,就删除key释放锁;

在释放锁的时候,如果判断key值吻合,但此时key过期了,锁被别人获取到,此时再删除key,就是释放了别人的锁了
要保证查询、判断、删除逻辑为原子操作,使用lua脚本

如何保证锁的可重入

如果在递归方法有加锁逻辑或其他调用有

lock.lock();
//逻辑
lock.lock();
//逻辑
lock.unLock();
lock.unLock();

要实现可重入锁,可以在锁的value值上做文章,在value值上记录重入次数,每次重入次数加一,每次unlock次数减一,直至为零,则删除key 释放锁;

key:
{
    "value":1
}

如果业务逻辑时间过长,锁提前过期释放了怎么办

  • 将过期时间设置的长一点
  • 需要给锁添加续期功能。

设置长过期时间的弊端就是,如果应用宕机之后锁需要经历较长的时间才能被别人获取,影响业务;

如果是有续期功能的话,如果宕机,锁也会被较短的过期时间给刷掉,是种更优美的解决方式;

如redission中获取锁后,会启动一个watchDog线程来监控当前线程是否还持有锁,如果还持有锁,就给他续期

具体操作为: 每十秒检查一下是否持有锁,如果锁未释放就重置一下锁的过期时间,实现续期;

如果应用在redis的master节点上获取锁成功,此时该master节点宕机,且锁数据还未同步到slave节点上,主从切换之后,其他应用趁机也获取了分布式锁

redLock

主从结构不是会有问题吗,redlock就换成使用多个不相关的、没有主从关系的redisMaster节点,来保证他们不会同时宕机,总数最好为奇数个。
redLock通过在多个节点上同时获取锁,如果超过半数的节点都获取锁成功,才算成功;否则失败,回滚删除所有节点的锁。

参考

原来大厂Redis分布式锁都这么设计的

Redis分布式锁的原理以及如何续期

到此这篇关于redis分布式锁优化的实现的文章就介绍到这了,更多相关redis分布式锁优化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-09-14

Redis分布式锁的实现方式(redis面试题)

什么是分布式锁? 要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁.进程锁. 线程锁:主要用来给方法.代码块加锁.当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段.线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state). 进程锁:为了控制同一操作系统中多个进程访问某个共享资源,因为进程具有独立性,各个进程无法访问其他进程的资源,因此无法通过synchronize

基于redis分布式锁实现秒杀功能

最近在项目中遇到了类似"秒杀"的业务场景,在本篇博客中,我将用一个非常简单的demo,阐述实现所谓"秒杀"的基本思路. 业务场景 所谓秒杀,从业务角度看,是短时间内多个用户"争抢"资源,这里的资源在大部分秒杀场景里是商品:将业务抽象,技术角度看,秒杀就是多个线程对资源进行操作,所以实现秒杀,就必须控制线程对资源的争抢,既要保证高效并发,也要保证操作的正确. 一些可能的实现 刚才提到过,实现秒杀的关键点是控制线程对资源的争抢,根据基本的线程知识,可

Redis实现分布式锁的几种方法总结

Redis实现分布式锁的几种方法总结 分布式锁是控制分布式系统之间同步访问共享资源的一种方式.在分布式系统中,常常需要协调他们的动作.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁. 我们来假设一个最简单的秒杀场景:数据库里有一张表,column分别是商品ID,和商品ID对应的库存量,秒杀成功就将此商品库存量-1.现在假设有1000个线程来秒杀两件商品,500个线程秒杀第一个商品,

Java Redis分布式锁的正确实现方式详解

前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性.在任意时刻,只有一个客户端能持有锁. 不会发生死锁.即使有一个客户端在

基于Redis实现分布式锁以及任务队列

一.前言 双十一刚过不久,大家都知道在天猫.京东.苏宁等等电商网站上有很多秒杀活动,例如在某一个时刻抢购一个原价1999现在秒杀价只要999的手机时,会迎来一个用户请求的高峰期,可能会有几十万几百万的并发量,来抢这个手机,在高并发的情形下会对数据库服务器或者是文件服务器应用服务器造成巨大的压力,严重时说不定就宕机了,另一个问题是,秒杀的东西都是有量的,例如一款手机只有10台的量秒杀,那么,在高并发的情况下,成千上万条数据更新数据库(例如10台的量被人抢一台就会在数据集某些记录下 减1),那次这个

Redis上实现分布式锁以提高性能的方案研究

背景: 在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等.大部分是解决方案基于DB实现的,Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系. 项目实践 任务队列用到分布式锁的情况比较多,在将业务逻辑中可以异步处理的操作放入队列,在其他线程中处理后出队,此时队列中使用了分布式锁,保证入队和出队的一致性.关于redis队列这块的逻辑分析,我将在下一次对其进行总结,此处先略过. 接下来对redis实现的分

详解Java如何实现基于Redis的分布式锁

前言 单JVM内同步好办, 直接用JDK提供的锁就可以了,但是跨进程同步靠这个肯定是不可能的,这种情况下肯定要借助第三方,我这里实现用Redis,当然还有很多其他的实现方式.其实基于Redis实现的原理还算比较简单的,在看代码之前建议大家先去看看原理,看懂了之后看代码应该就容易理解了. 我这里不实现JDK的java.util.concurrent.locks.Lock接口,而是自定义一个,因为JDK的有个newCondition方法我这里暂时没实现.这个Lock提供了5个lock方法的变体,可以

浅谈Redis分布式锁的正确实现方式

前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 1.互斥性.在任意时刻,只有一个客户端能持有锁. 2.不会发生死锁.即使有一个

java语言描述Redis分布式锁的正确实现方式

分布式锁一般有三种实现方式:1.数据库乐观锁:2.基于Redis的分布式锁:3.基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性.在任意时刻,只有一个客户端能持有锁. 不会发生死锁.即使有一个客户端在持有锁的期间

Redis分布式锁的正确实现方法总结

分布式锁一般有三种实现方式: 1.数据库乐观锁: 2.基于Redis的分布式锁: 3.基于ZooKeeper的分布式锁. 本文将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 1.互斥性.在任意时刻,只有一个客户端能持有锁. 2.不会发生死锁.即使有一个客户端在

谈谈Redis分布式锁的正确实现方法

前言 最近在参加学校安排的实训任务,我们小组需完成一套分布式&微服务跨境电商,虽然这题目看起来有点老套,并且队友多是 Java 技术栈,所以我光荣(被迫) 的成为了一名前端,并顺路使用 PHP 的 Swoole 帮助负责服务器端的同学编写了几个微服务模块.在小组成员之间的协作中,还是出现了不少有趣的火花. 在昨天 review 队友代码的过程中,发现了我们组分布式锁的写法似乎有点问题,实现代码如下: 加锁部分 解锁部分 主要原理是使用了 redis 的 setnx 去插入一组 key-value

浅谈Java分布式架构下如何实现分布式锁

01分布式锁运用场景 互联网秒杀,抢优惠卷,接口幂等性校验.咱们以互联网秒杀为例. @RestController @Slf4j publicclassIndexController{ @Autowired privateRedissonredission; @Autowired privateStringRedisTemplatestringRedisTemplate; @RequestMapping("/deduct_stock") publicStringdeductStock(

redis分布式锁及会出现的问题解决

一.redis实现分布式锁的主要原理: 1.加锁 最简单的方法是使用setnx命令.key是锁的唯一标识,按业务来决定命名.比如想要给一种商品的秒杀活动加锁,可以给key命名为 "lock_sale_商品ID" .而value设置成什么呢?我们可以姑且设置成1.加锁的伪代码如下: setnx(key,1) 当一个线程执行setnx返回1,说明key原本不存在,该线程成功得到了锁:当一个线程执行setnx返回0,说明key已经存在,该线程抢锁失败. 2.解锁 有加锁就得有解锁.当得到锁的

深入理解redis分布式锁和消息队列

最近博主在看redis的时候发现了两种redis使用方式,与之前redis作为缓存不同,利用的是redis可设置key的有效时间和redis的BRPOP命令. 分布式锁 由于目前一些编程语言,如PHP等,不能在内存中使用锁,或者如Java这样的,需要一下更为简单的锁校验的时候,redis分布式锁的使用就足够满足了. redis的分布式锁其实就是基于setnx方法和redis对key可设置有效时间的功能来实现的.基本用法比较简单. public boolean tryLock(String loc

浅谈redis采用不同内存分配器tcmalloc和jemalloc

我们知道Redis并没有自己实现内存池,没有在标准的系统内存分配器上再加上自己的东西.所以系统内存分配器的性能及碎片率会对Redis造成一些性能上的影响. 在Redis的 zmalloc.c 源码中,我们可以看到如下代码: /* Double expansion needed for stringification of macro values. */ #define __xstr(s) __str(s) #define __str(s) #s #if defined(USE_TCMALLOC