关于数据库缓存的各种问题及其解决方法
在高qps的系统中,为了避免每次请求都查询数据库,给数据库造成很大的压力,一般都会使用缓存来减轻数据库的访问压力。不过缓存的一些问题会导致缓存失去应有的作用,使得请求还是访问了数据库,给数据库造成了很大的压力。这些问题包括
- 缓冲穿透
- 缓冲击穿
- 缓冲雪崩
一、缓存穿透
缓冲穿透是指请求查询的数据,在数据库中根本不存在,所以缓存中也不会有,这样每次请求都会查询数据库的现象。
常见的解决方案有两种,一是缓存空值,二是使用布隆过滤器。
1.1 缓存空值
发生缓存穿透,是因为缓存中没有存储这些空数据的key。从而导致每次查询都到数据库去了。那么我们就可以为这些key在缓存中设置空值null。后面再出现查询这个key 的请求的时候,直接返回设置的空值即可。当然为了健壮性,我们要对这些key设置过期时间,以防止真的出现数据。
1.2 bloom filter(布隆过滤器)
BloomFilter 类似于一个hbase set 用来判断某个元素(key)是否存在于某个集合中。我们把有数据的key都放到BloomFilter中,每次查询的时候都先去BloomFilter判断,如果没有就直接返回null,这样也就不会查询数据库了。
在实际应用中,这两种方法会组合使用,即先经过布隆过滤器,过滤掉不存在的key,然后查询缓存,如果没有数据,那么返回缓存中的空值。另外,BloomFilter没有删除操作,对于删除的key,查询就会经过BloomFilter然后查询缓存再查询数据库,所以对于删除的key,也可以在缓存中存储空值来避免查询数据库。
另外,还可以在接口层做一些基础校验,避免恶意攻击,比如用户鉴权,id<=0的直接拦截等。
二、缓存击穿
缓存击穿是指大量请求同时查询一个key时,这个key刚好失效,使得大量请求都去查询数据库的现象。这样的key一般是热点数据。缓存击穿是单个key的过期问题引起的,而缓存雪崩是大量key过期引起的。
解决方案有两种,一是使用互斥锁或分布式锁,二是设置热点数据永不过期
2.1 互斥锁或分布式锁
当这些请求查询数据库时,只有第一个请求会拿到锁,其他请求的线程因为没有锁而被阻塞,就不会查询数据库。等第一个请求查询后,数据进行缓存,其他请求发现缓存中已经有数据,就不会再查询数据库。
//互斥锁
public static String getDate(String key) throws InterruptedException{String result = getDataFromCache(key);if(result == null){if(reenLock.tryLock()){result = getDataFromDb(key);if(result != null){setDataToCache(key, result);}reenLock.unlock();}else{Thread.sleep(100);result = getData(key);}}return result;
}
三、缓存雪崩
缓存雪崩是指由于某些原因,在同一时刻发生大量缓存失效,导致大量请求查询数据库的现象。比如缓存服务器宕机或大量缓存过期时间相同而同时过期等原因。
解决方案
3.1 使用缓存集群
对于缓存服务器宕机的情况,可以使用缓存集群实现高可用性。使用集群的另一个好处是可以把不同热点数据分布在不同缓存服务器上。
3.2 设置分散的过期时间
对于大量缓存同时过期的问题,可以将过期时间分散开,比如在原有过期时间上增加一个随机值,这样缓存的过期时间的重复率就会降低,就很难引发集体失效的情况。
3.3 设置热点数据永不过期
更多参考
https://blog.csdn.net/zeb_perfect/article/details/54135506
https://juejin.im/post/5c9a67ac6fb9a070cb24bf34
关于数据库缓存的各种问题及其解决方法相关推荐
- greenDAO缓存遇到的大坑的解决方法
greenDAO缓存遇到的大坑的解决方法 参考文章: (1)greenDAO缓存遇到的大坑的解决方法 (2)https://www.cnblogs.com/yongfengnice/p/1146635 ...
- Mysql 数据库锁表的原因和解决方法
Mysql 数据库锁表的原因和解决方法 参考文章: (1)Mysql 数据库锁表的原因和解决方法 (2)https://www.cnblogs.com/xinruyi/p/11108795.html ...
- windows下本地或者远程连接MYSQL数据库,报1130错误的解决方法
windows下本地或者远程连接MYSQL数据库,报1130错误的解决方法 参考文章: (1)windows下本地或者远程连接MYSQL数据库,报1130错误的解决方法 (2)https://www. ...
- SQL Server2008附加数据库之后显示为只读时解决方法
SQL Server2008附加数据库之后显示为只读时解决方法 啰嗦的话就不多说了,直入主题吧! 方案一: 碰到这中情况一般是使用的sa账户登录的,只要改为Windows身份验证,再附加数据库即可搞定 ...
- mysql 自动停止_MySQL数据库之mysql自动停止的完美解决方法
本文主要向大家介绍了MySQL数据库之mysql自动停止的完美解决方法 ,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助. 这两天新买的服务器mysql总是自动停止,查了日志 9:1 ...
- (转载)SQL Server2008附加数据库之后显示为只读时解决方法
SQL Server2008附加数据库之后显示为只读时解决方法 啰嗦的话就不多说了,直入主题吧! 方案一: 碰到这中情况一般是使用的sa账户登录的,只要改为Windows身份验证,再附加数据库即可搞定 ...
- 登陆SQL Server 2000数据库提示超时已过期的解决方法
登陆SQL Server 2000数据库提示超时已过期的解决方法 参考文章: (1)登陆SQL Server 2000数据库提示超时已过期的解决方法 (2)https://www.cnblogs.co ...
- mysql数据库主从不同步_MySQL数据库之mysql主从数据库不同步的2种解决方法
本文主要向大家介绍了MySQL数据库之mysql主从数据库不同步的2种解决方法 ,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助. 今天发现Mysql的主从数据库没有同步 先上Mas ...
- ORACLE数据库占用大量硬盘空间常规解决方法
ORACLE数据库占用大量硬盘空间常规解决方法 参考文章: (1)ORACLE数据库占用大量硬盘空间常规解决方法 (2)https://www.cnblogs.com/mei992599/p/3877 ...
最新文章
- C#类中的internal成员可能是一种坏味道
- oracle一条语句递归查询父子关系
- 北邮OJ 2016网预 - Saber's Conjecture
- 分布式文件系统之Hdfs是什么?
- 怎么修改file文件框的无文件提示_使用LativeLink时,DO文件编制步骤
- Java 错误:找不到或无法加载主类(源文件中含有包名 package)
- grpc python 多进程_Python多进程通信Queue、Pipe、Value、Array实例
- Sobel边缘检测算子OpenCV实现
- Apple M1 开启HiDPI的新方法,无需关闭SIP,无需SwitchResX
- man 1;man2 ;man 3区别
- [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content.
- html5图片无限循环播放,原生js实现无限循环轮播图效果
- rgb html转换,RGB与十六进制数值互转(html)
- 1. Win 10 :在此处打开命令窗口
- Linux/Unix关机、重启(shutdown\reboot\halt\init)等命令
- Python自动化:提取扫描件中的文字
- python包导入详解
- CEGUI 动画系统
- lua中面向对象(class)实现探索(一)
- 从FPGA到camera ISP漫谈