分布式锁一般有三种实现方式:

1. 数据库乐观锁;

2. 基于ZooKeeper的分布式锁;

3. 基于Redis的分布式锁;

这里大概说一下三种方式的优缺点,数据库乐观锁优点是实现简单,只需要for update关键词就可以实现,缺点是无法满足高并发量以及数据库读写频繁的系统

ZooKeeper分布式锁无论是从性能以及实现的功能来说都是非常优秀,只是在开发起来需要一定的基础,对新手可能不是很友好

而本文主要讲第三种利用redis实现分布式锁,优点是开发相对简单,能满足一定并发量的系统,缺点是存在线程争抢锁的问题,当并发量到达一定级别,多个线程去争抢同一个锁,对性能的影响较大


事务以及原子性

虽然Redis是单线程运行,但是在分布式的情况下对同一资源进行操作还是会出现问题,下图是一个简单的例子

所以一定要保证tomcat1以及tomcat2读写的原子性,既读与写要么都执行,要么都不执行。关于事务的原子性可以查询这里

那么如何保证呢,redis在2.6中加入了lua脚本功能可以轻松的解决这个问题,下面是一个简单的例子实现了上述的加100操作

Jedis jedis = jedisPool.getResource();
String script = "local a = redis.call('get', KEYS[0]) a = a + 100 redis.call('set', a)"; jedis.eval(script, 1, rname+"Lock",RedisCacheFactory.FactoryUUID,"1000");

分布式锁的具体实现

大概讲一下思路:首先加锁的方式是向redis里存入一个KEY-VALUE,KEY存入的加锁对象可以是方法、类、数据等等,VALUE存入持有锁的节点(例如tomcat1)

大概整理了一下几个问题:

Q:为什么VALUE存入持有锁的节点

A:为的是防止A加的锁被B给解除,保证只有持有锁的节点才能解锁

Q:怎么存入持有锁的节点

A:这里只是我的思路是在tomcat启的时候生成一个uuid作为该tomcat的token存入到VALUE中

Q:怎么防止死锁

A:利用Redis设置键的过期时间

下面贴出部分代码,仅供参考

加锁

JedisPool jedisPool = new JedisPool(new JedisPoolConfig(),RedisInstance.hostName,Integer.parseInt(RedisInstance.port),5000,password);
Jedis jedis = jedisPool.getResource();
// key1 : key值 argv1 :value值 argv2 :过期时间
String script = "if redis.call('EXISTS',KEYS[1]) ==0 then redis.call('set',KEYS[1],ARGV[1]) redis.call('EXPIRE',KEYS[1],ARGV[2]) return 1 else return 0 end";
long result = (long) jedis.eval(script, 1, rname+"Lock",RedisCacheFactory.FactoryUUID,"1000");
jedis.close();
jedisPool.close();

解锁

JedisPool jedisPool = new JedisPool(new JedisPoolConfig(),RedisInstance.hostName,Integer.parseInt(RedisInstance.port),5000,password);
Jedis jedis = jedisPool.getResource();
String script = "if redis.call('EXISTS',KEYS[1]) ==1 and redis.call('GET',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
long result = (long) jedis.eval(script, 1, rname+"Lock",RedisCacheFactory.FactoryUUID);
jedis.close();
jedisPool.close();

以上仅个人意见,如有错误的地方,还请各位海涵。

后面可能会整合这次缓存改造的所有环节发出来给大家参考 一下

补充说明一下:lua操作redis时如果操作多个key不在同一节点下会出错,原因是因为Cluster会将数据自动分布到不同的节点(虚拟的16384个slot,具体看这里)。

解决办法 后面会贴出详细教程

利用redis实现分布式锁的更多相关文章

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

    利用redis实现分布式锁知识点总结及相关改进 先上原文,本文只为总结及对相关内容的质疑并提出若干意见,原文内容更详细https://www.cnblogs.com/linjiqin/p/800383 ...

  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. s6-8 TCP 拥塞控制

    TCP 拥塞控制  虽然网络层也试图管理拥塞,但是,大多数繁重的任务是由TCP来完成的,因为针对拥塞的真正解决方案是减慢数据率  分组守恒:当有一个老的分组离开之后才允许新的分组注入网络  TC ...

  2. [f]智能获取浏览器版本UA信息的方法

    var browser={ versions:function(){ var u = navigator.userAgent, app = navigator.appVersion; return { ...

  3. hadoop2.7单节点

    $ sudo apt-get install ssh$ sudo apt-get install rsync 修改文件 etc/hadoop/hadoop-env.sh # set to the ro ...

  4. window、view相关

    View.Window以及Activity主要是用于显示并与用户交互window view activity surfaceView 三者间的关系: 在Activity中要设置View时,通常用的方法 ...

  5. python 学习之路【目录】

    目录: python--常用函数

  6. 制作系统U盘

    没有任何宣传软件成分昂,我就是这做的. 1.在百度搜索上搜索“通用PE大师”,点开了这个网站http://up.6615261.cn/index.html,打开之后如下图,下载这个二合一版本 2.在电 ...

  7. iOS 数组问题

    在iOS开发过程中,使用json抓取网络数据进行解析时,用tableview承载,发现数据已经抓取到,但是在cell里面使用却会导致程序崩溃 原因可能是初始化方法问题,将 _infoArray=[[N ...

  8. IntelliJ IDEA 常用快捷键使用说明

    Ctrl + / 可以实现单行注释的快速添加和取消.xml和html注释也能操作. Ctrl + Y 删除选中的代码,或者光标所在行,同时删除代码所占的空间. Ctrl + Alt + V 快速抽取变 ...

  9. Redis 指令 学习笔记

    Redis 什么是Redis redis是一种nosql数据库,他的数据是保存在内存中,同时redis可以定时把内存数据同步到磁盘,即可以将数据持久化,还提供了多个语言的API,操作比较方便 安装re ...

  10. SpringBoot中集成redis

    转载:https://www.cnblogs.com/zeng1994/p/03303c805731afc9aa9c60dbbd32a323.html 不是使用注解而是代码调用 需要在springbo ...