目录
1. 最基本的业务逻辑是:
2. 高并发场景下常见的缓存问题
2.1问题一 缓存穿透 : 一直查询不存在的数据
解决方案 : 短暂缓存null结果
2.2 问题二 缓存雪崩 : 大量key同时过期大量请求直击数据库
解决方案 : 在原有的过期时间上加一个随机的值,防止同时过期
2.3 问题三 缓存击穿 : 一个热点key过期此时大量请求直接到达数据库解决方案 : 控制一个人获得锁后查询数据库,查到后释放锁,其他人等待锁,获得锁后先查询缓存,然后根据情况判断是否查询数据库
3. 解决缓存击穿问题
3.1 首先想到的是使用synchronized加锁:
3.2 使用分布式锁
在常见的高并发量的场景下,为了避免线程抢占资源带来的问题,对资源上锁是很常见的操作,但是如果稍不留神就有可能因上锁而带来新的问题,此篇日记将在最常见的场景下梳理单体项目加锁到分布式项目加锁的整个流程以及常见的一些问题。
首先介绍业务背景,某商城商品三级分类列表数据的查询问题,分类列表数据作为热点数据,应该存放在缓存中。(此处不介绍本地缓存容易带来的数据一致性等问题,使用缓存中间件redis)
1. 最基本的业务逻辑是:
1.请求分类数据。
2.查询是否在缓存中,若从缓存中查询到则直接返回。
3.若不在缓存中,则查询数据库,查询后写入缓存。
上面的业务逻辑在高并发的场景下会遇见常见的三个问题:
2. 高并发场景下常见的缓存问题
2.1问题一 缓存穿透 : 一直查询不存在的数据
解决方案 : 短暂缓存null结果
2.2 问题二 缓存雪崩 : 大量key同时过期大量请求直击数据库
解决方案 : 在原有的过期时间上加一个随机的值,防止同时过期
2.3 问题三 缓存击穿 : 一个热点key过期此时大量请求直接到达数据库解决方案 : 控制一个人获得锁后查询数据库,查到后释放锁,其他人等待锁,获得锁后先查询缓存,然后根据情况判断是否查询数据库
前面的三个问题中,缓存穿透加null结果缓存与缓存雪崩过期时间加随机值都可以得到解决。而解决缓存击穿在于控制多线程中的同一时刻只能有一个线程可以获得锁查询数据库。
3. 解决缓存击穿问题
3.1 首先想到的是使用synchronized加锁:
synchronized(this){//获取数据业务逻辑}
这样操作单个服务器上没有什么问题,但在分布式系统下this获取对象锁只能在本服务器加锁,无法控制所有服务器同时只有一个服务器获得锁:
若是众多请求负载均衡到不同服务器上则同时就有众多请求直达数据库。因此需要引入分布式锁的概念。
3.2 使用分布式锁
详细请看: 分布式锁2 - redis实现分布式锁并解决常见问题