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堆缓存的多级缓存架构 时效性要求非常高的数据:库存 一般来说,显示的库存,都是时效性要求会相对高一些,因为随着商品的不断的交易,库存 ...
随机推荐
- SpringBoot + Mybatis + Redis 整合入门项目
这篇文章我决定一改以往的风格,以幽默风趣的故事博文来介绍如何整合 SpringBoot.Mybatis.Redis. 很久很久以前,森林里有一只可爱的小青蛙,他迈着沉重的步伐走向了找工作的道路,结果发 ...
- DES 加密解密 文件工具类
public class DESEncrypt { /** 加密工具 */ private Cipher encryptCipher = null; /** 解密工具 */ private Ciphe ...
- Centos中使用virtualenvwrapper
Centos中使用virtualenvwrapper python特有的一种软件环境,创建多个python环境,各个环境之间完全隔离,互不影响.它可以用来解决Python项目开发和运行过程中的依赖项和 ...
- Appium定位元素
定位元素规则 和 Selenium Web自动化一样,要操作界面元,必须先定位(选择)元素. Appius是基于 Selenium的,所以和 Selenium代码定位元素的基本规则相同 find el ...
- 多语言工作者の十日冲刺<1/10>
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺--第一天(04.30) 作业正文 ...
- win10使用WSL 2运行Docker Desktop,运行文件从C盘迁移到其他目录
前言 前几天重装系统,把系统升到了Windows 10 2004,然后在安装Docker Desktop(2.3.0.3版本)时发现跟以前不太一样了.现在Docker Desktop默认使用WLS 2 ...
- Java工具类—包装类
Java工具类--包装类 我们都知道,JDK 其实给我们提供了很多很多 Java 开发者已经写好的现成的类,他们其实都可以理解成工具类,比如我们常见的集合类,日期相关的类,数学相关的类等等,有了这些工 ...
- 入门大数据---SparkSQL联结操作
一. 数据准备 本文主要介绍 Spark SQL 的多表连接,需要预先准备测试数据.分别创建员工和部门的 Datafame,并注册为临时视图,代码如下: val spark = SparkSessio ...
- MongoDB入门二
MongoDB配置 本地启动 c:\MongoDB\bin>mongod.exe --dbpath "C:\\MongoDB\data\db" --logpath " ...
- 堆、栈、数据区、bss、代码段
一个程序的运行是需要内存的,那么我们平常写的程序的内存都是怎么分配的呢 (1)首先我们要知道,内存是真实存在的,内存是一个物理器件.它时由操作系统管理的,我们平常只要使用它就行了,为了方便管理.操作系 ...