zoukankan      html  css  js  c++  java
  • 分布式锁

    分布式锁

    利用redis实现分布式锁

     

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

    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();
    复制代码

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

  • 相关阅读:
    复制对象
    element.classList属性及方法应用
    Object.defineProperty
    965. Univalued Binary Tree
    700. Search in a Binary Search Tree
    561, Array Partition Ⅰ
    933. Number of Recent Calls
    999.Available Capture for rook
    961. N-Repeated Element in Size 2N Array
    709. To Lower Case
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/10437802.html
Copyright © 2011-2022 走看看