java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Redis分布式锁

Redis应用问题及分布式锁使用说明

作者:祁仙森

文章主要讨论了缓存穿透、缓存雪崩和分布式锁在高并发场景下的解决方案,包括对空值缓存、设置白名单、布隆过滤器监控、预先设置热门数据、实时调整过期时间、使用锁机制以及构建多级缓存架构等

缓存穿透

现象

  1. 应用服务器压力变大了,很多请求过来
  2. redis命中率降低
  3. 一直查询数据库(缓存中很多数据查询到,就查数据库,导致数据库压力增加)

原因

解决方案

缓存击穿

现象特点

  1. 数据库访问压力瞬时增大
  2. redis里面没有出现大量key过期
  3. redis正常运行

原因

Redis某个key过期了,大量访问使用这个key

解决方案

  1. 预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大key的时长
  2. 实时调整:现场监控热门数据,实时调整key的过期时长
  3. 使用锁(能避免这种情况,但是去点在于效率低下)

缓存雪崩

现象

  1. 数据库压力变大,服务器崩溃

原因

在极少时间段,查询大量key的集中过期情况

解决方案

Redis实现分布式锁

分布式锁实现方案

上述实现方式Redis性能最高,Zookeeper最可靠

Redis实现

  1. 最简单的使用setnx上锁,del解锁,但是此时有问题,若设置锁了,长时间不释放锁又会导致后续资源拿不到锁的情形
  2. 上述1中锁一直不释放的话,可以设置过期时间来解决这个问题,时间到了自动释放
setnx users name1
expire users 10
  1. 上述2案例有个问题,就是这个不是原子的,设置锁后,突然故障,无法设置过期时间,也会导致问题,因为Redis的操作是原子的,可以使用指令,加锁设置过期时间同时操作
set users name1 nx ex 5

分布式下锁误删除

出现情形

假设a和b两个线程,a线程先获取分布式锁,然后由于业务操作或者服务器卡顿等一系列操作造成a线程的锁过期自动失效释放了(而a线程还没有数据处理完)

a释放锁后,b线程获取了锁执行具体操作,此时a突然操作完了,然后释放了锁,而不是b主动释放的

这种情形就造成了锁误删除的情形

解决方案

  1. 将锁的值设置成uuid,唯一标识,set lock uuid nx ex 10
  2. 释放锁的时候首先判断当前uuid是否和要释放锁的uuid一样,一样释放,不一样不释放

Redis分布式锁——加锁释放锁的原子性优化

造成问题

在上述案例中的当a上锁,执行具体操作的时候,然后释放锁步骤,也遇到了比较锁的uuid值一样,恰巧在del操作要执行之前(也就是比较完成之后,删除操作之前)锁过期自动释放了,然后b线程获取了锁,还在执行具体的操作,a删除的是b的锁,这就造成的分布式下安全隐患

解决方案

在比较删除步骤嵌入原子性的LUA脚本在释放锁的比较释放进行做原子化操作

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文