利用redis实现分布式锁知识点总结及相关改进

先上原文,本文只为总结及对相关内容的质疑并提出若干意见,原文内容更详细https://www.cnblogs.com/linjiqin/p/8003838.html

@frameStart@

@frameTitle@最新修改@frameTitle@

老版问题:lock时如果只用jedis.set(String key, String value, String nxxx, String expx, int time)方法存在若干问题:1.不支持重入锁,2.且超时时间的设置也是一个问题

解决方案:1. 锁的结构用hash,因为string形式无法支持可重入;

2.  使用了hash就不能再用jedis.set(String key, String value, String nxxx, String expx, int time)这个方法了,所以取锁也要使用eval表达式。

hash数据结构:

 bizKey:{   // 某个业务锁
  clientId:“”,// 业务id,唯一;
state:1, //取锁次数,用来实现可重入
// 超时时间直接用expire来表示,用字段的话不安全。
}

伪代码如下:

加锁基本思路: 判断锁是否存在,如果不存在,直接加锁;如果存在,则判断client是否与当前业务id一致,如果一致,加锁成功,state+1,否则提示加锁失败

去锁基本思路:判断锁是否存在,如果不存在,直接返回成功;如果client不一致,返回失败;now = state-1,如果now=0,直接删掉锁。返回成功。

最后,关于超时时间的问题:如果不设超时的话,业务异常导致来不及解锁时会导致数据一直存在。如果设的话,设的太小了,可能业务处理时间太长,别的线程在锁过期后会取到锁,此方式最不可取。如果设的时间太长,与不设同义。

方案:?

关于锁超时的俩种言论,参考一下:

一种:

使用 WATCH/MULTI/EXEC ,watch能保证 MULTI 和 EXEC 之间的命令只有在watch的值没有变化才执行成功,见官方文档https://redis.io/topics/trans...

所以一般这个锁的值要在整个系统保持唯一。

另一种:

锁超时被释放不是很正常吗。。 因为我没有用过redis,所以对于楼上说的超时如何避免我不知道。。

但是从分布式系统的角度来分析这个问题,锁其实就等于租约,谁从redis得到了租约,谁就是集群的leader,执行一些follower不能做的操作,

但是呢,leader总是会由于种种问题(网络、gc)无法及时续租,导致超时,这时候另外一个follower进而得到锁,导致集群双主。

所以问题的性质就变成了分布式情况下如何避免多主(或脑裂)。常用的做法就是fencing机制,如kafka的epoch。楼主可以试下

@frameEnd@

1.redis基础知识点:

  1.1 多线程环境下,多条命令不具备原子性,尽量使用单命令或eval表达式;

  1.2 redis天然单线程,化异步为同步,处理效率极高;且一般内网操作,速度比较快;支持多机部署,用来实现锁机制十分合适;

2. 针对锁的基本特性,利用redis的特点解决之
  2.1互斥性:set一个key NX 观看返回值即可
  2.2 防死锁:设置key的过期时间即可
  2.3 容错性:使用Redisson实现分布式锁
  2.4 排他性:set key value时,value设置一个独一无二的值如uuid
  针对以上几个特性,
  **获取锁**:
    使用jedis.set(key, value_uuid, NX, PX, 10000);即可实现取锁;
  **释放锁**:
    使用eval表达式即可:
    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    Object result = jedis.eval(script, Collections.singletonList(key), Collections.singletonList(value));
  **存在问题**

    问题1:锁超时时间大小不好设置,因为业务处理的时间大小不确定,可能会很长,长到超时时间满足不了。

    问题2:关于拿锁是重试还是排队拿锁?可以自己参考AQS类,锁的本质就是一个状态的获得,AQS类是JVM中state变量的获取,而基于redis的分布式锁则是内存中变量的获取,redis已经天然的变异步为同步了,所以只能排队拿锁,如果恰好每次重试的过程中都是被其它客户端持有锁的,极有可能造成线程长时间拿不到锁(即使你忙循环调用redis,redis也不会单独优先处理你的)

  2.5 可重入:不支持,重置有效期是错误的方式;另外value_uuid被设定成了固定值(用来排他),无法像AQS的state字段那样增长或者减少。

  2.6 总结:排他和可重入似乎不能同时实现。而且实现了可重入,不支持排他,这个锁机制也是不可用的。所以,放弃可重入

利用redis实现分布式锁知识点总结及相关改进的更多相关文章

  1. 利用redis实现分布式锁

    分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于ZooKeeper的分布式锁: 3. 基于Redis的分布式锁: 这里大概说一下三种方式的优缺点,数据库乐观锁优点是实现简单,只需要for ...

  2. 【Redis】利用 Redis 实现分布式锁

    技术背景 首先我们需要先来了解下什么是分布式锁,以及为什么需要分布式锁. 对于这个问题,我们可以简单将锁分为两种--内存级锁以及分布式锁,内存级锁即我们在 Java 中的 synchronized 关 ...

  3. springboot利用redis实现分布式锁(redis为单机模式)

    1.pom文件添加redis支持 <dependency> <groupId>org.springframework.boot</groupId> <arti ...

  4. spring boot 利用redisson实现redis的分布式锁

    原文:http://liaoke0123.iteye.com/blog/2375469 利用redis实现分布式锁,网上搜索的大部分是使用java jedis实现的. redis官方推荐的分布式锁实现 ...

  5. 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存

    原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...

  6. 利用redis实现分布式事务锁,解决高并发环境下库存扣减

    利用redis实现分布式事务锁,解决高并发环境下库存扣减   问题描述: 某电商平台,首发一款新品手机,每人限购2台,预计会有10W的并发,在该情况下,如果扣减库存,保证不会超卖 解决方案一 利用数据 ...

  7. 基于redis的分布式锁的分析与实践

    ​ 前言:在分布式环境中,我们经常使用锁来进行并发控制,锁可分为乐观锁和悲观锁,基于数据库版本戳的实现是乐观锁,基于redis或zookeeper的实现可认为是悲观锁了.乐观锁和悲观锁最根本的区别在于 ...

  8. 基于redis的分布式锁二种应用场景

    “分布式锁”是用来解决分布式应用中“并发冲突”的一种常用手段,实现方式一般有基于zookeeper及基于redis二种.具体到业务场景中,我们要考虑二种情况: 一.抢不到锁的请求,允许丢弃(即:忽略) ...

  9. 利用多写Redis实现分布式锁原理与实现分析(转)

    利用多写Redis实现分布式锁原理与实现分析   一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子:场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能 ...

随机推荐

  1. python简明教程代码

    #!user/bin/env python #-*- coding:utf-8 -*- # code001 print('hello world') (only one quotation mark, ...

  2. 关于springboot2.x 的 RedisCacheManager变化

    springboot配置缓存过期时间,大部分是使用ReidsCacheManager来进行自定义的配置 以下是大部分网上的代码(这也是基于springboot1.x的版本可以使用的) @Beanpub ...

  3. C# 6.0:Auto-Property initializer

    在之前的开发中,属性只能在构造函数中进行初始化,如果它有定义一个后台字段的话,那这个字段就就可以在定义的地方初始化.C# 6.0 引进了一个Auto-Property initializer机制使属性 ...

  4. var entsMapLocation = {……}函数

    var entsMapLocation = { global: { $popupCityBox: $(".ents-map-location-popup-box"), isPosi ...

  5. awk 正则匹配指定字段次数统计

    1. 文本数据 head 12315_industry_business.csv name,business,label,label_name 沧州光松房屋拆迁有限公司,旧房拆迁.改造:物业服务(依法 ...

  6. JAVA\Android 多线程实现方式及并发与同步

    转载:https://blog.csdn.net/csdn_aiyang/article/details/65442540 概述     说到线程,就不得不先说线程和进程的关系,这里先简单解释一下,进 ...

  7. SAS 日期格式显示年月的format

    首先要感谢bobguy在人大论坛上的帮助!之前和webgu也在圈子里讨论过这个问题,只找到一个yymmn6.的format,只能应用于yyyymm的情况.有了bobguy大侠的帮助,我们现在就可以表达 ...

  8. WebApp的自动测试工具: protractor和selenium

    Protractor是Selenium的扩充,支持Angularjs element(by.css('my-css')).click(); 一.用by的各种Locator定位元素 选中1个元素: el ...

  9. fontFamily 'Ionicons' is not a system font and has not been loaded through Expo.Font.loadAsync的问题

    import * as React from "react";import { Provider } from "mobx-react/native";impo ...

  10. SQL server 2008(Linux安装)

    今天应公司的要求,需要在阿里云上安装sql server 在本地使用,由于自己原来没有涉及过这样的安装所以走了很多的弯路.现在将我的安装过程与大家分享,希望能够帮到想要学习这个方面的人.以下是我用Ce ...