利用redis实现分布式锁知识点总结及相关改进
利用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实现分布式锁知识点总结及相关改进的更多相关文章
- 利用redis实现分布式锁
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于ZooKeeper的分布式锁: 3. 基于Redis的分布式锁: 这里大概说一下三种方式的优缺点,数据库乐观锁优点是实现简单,只需要for ...
- 【Redis】利用 Redis 实现分布式锁
技术背景 首先我们需要先来了解下什么是分布式锁,以及为什么需要分布式锁. 对于这个问题,我们可以简单将锁分为两种--内存级锁以及分布式锁,内存级锁即我们在 Java 中的 synchronized 关 ...
- springboot利用redis实现分布式锁(redis为单机模式)
1.pom文件添加redis支持 <dependency> <groupId>org.springframework.boot</groupId> <arti ...
- spring boot 利用redisson实现redis的分布式锁
原文:http://liaoke0123.iteye.com/blog/2375469 利用redis实现分布式锁,网上搜索的大部分是使用java jedis实现的. redis官方推荐的分布式锁实现 ...
- 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存
原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...
- 利用redis实现分布式事务锁,解决高并发环境下库存扣减
利用redis实现分布式事务锁,解决高并发环境下库存扣减 问题描述: 某电商平台,首发一款新品手机,每人限购2台,预计会有10W的并发,在该情况下,如果扣减库存,保证不会超卖 解决方案一 利用数据 ...
- 基于redis的分布式锁的分析与实践
前言:在分布式环境中,我们经常使用锁来进行并发控制,锁可分为乐观锁和悲观锁,基于数据库版本戳的实现是乐观锁,基于redis或zookeeper的实现可认为是悲观锁了.乐观锁和悲观锁最根本的区别在于 ...
- 基于redis的分布式锁二种应用场景
“分布式锁”是用来解决分布式应用中“并发冲突”的一种常用手段,实现方式一般有基于zookeeper及基于redis二种.具体到业务场景中,我们要考虑二种情况: 一.抢不到锁的请求,允许丢弃(即:忽略) ...
- 利用多写Redis实现分布式锁原理与实现分析(转)
利用多写Redis实现分布式锁原理与实现分析 一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子:场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能 ...
随机推荐
- python简明教程代码
#!user/bin/env python #-*- coding:utf-8 -*- # code001 print('hello world') (only one quotation mark, ...
- 关于springboot2.x 的 RedisCacheManager变化
springboot配置缓存过期时间,大部分是使用ReidsCacheManager来进行自定义的配置 以下是大部分网上的代码(这也是基于springboot1.x的版本可以使用的) @Beanpub ...
- C# 6.0:Auto-Property initializer
在之前的开发中,属性只能在构造函数中进行初始化,如果它有定义一个后台字段的话,那这个字段就就可以在定义的地方初始化.C# 6.0 引进了一个Auto-Property initializer机制使属性 ...
- var entsMapLocation = {……}函数
var entsMapLocation = { global: { $popupCityBox: $(".ents-map-location-popup-box"), isPosi ...
- awk 正则匹配指定字段次数统计
1. 文本数据 head 12315_industry_business.csv name,business,label,label_name 沧州光松房屋拆迁有限公司,旧房拆迁.改造:物业服务(依法 ...
- JAVA\Android 多线程实现方式及并发与同步
转载:https://blog.csdn.net/csdn_aiyang/article/details/65442540 概述 说到线程,就不得不先说线程和进程的关系,这里先简单解释一下,进 ...
- SAS 日期格式显示年月的format
首先要感谢bobguy在人大论坛上的帮助!之前和webgu也在圈子里讨论过这个问题,只找到一个yymmn6.的format,只能应用于yyyymm的情况.有了bobguy大侠的帮助,我们现在就可以表达 ...
- WebApp的自动测试工具: protractor和selenium
Protractor是Selenium的扩充,支持Angularjs element(by.css('my-css')).click(); 一.用by的各种Locator定位元素 选中1个元素: el ...
- 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 ...
- SQL server 2008(Linux安装)
今天应公司的要求,需要在阿里云上安装sql server 在本地使用,由于自己原来没有涉及过这样的安装所以走了很多的弯路.现在将我的安装过程与大家分享,希望能够帮到想要学习这个方面的人.以下是我用Ce ...