分布式缓存、分布式锁笔记

分布式缓存、分布式锁笔记

本地缓存

由于 spring boot 默认是单例的,可以利用map集合存放数据。

问题1缓存击穿 在大量请求同时请求一个缓存中不存在的数据,由于查询数据需要一定的时间。在这段时间内的请求无法在缓存中取得数据,也会直接请求到数据库。

解决方案:将查询数据库的代码上锁,进入被锁住的代码块时先查看缓存中是否存在数据,如果存在直接返回。

问题2

在单机应用程序时没用问题,但是在分布式集群部署时会造成以下问题:

1.不同主机间的缓存数据不能共享(数据不一致)

2.每台主机都需要去查询数据库的问题。

解决方案:使用分布式缓存(比如 redis )

分布式缓存

将数据以 json 的格式存到 redis 中,当需要获取数据时,先查看 redis 中是否存在数据,不存在再去查数据库。

问题1缓存穿透 当大量并发请求一个缓存中不存在,并且数据库中也不存在的数据时,会造成这些请求同时命中数据库。

解决方案:将查询不到的数据也存入 redis 中,并且设置一个过期时间。

问题2缓存雪崩 缓存中大批量数据到过期时间,数据库查询数据量巨大,引起数据库压力过大甚至down机

解决方案:增加随机过期时间

问题3缓存击穿 对于一个缓存中不存在key,在某个时间点被大量并发访问,这些请求都不会命中缓存,都会命中数据库,导致数据库崩溃。

解决方案:加锁(只让一个人去查,查完后放入缓存,其他人去缓存获取)

本地锁

使用synchronized锁住方法或者代码块;

访问数据时先查看缓存中是否存在,如果不存在则查询数据库,查询数据库的代码需要上锁。

问题1:当大量并发请求进入时,都检测到缓存中没用数据,都会执行锁住的代码块查询数据库

解决方案:在进入上锁代码块后再进行一次判断,查看缓存中是否存在数据,如果存在直接在缓存中拿数据。

分布式锁

​ 在 redis 中设置一个key比如设置一个名为 lock 的key,值为1,利用

set lock 1 NX

来设置,如果返回nul则代表key已经存在,已经有人在查询,如果返回OK则代表占用锁成功,执行查询数据库的方法,执行结束后将lock删除即可。

​ 但是这样依然存在问题,假设当拿到锁之后出现了异常,导致无法释放锁。就会造成没有查到数据,并且其他人无法进入查询的方法

可以在 finally 中释放lock锁。

​ 但是当拿到锁之后服务器停电,就会造成finally中的代码无法执行,依然没有解决问题。

​ 为了解决这个问题,我们可以在设置lock这个key的时候给他设置一个过期时间,这样即使一台服务器断电了,lock在到达过期时间后,其他人依然可以去查询数据库。

问题

当程序运行时间超过key的过期时间时,其他人可能已经拿到了锁。

如果这时运行结束,删除lock锁,删除的会是其他人的锁。

解决方案

1.在设置lock锁的时候,生成一个随机的UUID,并且将这个lock的值设置为这个UUID

2.删除时先看断一下lock的值是不是自己设置的UUID,如果一致则删除lock

注意事项:删除时不可以使用代码逻辑来进行判断删除,可能在你判断完UUID后redis的key刚好失效,这时候删除的依然是别人的lock。

一定要使用 lua 脚本进行删除,这个脚本一定是同一时刻执行完毕的:

注意事项

删除时不可以使用代码逻辑来进行判断删除,可能在你判断完UUID后redis的key刚好失效,这时候删除的依然是别人的lock。

一定要使用 lua 脚本进行删除,这个脚本一定是同一时刻执行完毕的:

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值