分布式应用下的Redis单机锁设计与实现
背景
最近写了一个定时任务,期望是同一时间只有一台机器运行即可。因为是应用是在集群环境下跑的,所以需要自己实现类一个简陋的Redis单机锁。
原理
主要是使用了Redis的SET NX特性,成功设置的那个客户端则被认为拿到了锁,没有设置成功的其他客户单则认为没有拿到锁。
在分布式环境下使用锁是挺危险的一件事情,我们可能会遇到一些问题:
- Redis单点故障;
- 应用与Redis网络不通;
- 应用异常导致锁没有得到释放;
- 误操作锁。
对于问题1,避免Redis单点故障,可以使用Redis分布式锁的实现,提供了多种语言的开源实现(http://redis.io/topics/distlock),也可以使用其他配置管理类组件实现(比如:zk、consul、etcd等),不在此文讨论。
对于问题2,我们需要把业务限定在不强依赖Redis锁的范围,虽然绝大多数情况不会发生问题,但是不能完全保证Redis锁不出问题。
对于问题3,为了防止异常引起的死锁情况,需要为每个锁设置超时时间,以确保不会因为应用问题导致无法释放锁。同时要设置一个合理的超时时间以免,达不到或者削弱锁的效果。
对于问题4,为每个锁存储一个标记,当解锁的时候,进行验证,用以保证每个客户端只能操作自己的锁。
实现
public class RedisLock {
private static final Logger logger = LoggerFactory.getLogger(RedisLocker.class);
// update on 2019-11-08 22:55:00 修改成线程安全版本
private final Map<String, String> LOCK_MAP = new ConcurrentHashMap<String, String>(4);
private JedisPool pool;
public enum EXPX {
EX,PX
}
public boolean tryAcquire(String topic, EXPX expx,long time) throws Exception{
if (!LOCK_MAP.containsKey(topic)) {
String uuid = UUID.randomUUID().toString();
Jedis jedis = null;
// 存在key,返回空,不存在返回OK
try {
jedis = pool.getResource();
String result = jedis.set(topic, uuid, "NX", expx.name(), time);
logger.error("获取返回值,result {}", result);
if ("OK".equals(result)) {
LOCK_MAP.put(topic, uuid);
return true;
}
logger.error("获取锁失败,result {}", result);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
throw e;
}finally {
pool.returnResource(jedis);
}
}
return false;
}
public boolean unlock(String topic) {
Jedis jedis = null;
try {
jedis = pool.getResource();
String random = jedis.get(topic);
if (random != null && random.equals(LOCK_MAP.get(topic))) {
jedis.del(topic);
}
LOCK_MAP.remove(topic);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
throw e;
} finally {
pool.returnResource(jedis);
}
return true;
}
public void setPool(JedisPool pool) {
this.pool = pool;
}
}
总结
本文做了一种简单暴力的锁的实现。没有做高可用的方案,主要胜在轻量,简单,在平时场景可以使用。
除了使用配置中心相关的组件也是可以实现锁的,并且是分布式的锁。
关于RedisPool的两点需要注意:
- 在锁的场景,testOnBorrow应该为true;
- 设置合理的空闲连接数;
- 设置连接上限,防止占用过多资源。
分布式应用下的Redis单机锁设计与实现的更多相关文章
- redis互斥锁简易设计原理【原】
redis互斥锁设计 方式一: 使用 set(arg1,arg2,arg3,arg4,arg5) 绿线部分代码 //如果不存在就设置,且设置成功60秒后key自动失效,成功会返回字符串"OK ...
- 亿级流量场景下,大型缓存架构设计实现【1】---redis篇
*****************开篇介绍**************** -------------------------------------------------------------- ...
- 【分布式缓存系列】集群环境下Redis分布式锁的正确姿势
一.前言 在上一篇文章中,已经介绍了基于Redis实现分布式锁的正确姿势,但是上篇文章存在一定的缺陷——它加锁只作用在一个Redis节点上,如果通过sentinel保证高可用,如果master节点由于 ...
- 使用Redis实现锁(支持分布式应用)(整理网络资料)
使用Redis实现锁(支持分布式应用) 1. 简介 使用Redis指令setnx.expire.getset等操作实现互斥资源的访问 本文内容来着网络整理,参考: http://www.linu ...
- 探索Redis设计与实现15:Redis分布式锁进化史
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- 基于Redis的分布式锁设计
前言 基于Redis的分布式锁实现,原理很简单嘛:检测一下Key是否存在,不存在则Set Key,加锁成功,存在则加锁失败.对吗?这么简单吗? 如果你真这么想,那么你真的需要好好听我讲一下了.接下来, ...
- 利用redis 分布式锁 解决集群环境下多次定时任务执行
定时任务: @Scheduled(cron= "0 39 3 * * *") public void getAllUnSignData(){ //检查任务锁,若其它节点的相同定时任 ...
- [原创] PHP 使用Redis实现锁
目录 锁实现的注意点 加锁 connect 与 pconnect 解锁 Redis 中使用 Lua 脚本的注意点 Redis集群分布式锁 RedLock 算法 锁实现的注意点 互斥: 任意时刻, 只能 ...
- Redis分布式锁实战
什么是分布式锁 在单机部署的情况下,要想保证特定业务在顺序执行,通过JDK提供的synchronized关键字.Semaphore.ReentrantLock,或者我们也可以基于AQS定制化锁.单机部 ...
随机推荐
- NOI2001|POJ1182食物链[种类并查集 向量]
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 65430 Accepted: 19283 Description ...
- 3.开发Java消息驱动bean实例代码
java消息服务(JMS)是用于访问企业消息系统的开发商中立的API.企业消息系统可以协助应用软件通过网络进行消息交互.应用程序A发送一条消息到消息服务器的某个目的地(Destination),然后消 ...
- BBR拥塞控制算法
BBR拥塞控制算法是Google最新研发的单边TCP拥塞控制算法Linux 内核4.9 已引入这个BBR算法,本人在CAC测试Ubuntu 14.04 安装Linux 4.9内核,延迟优化效果和TCP ...
- DOCKER是什么,它解决了什么问题?(转)
Docker 虚拟机 1. docker与虚拟机性能比较 2. 如日中天的Docker解决了什么问题?
- CSS代码实例:用CSS代码写出的各种形状图形
一共收集整理了图形20个,比较实用,同时也为了熟悉CSS的代码.整合了一下,有错误欢迎指出. 1.正方形 #square { width: 100px; height: 100px; backgrou ...
- php $CI =& get_instance();
初学php 看有人这样写,$CI =& get_instance(); 要你自定义的类库中访问CodeIgniter的原始资源,你必须使用 get_instance() 函数.这个函数返回一个 ...
- SQLite剖析之事务处理技术
前言 事务处理是DBMS中最关键的技术,对SQLite也一样,它涉及到并发控制,以及故障恢复等等.在数据库中使用事务可以保证数据的统一和完整性,同时也可以提高效率.假设需要在一张表内一次插入20个人的 ...
- html,body的关系
先上一张关系图 最底下的一个是画布,往上一层是html结构,再往上一层是body结构 默认情况下html,body的height都是0,你给这两个元素分别加个边框就能看出来,要特别注意的是加背景颜色是 ...
- [Bundling and Minification ] 三、缩小
Minification 缩小,将文档的Size减小.主要是通过一下方式缩小文档的Size: 1.移除没用的空行 . 2.删除代码注释. 3.缩短js变量的名称,将变量名用一个字母表示.
- u盘安装系统教程详解
一.准备阶段 提前准备一个至少1G或以上的u盘,方便好用. 1.制作u盘启动工具 (1)工具下载,推荐IT天空的优启通 下载地址:https://www.itiankong.net/thread-37 ...