通过Redis 实现分布式锁_利用Jedis 客户端
前言
分布式锁一般有三种实现方式:
- 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。
本篇博客将介绍第二种方式,基于Redis实现分布式锁。
虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。
可靠性
首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
互斥性:在任意时刻,只有一个客户端能持有锁。
不会发生死锁:即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
具有容错性:只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
解铃还须系铃人:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
代码实现
一、引入redis 依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
备注:根据版本不同,jedis 的set 方法也有所不同
二、配置文件增加redis 配置
# redis.properties 配置文件:
# region Redis jedis
# redis配置开始
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=redis123456
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=1024
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=10000
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=100
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=5
# 连接超时时间(毫秒)
spring.redis.timeout=10000
# 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时
spring.redis.block-when-exhausted=true
# endregion
三、利用Spring 把JedisPool 加入Bean 工厂
@Configuration
@PropertySource("classpath:application.properties")
@Slf4j
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.block-when-exhausted}")
private boolean blockWhenExhausted;
@Bean
public JedisPool redisPoolFactory() throws Exception {
log.info("JedisPool注入开始!!");
log.info("redis地址:" + host + ":" + port);
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
// 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
jedisPoolConfig.setBlockWhenExhausted(blockWhenExhausted);
// 是否启用pool的jmx管理功能, 默认true
jedisPoolConfig.setJmxEnabled(true);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password);
log.info("JedisPool注入成功!!");
return jedisPool;
}
}
四、封装RedisService 对外提供服务
@Service
@Slf4j
public class RedisService {
//Redis 成功返回结果标识
private static final String LOCK_SUCCESS = "OK";
//Reis 操作返回成功
private static final Long RELEASE_SUCCESS = 1L;
//Redis锁不存在时才设置成功
private static final String SET_IF_NOT_EXIST = "NX";
//Redis锁超时时间单位
private static final String SET_WITH_EXPIRE_TIME = "PX";
@Autowired
private JedisPool jedisPool;
/**
* 尝试获取分布式锁
*
* @param lockKey 锁
* @param requestId 请求唯一标识(可以通过uuid等方式获取唯一ID)
* @param expireTime 超期时间(毫秒)
* @return 是否获取成功
*/
public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) {
Jedis jedis = jedisPool.getResource();
//Jedis 3.0.0 以前的版本
//String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
//Jedis 3.0.0 及以后的版本
SetParams setParams = SetParams.setParams().nx().px(expireTime);
String result = jedis.set(lockKey, requestId, setParams);
return LOCK_SUCCESS.equals(result);
}
/**
* 释放分布式锁
*
* @param lockKey 锁
* @param requestId 请求唯一标识(加锁时用的唯一标识)
* @return 是否释放成功
*/
public boolean releaseDistributedLock(String lockKey, String requestId) {
Jedis jedis = jedisPool.getResource();
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(lockKey), Collections.singletonList(requestId));
return RELEASE_SUCCESS.equals(result);
}
}
五、简单解释
1. 利用redis 的set 命令的 5个参数保证操作的原子性
2. 利用Lua 脚本保证在释放锁时的原子性
3. 利用requestId 唯一标识保证不会释放别人的锁
通过Redis 实现分布式锁_利用Jedis 客户端的更多相关文章
- 利用redis实现分布式锁知识点总结及相关改进
利用redis实现分布式锁知识点总结及相关改进 先上原文,本文只为总结及对相关内容的质疑并提出若干意见,原文内容更详细https://www.cnblogs.com/linjiqin/p/800383 ...
- 利用redis实现分布式锁
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于ZooKeeper的分布式锁: 3. 基于Redis的分布式锁: 这里大概说一下三种方式的优缺点,数据库乐观锁优点是实现简单,只需要for ...
- spring boot 利用redisson实现redis的分布式锁
原文:http://liaoke0123.iteye.com/blog/2375469 利用redis实现分布式锁,网上搜索的大部分是使用java jedis实现的. redis官方推荐的分布式锁实现 ...
- 利用多写Redis实现分布式锁原理与实现分析(转)
利用多写Redis实现分布式锁原理与实现分析 一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子:场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能 ...
- 基于 Redis 的分布式锁
前言 分布式锁在分布式应用中应用广泛,想要搞懂一个新事物首先得了解它的由来,这样才能更加的理解甚至可以举一反三. 首先谈到分布式锁自然也就联想到分布式应用. 在我们将应用拆分为分布式应用之前的单机系统 ...
- 基于redis的分布式锁(转)
基于redis的分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...
- 基于redis的分布式锁(不适合用于生产环境)
基于redis的分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...
- redis系列:基于redis的分布式锁
一.介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分为两部分,一个是单机环境, ...
- 基于redis的分布式锁的分析与实践
前言:在分布式环境中,我们经常使用锁来进行并发控制,锁可分为乐观锁和悲观锁,基于数据库版本戳的实现是乐观锁,基于redis或zookeeper的实现可认为是悲观锁了.乐观锁和悲观锁最根本的区别在于 ...
随机推荐
- nyoj 27-水池数目(BFS, DFS)
27-水池数目 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:17 submit:22 题目描述: 南阳理工学院校园里有一些小河和一些湖泊,现在,我 ...
- hdu 3549 Flow Problem (Dinic)
Flow ProblemTime Limit: 5000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total ...
- 力扣(LeetCode)验证回文字符串II 个人题解
给定一个非空字符串 s,最多删除一个字符.判断是否能成为回文字符串. 示例 1: 输入: "aba" 输出: True 示例 2: 输入: "abca" 输出: ...
- SpringBoot 源码解析 (十)----- Spring Boot的核心能力 - 集成AOP
本篇主要集成Sping一个重要功能AOP 我们还是先回顾一下以前Spring中是如何使用AOP的,大家可以看看我这篇文章spring5 源码深度解析----- AOP的使用及AOP自定义标签 Spri ...
- 【Elasticsearch 7 探索之路】(四)Analyzer 分析
上一篇,什么是倒排索引以及原理是什么.本篇讲解 Analyzer,了解 Analyzer 是什么 ,分词器是什么,以及 Elasticsearch 内置的分词器,最后再讲解中文分词是怎么做的. 一.A ...
- mysqldump工具实现mysql数据库的备份还原
简介 冷.温.热备份 冷备:读写操作均不可进行 温备:读操作可执行:但写操作不可执行 热备:读写操作均可执行 MyISAM:温备,不支持热备 InnoDB:都支持 不管是热备还原还是冷备还原,还原时都 ...
- 【NHOI2018】扑克游戏
[问题描述] 有一种别样“小猫钓鱼”扑克游戏.有 N 张牌,每张牌都有一个花色和点数.游戏的规则:扑克接龙时,若前面有同样花色的牌,你可以将这两张牌连同之间的牌都取走,得到的分值为取走牌点数之和.这里 ...
- urllib练习
# coding = utf-8 """ 解析https://www.kuaidaili.com/free/网站里的代理地址, 并测试是否可用 ""& ...
- 前端常用得CSS代码分享
前端常用得CSS代码分享 本文首发于公众号:小夭同学,同步更新个人博客:故事影片,转载请署名.代码不断更新中!! 1,垂直居中对齐 .vc { position: absolute; top: 50% ...
- Git的安装和使用教程详解
---恢复内容开始--- 本篇笔记聊聊Git的安装和使用教程 一.认 识 Git ...