分布式锁-Redis

2020-05-14  本文已影响0人  GIT提交不上

一、缓存常见问题

  对于访问频率高、读多写少、一致性要求不高的数据适合做缓存。

1.1 缓存穿透

  缓存穿透:缓存和数据库中都没有的数据,不断发起请求,如发起为id为-1的数据或id为特别大不存在的数据。
  解决方案:

1.2 缓存击穿

  热点数据:缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来。
  解决方案:

  互斥锁示例代码如下所示:

static Lock reenLock = new ReentrantLock();
 
public List<String> getData04() throws InterruptedException {
    List<String> result = new ArrayList<String>();
    // 从缓存读取数据
    result = getDataFromCache();
    if (result.isEmpty()) {
        if (reenLock.tryLock()) {
            try {
                System.out.println("我拿到锁了,从DB获取数据库后写入缓存");
                // 从数据库查询数据
                result = getDataFromDB();
                // 将查询到的数据写入缓存
                setDataToCache(result);
            } finally {
                reenLock.unlock();// 释放锁
                }
 
            } else {
                result = getDataFromCache();// 先查一下缓存
            if (result.isEmpty()) {
                System.out.println("我没拿到锁,缓存也没数据,先小憩一下");
                Thread.sleep(100);// 小憩一会儿
                return getData04();// 重试
            }
        }
    }
    return result;
}

1.3 缓存雪崩

  缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是并发查多条数据
  解决方案:

【分布式】缓存穿透、缓存雪崩,缓存击穿解决方案
缓存穿透、缓存击穿、缓存雪崩区别和解决方案

二、Redis实现分布式锁

2.1 锁超时

  线程一获取到锁,但是未执行expire设置过期时间(setnx不支持设置过期时间)就Down掉了,此时就变成了死锁。

if(setnx(lock_sale_商品ID,1) == 1){
    expire(lock_sale_商品ID,30)
    try {
        do something ......
    } finally {
        del(lock_sale_商品ID)
    }
}

  使用set 指令的可选参数,设置过期时间:

set(lock_sale_商品ID,1,30,NX)

2.2 锁误删

  由于线程一执行过慢,锁自动释放了,线程二获取到锁,此时线程一执行完毕删除锁,造成锁误删。
  解决方法:在 del 释放锁之前做一个判断,验证当前的锁是不是自己加的锁,将当前的线程 ID 当做 value。

//加锁
String threadId = Thread.currentThread().getId()
set(key,threadId ,30,NX)

//解锁
if(threadId .equals(redisClient.get(key))){
    del(key)
}

  存在问题:判断和释放锁是两个独立操作,不是原子性
  解决方法:使用lua脚本执行保证原子性。
  优化:让获得锁的线程开启一个守护线程,用来给快要过期的锁续航。

漫画:什么是分布式锁?
什么是分布式锁

三、Redission实现分布式锁

  加锁原则:

  Redisson保证value的唯一性:UUID+ThreadID。
  Redission分布式锁原理如下:

图3-1 Redission分布式锁原理.png

  存在问题:master节点宕机,导致多个客户端对同一个分布式锁完成了加锁。
  解决方法:使用RedLock(Redis Distributed Lock)。

Redisson实现分布式锁(1)---原理

三、RedLock实现分布式锁

  算法思想:在多个redis实例上创建锁,必须在大多数redis节点(超过一半)上都成功创建锁,才能算这个整体的RedLock加锁成功。
  CAP定理:在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

分布式锁实现Demo:https://github.com/just-right/vote/tree/distributed

Redis RedLock 完美的分布式锁么?

上一篇下一篇

猜你喜欢

热点阅读