Redis作为缓存可能会出现的问题及解决方案
Redis是个大话题,只要是去面试Java开发,几乎必问。基础一点的问Redis是什么东西?用来做什么?Redis支持哪些数据类型?Redis的性能为什么那么好?复杂一点的就会问到缓存穿透、缓存击穿、缓存雪崩等问题。而我在面试的时候也被问到了Redis为什么用来做缓存的问题。
所以我觉得很有必要总结一下Redis作为缓存使用,可能会引发的问题。以达到温故而知新的效果
ps:在本文章中,就不讨论Redis能用来干啥?这种基础问题了
一、Redis简介:
在讨论Redis作为缓存使用,可能会引发的问题之前,我们得了解官方是怎么定义Redis
Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。
它支持多种类型的数据结构,如字符串(Strings),散列(Hash),列表(List),集合(Set),有序集合(Sorted Set或者是ZSet)。
Redis 内置了复制(Replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(Transactions) 和不同级别的磁盘持久化(Persistence),并通过 Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(High Availability)。
Redis也提供了两种持久化策略,这些策略可以让用户将自己的数据保存到磁盘上面进行存储。根据实际情况,可以每隔一定时间将数据集以快照的形式保存在磁盘(RDB策略),或者将所有操作成功的命令追加到命令日志中(AOF策略),它会在执行命令时,将被执行的命令复制到硬盘里面,实现实时持久化数据的效果。当然,根据实际开发的需求,你也可以关闭持久化功能,单纯的将Redis作为一个高效的网络的缓存数据功能使用。
二、Redis作为缓存使用,可能会引发的问题(重点)
Redis由C语言开发,并且将数据存储在内存中,可以说Redis完全是基于内存进行操作,对数据读写的速度极快、性能极好。官方提供的数据是可以达到每秒100000+的吞吐量(每秒内查询次数),如此优秀的机制使Redis极其适合作为缓存使用。
1.缓存穿透
程序在处理缓存时,一般是先从缓存查询,如果缓存没有这个key(理解为数据),则会从数据库中查询,并将查询到的数据保存到缓存中去。
好,问题来了,如果有个坏心眼的人向服务器发起请求,去查询一个一定不存在的数据,由于缓存中没有查到对应的数据时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,缓存形同虚设,这就是缓存穿透。
解决方案:
1)最粗暴也是最常用的方法就是,如果一个查询的数据为空(不管是数据不存在还是系统故障),我们就把这个空结果进行缓存,但要把它的过期时间设置得很短,最长不超过5分钟,这样能有效的解决缓存穿透问题。
2)其次,可以采用布隆过滤器,也能解决缓存穿透问题
2.缓存击穿
缓存击穿和缓存穿透在本质上很相似,都是查询数据时缓存失去了作用,导致请求直接去数据库查询数据,但是造成缓存失效的原因却是天差地别。
大量用户在同一时间内访问某热点数据时,存储在缓存中的热点数据却突然失效(过期时间),结果就是大量的请求直接访问数据库,使数据库的压力变大,甚至导致数据库宕机,这就是缓存击穿。
解决方案:比较常用的方法是加互斥锁(mutex)保证数据的一致性。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去访问数据库,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set另一个请求所需要的数据,当操作返回成功时,再进行访问数据库的操作并回设缓存;否则,就重试整个get缓存的方法。
3.缓存雪崩
如果缓存的数据集中在一段时间内大批失效,而不巧的是在这段时间内又有大量用户发起请求访问数据,这样就会造成大量的缓存击穿,所有的请求都会直接去访问数据库,导致数据库在短时间内宕机,这就是缓存雪崩。
ps:这里我使用了夸张的修辞手法。缓存雪崩不一定会造成数据库宕机,但缓存如果发生雪崩现象,那肯定是很严重的
解决方案:
1)加锁排队。加互斥锁,添加信息队列
2)数据预热。可以通过缓存Reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀
3)设置热点缓存永不过时
笔者: 以上问题及解决方案纯粹个人见解,如果有错误的地方,还请指正
Redis作为缓存可能会出现的问题及解决方案
Redis是个大话题,只要是去面试Java开发,几乎必问。基础一点的问Redis是什么东西?用来做什么?Redis支持哪些数据类型?Redis的性能为什么那么好?复杂一点的就会问到缓存穿透、缓存击穿、缓存雪崩等问题。而我在面试的时候也被问到了Redis为什么用来做缓存的问题。
所以我觉得很有必要总结一下Redis作为缓存使用,可能会引发的问题。以达到温故而知新的效果
ps:在本文章中,就不讨论Redis能用来干啥?这种基础问题了
一、Redis简介:
在讨论Redis作为缓存使用,可能会引发的问题之前,我们得了解官方是怎么定义Redis
Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。
它支持多种类型的数据结构,如字符串(Strings),散列(Hash),列表(List),集合(Set),有序集合(Sorted Set或者是ZSet)。
Redis 内置了复制(Replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(Transactions) 和不同级别的磁盘持久化(Persistence),并通过 Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(High Availability)。
Redis也提供了两种持久化策略,这些策略可以让用户将自己的数据保存到磁盘上面进行存储。根据实际情况,可以每隔一定时间将数据集以快照的形式保存在磁盘(RDB策略),或者将所有操作成功的命令追加到命令日志中(AOF策略),它会在执行命令时,将被执行的命令复制到硬盘里面,实现实时持久化数据的效果。当然,根据实际开发的需求,你也可以关闭持久化功能,单纯的将Redis作为一个高效的网络的缓存数据功能使用。
二、Redis作为缓存使用,可能会引发的问题(重点)
Redis由C语言开发,并且将数据存储在内存中,可以说Redis完全是基于内存进行操作,对数据读写的速度极快、性能极好。官方提供的数据是可以达到每秒100000+的吞吐量(每秒内查询次数),如此优秀的机制使Redis极其适合作为缓存使用。
1.缓存穿透
程序在处理缓存时,一般是先从缓存查询,如果缓存没有这个key(理解为数据),则会从数据库中查询,并将查询到的数据保存到缓存中去。
好,问题来了,如果有个坏心眼的人向服务器发起请求,去查询一个一定不存在的数据,由于缓存中没有查到对应的数据时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,缓存形同虚设,这就是缓存穿透。
解决方案:
1)最粗暴也是最常用的方法就是,如果一个查询的数据为空(不管是数据不存在还是系统故障),我们就把这个空结果进行缓存,但要把它的过期时间设置得很短,最长不超过5分钟,这样能有效的解决缓存穿透问题。
2)其次,可以采用布隆过滤器,也能解决缓存穿透问题
2.缓存击穿
缓存击穿和缓存穿透在本质上很相似,都是查询数据时缓存失去了作用,导致请求直接去数据库查询数据,但是造成缓存失效的原因却是天差地别。
大量用户在同一时间内访问某热点数据时,存储在缓存中的热点数据却突然失效(过期时间),结果就是大量的请求直接访问数据库,使数据库的压力变大,甚至导致数据库宕机,这就是缓存击穿。
解决方案:比较常用的方法是加互斥锁(mutex)保证数据的一致性。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去访问数据库,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set另一个请求所需要的数据,当操作返回成功时,再进行访问数据库的操作并回设缓存;否则,就重试整个get缓存的方法。
3.缓存雪崩
如果缓存的数据集中在一段时间内大批失效,而不巧的是在这段时间内又有大量用户发起请求访问数据,这样就会造成大量的缓存击穿,所有的请求都会直接去访问数据库,导致数据库在短时间内宕机,这就是缓存雪崩。
ps:这里我使用了夸张的修辞手法。缓存雪崩不一定会造成数据库宕机,但缓存如果发生雪崩现象,那肯定是很严重的
解决方案:
1)加锁排队。加互斥锁,添加信息队列
2)数据预热。可以通过缓存Reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀
3)设置热点缓存永不过时
笔者: 以上问题及解决方案纯粹个人见解,如果有错误的地方,还请指正
Redis作为缓存可能会出现的问题及解决方案的更多相关文章
- 高并发简单解决方案————redis队列缓存+mysql 批量入库(ThinkPhP)
问题分析 问题一:要求日志最好入库:但是,直接入库mysql确实扛不住,批量入库没有问题,done.[批量入库和直接入库性能差异] 问题二:批量入库就需要有高并发的消息队列,决定采用redis lis ...
- HAProxy 的负载均衡服务器,Redis 的缓存服务器
问答社区网络 StackExchange 由 100 多个网站构成,其中包括了 Alexa 排名第 54 的 StackOverflow.StackExchang 有 400 万用户,每月 5.6 亿 ...
- spring使用redis做缓存
缓存 什么是缓存? 在高并发下,为了提高访问的性能,需要将数据库中 一些经常展现和不会频繁变更的数据,存放在存取速率更快的内存中.这样可以 降低数据的获取时间,带来更好的体验 减轻数据库的压力 缓存适 ...
- 知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路
本文来自知乎官方技术团队的“知乎技术专栏”,感谢原作者陈鹏的无私分享. 1.引言 知乎存储平台团队基于开源Redis 组件打造的知乎 Redis 平台,经过不断的研发迭代,目前已经形成了一整套完整自动 ...
- Spring Boot + Mybatis + Redis二级缓存开发指南
Spring Boot + Mybatis + Redis二级缓存开发指南 背景 Spring-Boot因其提供了各种开箱即用的插件,使得它成为了当今最为主流的Java Web开发框架之一.Mybat ...
- 从单机到2000万 QPS 并发的 Redis 高性能缓存实践之路
1.引言 知乎存储平台团队基于开源Redis 组件打造的知乎 Redis 平台,经过不断的研发迭代,目前已经形成了一整套完整自动化运维服务体系,提供很多强大的功能.本文作者陈鹏是该系统的负责人,本次文 ...
- c#实例化继承类,必须对被继承类的程序集做引用 .net core Redis分布式缓存客户端实现逻辑分析及示例demo 数据库笔记之索引和事务 centos 7下安装python 3.6笔记 你大波哥~ C#开源框架(转载) JSON C# Class Generator ---由json字符串生成C#实体类的工具
c#实例化继承类,必须对被继承类的程序集做引用 0x00 问题 类型“Model.NewModel”在未被引用的程序集中定义.必须添加对程序集“Model, Version=1.0.0.0, Cu ...
- Redis之缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
目录 Redis之缓存雪崩.缓存穿透.缓存预热.缓存更新.缓存降级 1.缓存雪崩 2.缓存穿透 3.缓存预热 4.缓存更新 5.缓存降级 Redis之缓存雪崩.缓存穿透.缓存预热.缓存更新.缓存降级 ...
- Redis 多级缓存架构和数据库与缓存双写不一致问题
采用三级缓存:nginx本地缓存+redis分布式缓存+tomcat堆缓存的多级缓存架构 时效性要求非常高的数据:库存 一般来说,显示的库存,都是时效性要求会相对高一些,因为随着商品的不断的交易,库存 ...
随机推荐
- cocos2dx Mac平台 打印长字符串,游戏卡死
1,打开了输出控制台,输出卡死的解决方案: 打开控制台: game -console enable 关闭控制台: game -console false 修改文件 ConsoleWindowContr ...
- Spring Boot 2 实战:利用Redis的Geo功能实现查找附近的位置
1. 前言 老板突然要上线一个需求,获取当前位置方圆一公里的业务代理点.明天上线!当接到这个需求的时候我差点吐血,这时间也太紧张了.赶紧去查相关的技术选型.经过一番折腾,终于在晚上十点完成了这个需求. ...
- Nginx 如何自定义变量?
之前的两篇文章 Nginx 变量介绍以及利用 Nginx 变量做防盗链 讲的是 Nginx 有哪些变量以及一个常见的应用.那么如此灵活的 Nginx 怎么能不支持自定义变量呢,今天的文章就来说一下自定 ...
- 505. The Maze II
原题链接:https://leetcode.com/articles/the-maze-ii/ 我的思路 在做完了第一道迷宫问题 http://www.cnblogs.com/optor/p/8533 ...
- python黑帽子之tcp客户端
在渗透测试过程中,我们经常会需要创建一个tcp客户端来连接服务,发送垃圾数据,进行模糊测试等任务,所以我们来用python创建一个简单的tcp客户端. import sockettarget_host ...
- Python实用笔记 (7)高级特性——切片
列表L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack'] 取前3个元素 >>> L[0:3] ['Michael', 'Sarah', ' ...
- jquery入门(3)
4.jQuery中的事件绑定 4.1.事件绑定 on方法绑定 $('#box').on('click',function(){ alert(1); }) 直接绑定 $("#box" ...
- js语法基础入门(6)
6.函数 6.1.函数是什么? 函数就是具有名称和一定功能点代码块,这段代码块被封装起来,由一组语句组成,它们是JavaScript的基础模块单元,用于代码复用.信息隐藏和组合调用.一般来说,所谓编程 ...
- org.hibernate.LazyInitializationException异常解决办法
org.hibernate.LazyInitializationException异常failed to lazily initialize a collection...的解决方案使用hiberna ...
- 安装mysql教程
linux下安装mysql 方式一:源码包安装 环境介绍:本安装教程基于虚拟机CentOS7.6版本进行安装,mysql版本为5.7版本. 一.卸载已安装的mysql服务 由于我原本在虚拟机已安装过m ...