redis缓存雪崩概念
A. 12 个问题搞懂 Redis
都说学习需要带着问题,带着思考进行学习,下面就以问题的形式来学习下 Redis 。
1、什么是 Redis ?
2、都说 Redis 是单线程模型,到底是什么意思?
3、为什么在数据读写处理上不使用多线程?
4、为什么使用单线程,速度却很快?
5、单线程处理的瓶颈是什么?
6、Redis 6.0 调整为多线程的原因?
7、在 Redis 中怎样做持久化?
8、常说的缓存雪崩、击穿、穿透是什么?
9、怎样解决雪崩、击穿、穿透带来的问题?
10、怎样设计缓存的淘汰机制?
11、怎样保证缓存和数据库的数据一致?
12、Redis 有什么使用规范?
Redis 的知识远不止如此,本文总结了一些我认为比较重要的一些点,希望对您有所帮助!
B. Redis持久化的方式有哪些优缺点分别是什么
持久化的目的主要是做灾难恢复,数据恢复。由于Redis的数据全都放在内存里面,如果Redis挂了,没有配置持久化的话,重启的时候数据会全部丢失。
突然间,大量的请求过来,缓存全都无法命中,造成缓存雪崩,mysql无法承载大量的请求,造成整个系统崩溃。如果把Redis持久化做好,即使Redis故障了,也能够立即重启,对外提供服务。
Redis持久化分为两种:
AOF持久化配置:
在Redis的配置文件中存在三种同步方式,它们分别是:
RDB的优缺点:
AOF的优缺点:
RDB和AOF如何选择?
rdb是Redis DataBase缩写
功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数
Aof是Append-only file缩写
每当执行服务器(定时)任务或者函数时flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作
aof写入保存:
WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件
SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。
存储结构:
内容是redis通讯协议(RESP )格式的命令文本存储。
比较:
1、aof文件比rdb更新频率高,优先使用aof还原数据。
2、aof比rdb更安全也更大
3、rdb性能比aof好
4、如果两个都配了优先加载AOF
C. redis缓存使用中的热key问题
在Redis中,访问频率高的key称为热点key,当某一热点key的请求到Server主机时,由于请求量特别大,导致主机资源不足,甚至宕机,影响正常的服务
1.用户消费的数据远大于生产的数据,比如热卖商品、热点新闻、热点评论等,这些典型的读多写少的场景会产生热点问题
2.请求分片集中,超过单Server的性能极限,比如 固定名称key,哈希落入一台Server,访问量极大的情况,超过Server极限时,就会导致热点Key问题的产生
1.流量集中,达到物理网卡上限,影响其他key的访问。
2.请求过多,缓存分片服务被打垮,不能通过扩容解决,且不能发挥集群多分片的优势。
3.缓存击穿,可能打到DB,引起业务雪崩。
1.凭借业务经验,进行预估哪些是热key
2.客户端统计收集,本地统计或者上报
3.如果服务端有代理层,可以在代理层进行收集上报
1.增加分片副本,分担读流量
2.热key备份,比如key,备份为key1,key2……keyN,同样的数据N个备份,N个备份分布到不同分片,访问时可随机访问N个备份中的一个,进一步分担读流量
3.使用本地缓存,发现热key后,将热key对应数据加载到应用服务器本地缓存中,访问热key数据时,直接从本地缓存中获取,而不会请求到redis服务器。
http://tigcms.jd.com/details/S11dBQ5M7.html
https://help.aliyun.com/document_detail/67252.html
https://www.cnblogs.com/rjzheng/p/10874537.html
D. 缓存击穿、穿透、雪崩及Redis分布式锁
分布式锁: setnx ,redisson 并发问题
幂等问题: 落表状态,Redis
缓存击穿: 指缓存中无,db中有
原因: 一个key高并发恰好失效导致大量请求到db
方案: 加锁,自旋锁,或一个线程查db,一个线程监控(直接用Redisson分布式锁)
缓存穿透:指缓存和db中均无
原因: 一般是恶意请求
方案: 加布隆过滤,或查db无时,也设置缓存,value为某些特殊表示或"null"
雪崩:指缓存同时大量失效
原因: 大量的key同时失效,db压力加大
方案: 设置失效时间是增加随机数
问题方案文献:
https://www.jianshu.com/p/31ab9b020cd9 (图例分析)
https://blog.csdn.net/fcvtb/article/details/89478554
Redis分布式锁:
事务未执行完锁已到期释放问题:使用Redissoin解决续租问题,内部已解决
分布式锁文献:
https://www.jianshu.com/p/4838f8be00c9
https://blog.csdn.net/qq_30038111/article/details/90696233 (setnx + expire同时操作)
====================================
https://www.runoob.com/redis/keys-scan.html
https://www.jianshu.com/p/611a492d9121 Redis原理与应用
E. Redis - 集群Hash槽分配
常见的Redis集群架构是三主三从的结构,为了保证数据分片,redis采用了Hash槽的概念,即:
常见的三主三从结构,将solt平均分到三个节点上
如果存入一个值,按照redis cluster哈希槽的 算法 : CRC16('key')384 = 6782。 那么就会把这个key 的存储分配到 B 上了。同样,当我连接(A,B,C)任何一个节点想获取'key'这个key时,也会这样的算法,然后内部跳转到B节点上获取数据
新增一个节点D,redis cluster的这种做法是从各个节点的前面各拿取一部分slot到D上,会变成这样:
同样删除一个节点也是类似,移动完成后就可以删除这个节点了。
Redis的Hash槽分配不是 一致性Hash ,一致性Hash是成一个hash环,当节点加入或者失效的时候,在环上顺时针找到对应节点。而Redis集群属于手动分配 线性Hash槽 ,需要手动指定,并且尽量做到各个节点solt平均分配。
而至于为什么Redis没有采用一致性Hash,因为如果一个节点失效,把数据转移到下一个节点,容易造成缓存雪崩,而采用hash槽+副本节点失效的时候从节点自动接替,不易造成雪崩。
F. Redis缓存雪崩就这么简单
在实际项目开发中,我们都知道Redis不可能把所有的数据都缓存起来( 内存昂贵且有限 ),所以Redis需要对数据设置过期时间,并采用的是惰性删除+定期删除两种策略对过期键删除。
如果缓存数据 设置的过期时间是相同 的,并且Redis恰好将这部分数据全部删光了。这就会导致在这段时间内,这些缓存 同时失效 ,全部请求到数据库中。
这就是缓存雪崩 :
缓存雪崩如果发生了,很可能就把我们的数据库 搞垮 ,导致整个服务瘫痪,造成的后果很严重。
对缓存数据设置相同的过期时间,导致某段时间内缓存失效。”
对于“Redis挂掉了”,我们可以有以下的思路:
G. SpringBoot进阶之缓存中间件Redis
大家好,一直以来我都本着 用最通俗的话理解核心的知识点, 我认为所有的难点都离不开 “基础知识” 的铺垫
“大佬可以绕过 ~”
本节给大家讲讲 “java的SpringBoot框架” , 之前我们学习的都是java的基础知识和底层提供的一些能力,我们日常工作都是在写接口。在我们在产品开发中,一般我们都会选择比较稳定的框架来帮我们加速开发,不会自己去造轮子,而在java众多框架中,spring框架表现的非常好,大部分公司都会首选它作为开发框架,而至今,大部分企业都是以 springboot 来构建项目了,一个稳健的系统需要引入稳定的技术~
如果你是一路看过来的,很高兴你能够耐心看完。前几期都是带大家学习了 SpringBoot 的基础使用以及集成 mybatis 开发,这也是我们写业务的基础,如果你还不熟悉这些,请先看完它们。接下来的几期内容将会带大家进阶使用,会先讲解基础 中间件 的使用和一些场景的应用,或许这些技术你听说过,没看过也没关系,我会带大家一步一步的入门,耐心看完你一定会有 收获 ,本期将会给大家讲解最热门的缓存中间件技术 Redis ,同样的,我们集成到 Springboot 中。最近github可能会被墙,所以我把源码放到了国内gitee上,本节我们依然使用上期的代码
Redis 是由意大利人Salvatore Sanfilippo(网名:antirez)开发的一款内存高速缓存数据库。全称叫 Remote Dictionary Server(远程数据服务) 是由 C语言 编写的,Redis是一个 key-value 存储系统,它支持丰富的数据类型,如: string、list、set、zset(sorted set)、hash 。
它本质上是一种键值对数据库,我们之前学习的 mysql 它是持久层的关系型数据库,而 redis 它的存储主要存在 内存 中。我们都知道在 内存 中的数据读取是非常快的,就好比你把一个变量存到磁盘读取和直接放到代码中运行,肯定是在代码中拿到的速度快,因为运行时期,都是直接存到内存的。
给大家总结一下:
有了基本的概念之后,我们下面进行环境搭建,在学习阶段,安装 redis 很简单,生产环境一般我们也会选择云产品,一切为了服务保障,虽说它只是做缓存用,但也是系统的一把 保护伞
如果你是 mac 用户,你可以运行如下命令:
安装完成后会提示你运行命令,运行即可。
win 用户也很简单,直接下载 redis 软件,双击运行即可,运行之后它会有一个小方块的图案,和 locahost:6379 的log,说明运行成功了。初始阶段没有配置的 redis 默认 host 就是本地, port 就是 6379 , 而且是 没有密码 就可以访问的。
推荐一个客户端软件 Redis Desktop Manager ,它是 redis 的客户端界面软件,方便面我们学习的时候 清理缓存 使用,生产慎连。
我们不给大家讲它的基本命令使用,它也有语法,可以通过类似命令执行,如果想学习的小伙伴,可以自行搜索。本期重点内容是在 sprinboot 中的使用,我们平时开发不可能是去命令行里敲的,都是代码里执行,而目前市面上有很多封装好的库,我们可以直接调用它的方法,很方便的就可以操作它了,不用记一些繁琐的命令,下面我们就实际操作一下:
修改 pom.xml
修改 application.yml :
redis 默认是有 16 个库,不是 15 个啊,从 0 开始算的,我们随便连一个
通过代码很好理解, 首先需要引入 StringRedisTemplate ,然后需要设置一个 key ,那么思考一下,这个 key 允许重复吗
我们进客户端看一下,发现 key 还是只有一个,但是值变成了新的值了,所以可以得知 key 是唯一的,我们重新设置的时候相当于刷新了它。
在 redis 中删除缓存有两种方式,一种是自我消亡,也就是 过期 销毁,还有有一种是 主动 销毁,我们先看一下,过期时间如何设置
我们设置了 10s 后过期,过完10s后发现,这个```key data``消失了。我们在看看如何主动删除
我们可以利用 Redis 做一个计数器,实现自增功能,你可以用它做网站访问统计
通常做法,我们会把它封装一下,后续使用直接引入封装好的即可,把它直接交给 Springboot容器 管理
其实这个类,你还可以继续进一步封装,比如约束 key 的规范,约束过期时间,约束数据类型等等,这一切也都是为了规范和后期维护,防止滥用缓存
缓存的主要场景是用于解决热点数据问题,因为这些数据是访问频率比较高的,当大量的请求进来, mysql 可能压力很大,这样一来,数据查询效率就很慢,用户肯不高兴等了,这样用户体验很不好。所以我们一般做法,都是把这些热点数据放到缓存里,因为缓存读取速度很快。当有新数据的时候,我们再及时更新它,一般流程是先查询缓存,查到了直接返回缓存数据,查不到再走数据库,然后再刷回缓存。
但是并发足够大的时候,还是会暴露出很多问题,比如面试常问的一些高频问题 缓存雪崩、缓存穿透、缓存雪崩 ,这些问题后边会给大家专门讲,和如何去防范。所以总的来说,引入任何一门技术并不是万事大吉,还需我们不断的在实践中积累经验
本期到这里就结束了,总结一下,我们了解了什么是 redis ,以及在 springboot 中如何去使用它们,很简单,没什么复杂的东西。但这里想多说一点的是,缓存的设计却是很复杂的,因为工具是死的,人是活的,我们如何正确设计,需要我们在项目中不断的积累。
我们之前教大家查询列表数据,都是所有数据返回,还没有教大家如何去做分页,下期将带大家学习一下 mybatis 分页插件的使用 ,下期不见不散, 关注我,不迷路~
H. redis常见问题
1. 缓存击穿
缓存击穿是指一个请求要访问的数据,缓存中没有,但数据库中有的情况。这种情况一般都是缓存过期了。
但是这时由于并发访问这个缓存的用户特别多,这是一个热点 key,这么多用户的请求同时过来,在缓存里面没有取到数据,所以又同时去访问数据库取数据,引起数据库流量激增,压力瞬间增大,直接崩溃给你看。
所以一个数据有缓存,每次请求都从缓存中快速的返回了数据,但是某个时间点缓存失效了,某个请求在缓存中没有请求到数据,这时候我们就说这个请求就"击穿"了缓存。
针对这个场景,对应的解决方案一般来说有三种。
借助Redis setNX命令设置一个标志位就行。设置成功的放行,设置失败的就轮询等待。就是在更新缓存时加把锁
后台开一个定时任务,专门主动更新过期数据
比如程序中设置 why 这个热点 key 的时候,同时设置了过期时间为 10 分钟,那后台程序在第 8 分钟的时候,会去数据库查询数据并重新放到缓存中,同时再次设置缓存为 10 分钟。
其实上面的后台续命思想的最终体现是也是永不过期。
只是后台续命的思想,会主动更新缓存,适用于缓存会变的场景。会出现缓存不一致的情况,取决于你的业务场景能接受多长时间的缓存不一致。
2. 缓存穿透
缓存穿透是指一个请求要访问的数据,缓存和数据库中都没有,而用户短时间、高密度的发起这样的请求,每次都打到数据库服务上,给数据库造成了压力。一般来说这样的请求属于恶意请求。
解决方案有两种:
就是在数据库即使没有查询到数据,我们也把这次请求当做 key 缓存起来,value 可以是 NULL。下次同样请求就会命中这个 NULL,缓存层就处理了这个请求,不会对数据库产生压力。这样实现起来简单,开发成本很低。
3. 缓存雪崩
缓存雪崩是指缓存中大多数的数据在同一时间到达过期时间,而查询数据量巨大,这时候,又是缓存中没有,数据库中有的情况了。
防止雪崩的方案简单来说就是错峰过期。
在设置 key 过期时间的时候,在加上一个短的随机过期时间,这样就能避免大量缓存在同一时间过期,引起的缓存雪崩。
如果发了雪崩,我们可以有服务降级、熔断、限流手段来拒绝一些请求,保证服务的正常。但是,这些对用户体验是有一定影响的。
4. Redis 高可用架构
Redis 高可用架构,大家基本上都能想到主从、哨兵、集群这三种模式。
哨兵模式:
它主要执行三种类型的任务:
哨兵其实也是一个分布式系统,我们可以运行多个哨兵。
然后这些哨兵之间需要相互通气,交流信息,通过投票来决定是否执行自动故障迁移,以及选择哪个从服务器作为新的主服务器。
哨兵之间采用的协议是 gossip,是一种去中心化的协议,达成的是最终一致性。
选举规则: