背景

最近写了一个定时任务,期望是同一时间只有一台机器运行即可。因为是应用是在集群环境下跑的,所以需要自己实现类一个简陋的Redis单机锁。

原理

主要是使用了Redis的SET NX特性,成功设置的那个客户端则被认为拿到了锁,没有设置成功的其他客户单则认为没有拿到锁。

在分布式环境下使用锁是挺危险的一件事情,我们可能会遇到一些问题:

  1. Redis单点故障;
  2. 应用与Redis网络不通;
  3. 应用异常导致锁没有得到释放;
  4. 误操作锁。

对于问题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的两点需要注意:

  1. 在锁的场景,testOnBorrow应该为true;
  2. 设置合理的空闲连接数;
  3. 设置连接上限,防止占用过多资源。

分布式应用下的Redis单机锁设计与实现的更多相关文章

  1. redis互斥锁简易设计原理【原】

    redis互斥锁设计 方式一: 使用 set(arg1,arg2,arg3,arg4,arg5) 绿线部分代码 //如果不存在就设置,且设置成功60秒后key自动失效,成功会返回字符串"OK ...

  2. 亿级流量场景下,大型缓存架构设计实现【1】---redis篇

    *****************开篇介绍**************** -------------------------------------------------------------- ...

  3. 【分布式缓存系列】集群环境下Redis分布式锁的正确姿势

    一.前言 在上一篇文章中,已经介绍了基于Redis实现分布式锁的正确姿势,但是上篇文章存在一定的缺陷——它加锁只作用在一个Redis节点上,如果通过sentinel保证高可用,如果master节点由于 ...

  4. 使用Redis实现锁(支持分布式应用)(整理网络资料)

    使用Redis实现锁(支持分布式应用) 1.    简介 使用Redis指令setnx.expire.getset等操作实现互斥资源的访问 本文内容来着网络整理,参考: http://www.linu ...

  5. 探索Redis设计与实现15:Redis分布式锁进化史

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  6. 基于Redis的分布式锁设计

    前言 基于Redis的分布式锁实现,原理很简单嘛:检测一下Key是否存在,不存在则Set Key,加锁成功,存在则加锁失败.对吗?这么简单吗? 如果你真这么想,那么你真的需要好好听我讲一下了.接下来, ...

  7. 利用redis 分布式锁 解决集群环境下多次定时任务执行

    定时任务: @Scheduled(cron= "0 39 3 * * *") public void getAllUnSignData(){ //检查任务锁,若其它节点的相同定时任 ...

  8. [原创] PHP 使用Redis实现锁

    目录 锁实现的注意点 加锁 connect 与 pconnect 解锁 Redis 中使用 Lua 脚本的注意点 Redis集群分布式锁 RedLock 算法 锁实现的注意点 互斥: 任意时刻, 只能 ...

  9. Redis分布式锁实战

    什么是分布式锁 在单机部署的情况下,要想保证特定业务在顺序执行,通过JDK提供的synchronized关键字.Semaphore.ReentrantLock,或者我们也可以基于AQS定制化锁.单机部 ...

随机推荐

  1. 线程同步之 yield() wait()

    yield()没有参数. sleep 方法使当前运行中的线程睡眼一段时间,进入不可运行状态,这段时间的长短是由程序设定的,yield 方法使当前线程让出CPU占有权,但让出的时间是不可设定的.yiel ...

  2. Java程序设计之正则表达式

    正则表达式平时在用到字符串处理的时候是比较常用的,个人觉得不需要刻意的去理解,用的话把文档拿出来查一下就好了,下面给个链接 http://www.php100.com/manual/Javascrip ...

  3. AC日记——最大数 洛谷 P1198 [JSOI2008]

    题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:L不超过当前数列的长度. 2. 插入操作 ...

  4. 服务器504——一般情况下是由nginx默认的fastcgi进程响应慢引起的

    情况一解决办法: 默认的fastcgi进程响应的缓冲区是8K,我们可以设置大一点,在nginx.conf里,加入:fastcgi_buffers 8 128k 这表示设置fastcgi缓冲区为8块12 ...

  5. jmeter(七)定时器

    知识来源有点复杂,其他测试工作者的博客,百度百科,搜集的电子文档,个人理解等等,限于水平和理解能力,可能有些内容有错误的地方... jmeter提供了很多元件,帮助我们更好的完成各种场景的性能测试,其 ...

  6. MySQL 常用的sql语句小结(待续)

    mysql 常用的sql语句 1.查看数据库各个表中的记录数 USE information_schema; SELECT table_name,table_rows FROM tables WHER ...

  7. ARM Cortex-M0权威指南高清中文版pdf免费分享下载

    版 次:1 页 数:433 字 数:655000 印刷时间:2013-8-1 开 本:16开 纸 张:胶版纸 印 次:1 包 装:平装 丛书名:清华开发者书库 国际标准书号ISBN:978730233 ...

  8. 吉特仓库管理系统-.NET打印问题总结

    在仓储系统的是使用过程中避免不了的是打印单据,仓库系统中包含很多单据:入库单,出库单,盘点单,调拨单,签收单等等,而且还附带着很多的条码标签的打印.本文在此记录一下一个简单的打印问题处理方式.处理问题 ...

  9. 85 megacli-查看raid信息

    文章本身我不做过多修改了,在这里我就把自己在安装时候碰到的难点跟大家提下.1.何处下载?首先,根据文章中的路径已经下载不到相应的文件了,在此我们就自己到http://www.lsi.com的网站上去搜 ...

  10. linux基础知识与技能1

    1.隐藏文件与非隐藏文件Linux中:linux中隐藏文件特点是文件名以.开头,跟文件属性无关.在linux中查看隐藏文件用ls -a命令(普通显示ls)2.相对路径与绝对路径什么是路径:路径是用来标 ...