本人小白一个,不能保证博客中内容都准确,如果博客中有错误的地方,望各位多多指教,请指正。欢迎找我一起讨论
redis知识总结
1、redis是什么?是用来干什么的?适合存储哪些数据?
redis 是用 C语言编写的一个非关系型数据库
redis可以用来做缓存,分布式锁
redis适合存储 高频的热点数据---广告 、用户经常访问的数据
2、为什么redis是单线程的 速度还那么快?
redis是基于内存的,绝大部分请求都是纯粹的内存操作,速度非常快,
数据结构非常简单,对数据操作也简单
采用的是单线程,避免了上下文切换和竞争条件,不存在多个线程切换导致的CPU消耗,也不用考虑锁的问题
使用多路复用IO模型,非阻塞IO
3、介绍一下 redis的持久化策略
RDB (默认) : 按照一定的时间将内存的数据以快照的形式保存在硬盘 全量同步用RDB
AOF :将redis执行的每次写命令记录到单独的日志文件中,当重启redis时,会通过执行这个日志文件中记录的操作来恢复数据 增量同步用AOF
当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复
4、谈谈 AOF和 RDB的优劣势
RDB 文件小,对性能的消耗小,恢复速度快,但会出现丢失的现象 (RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失)
AOF 文件比较大,对性能消耗大,恢复速度比较慢 ,数据安全
5、redis有哪些数据结构,分别适合什么样的场景使用?
String - 验证码、用户认证信息、普通缓存数据
List - 可以用作消息队列
Hash - 用户购物车数据、秒杀时间段对应商品信息
set - 可以实现获取两个集合的差集、交集,比如共同好友
zset - 可以用来实现优先级队列(比如延迟任务队列)
6、redis 三大问题 雪崩、击穿、穿透
缓存雪崩
redis挂了,或者大批量key同时失效,让很多请求访问mysql
100W条不同的数据 过期时间都是 10天,那么10天过后 这100W条数据 全部同时失效
解决方案
-
redis挂了 ,解决就是搭建集群(cluster)
-
大批量key同时失效,解决就是,错开数据过期时间 10W设置一个过期时间 5W设置一个过期时间 20W设置一个过期时间......
-
如果已经出现了雪崩,那就降级、熔断
redis 雪崩 : 大量的key在同一时间失效 ,导致大量请求直接访问数据库
解决: 错开过期时间
缓存击穿 : 数据库中有这条数据,缓存中没有
某个热点数据刚好过期(失效),redis把这条数据自动删除了,此时,大量并发因缓存过期未命中redis,导致请求mysql
解决方案
-
针对某个key过期后,使用分布式锁机制,查询mysql数据库之前 加一把锁, 让第一个线程 查询mysql 之前 重新查询缓存,如果还是查不到,就去mysql中查询,然后将数据缓存到redis 中,其它线程在第一个线程从新缓存redis后从redis读取数据。就第一个线程访问了数据库,其他线程都是访问的缓存 。
-
高热数据不过期
缓存穿透 : 数据库 和 redis中都没有这条数据
大量的不存在的key值(查询的key值在redis中和mysql数据库中都没有数据,这个值根本就不存在, 比如 id = -1 , 在mysql中id自增主键 不肯能为 -1 ,所以此时在redis中和mysql数据库中都没有数据,直接穿透了redis 和 数据库 ),透过redis,查询mysql
解决方案
-
布隆过滤器(位数组-hash结构),判断key是否存在(正常值),如果不存在则直接响应(避免请求mysql)
代码复杂,难维护,因为往数据库中添加一条数据,也要同时向布隆过滤器中添加一条,不然的话就会当作非法请求,直接拦截。另外一个 比如: 数据库中数据有10W条数据,现在删除了 8 W (此时就会出现占用内存 提高误判,所以才要重建,当然不重建也可以,只要你能扛得住这个内存消耗和误判),但是布隆过滤器不能删除,此时要考虑重建,也就是重新初始化布隆过滤器 (可以用定时任务,定时更新频率要看删除的数据多少来定)
具体描述:将查询表中字段的所有值存入 布隆过滤器,比如要查表中一个id字段,那么我就把这个表中id字段的所以的值加入到布隆过滤器,然后比如要查询这个id,在查询之前就先访问布隆过滤器。
-
缓存空对象: 效果不是很好,因为第一次仍然会去查数据库,换一个不存在的数据的key,仍然会去查询数据库,这样会导致redis中有大量没用的数据,占redis的内存。所以它解决的是 一个key多次访问的问题。
具体描述:查询一条不存在的数据的时候,也就是说这条数据在数据库中不能查到,把这条数据加入到redis缓存,key不变,value设置为空对象,然后在查询redis的时候加个判断,判断这个key对应的value是不是空对象,如果是直接返回 “查询无果” 。 这样的话 同一个key第二次访问就不会走数据库了,直接在redis就能查到。
7、redis和数据库数据不一致问题
什么情况下 会出现这样的问题 ? 更新操作的时候
比如说 我现在数据库中有1001 条数据 redis中也有1001条数据 ,现在要更新数据,那应该怎么更新数据呢?
场景一: 先更新数据库中数据,再更新redis缓存数据,如果 更新redis缓存数据失败了呢,redis宕机?此时 数据库中是新数据,redis中是旧数据,数据出现了不一致
场景二: 先更新数据库中数据,再更新redis缓存数据,如果因为网络等原因,线程B 比线程A先更新了redis缓存,此时就出现了数据不一致(脏数据)
解决:
先删除缓存,再修改数据库。如果数据库修改失败了,那么数据库中的是旧数据,缓存中是空的,那么数据不会不一致。因为读的时候缓存没有,则读数据库中的旧数据,然后更新到缓存中
场景三: 先删除缓存,再更新数据库。此时数据发生了变更,先删除缓存,再去修改数据库,此时另外一个请求过来,去读缓存,发现缓存是空的去查询数据库,查到的是旧数据,更新到缓存中,随后数据变更的程序完成了数据库的值更新了,此时数据库和缓存中的数据不一样。
解决:
方案一: 延时双删 删除redis-->更新mysql-->延时5秒钟-->删除redis
.
方案二 (解决读多写少的场景) : 用读写锁 优化 读写锁 的锁对象 要一样 可以使用 Redisson 直接 获取锁 底用的是 lua脚本 在设置每个key的时候绑定了一个mode
,读锁绑定了一个 read mode 写锁绑定了一个 write mode
方案三 (解决读多写多的场景) :
缓存设置一个超时时间(这个时间要根据业务场景来定) 又要用缓存 又要用数据库 又要支撑高并发 ,只能去保证最终一致性
读多写多的场景 就不应该用缓存 ,直接读数据库不就可以了
读多写多的场景 又要用缓存 怎么解决数据不一致 (保证一致性,非最终一致性,可以理解为强一致性) ? cannal中间件可以解决
8、redis的删除策略
-
定时删除 创建一个定时器
-
描述:利用定时任务,扫描全部的键,删除过期键
-
优点:可以及时的删除过期数据,对内存消耗小
-
缺点:扫描时对cpu消耗太大
-
-
惰性删除:
-
描述:什么时候用这个键,再去expires中查找对应的过期时间,过期了就删除
-
优点:cpu消耗小
-
缺点:内存里面可能存在很多过期的数据
-
-
定期删除:
-
描述:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
-
优点:对于之前的两种策略做了一个时间和空间选择的权衡
-
9、redis 淘汰策略(三类八种)
-
第一种策略:检测expires将要过期的数据
-
volatile-lru:它对带过期时间的 key 采用最近最少访问(空闲时间最久)算法来淘汰 (没有设置过期时间的不会被淘汰)
如果有一些数据一直放在内存数据库中,一些数据可以被淘汰 可以使用这种策略
---- 手写lru 基于 linkedHashMap ( 核心 如果数据最近被访问过,将来它可能被访问的几率大于其他的key )
-
volatile-lfu:它对带过期时间的 key 采用最近最不经常使用(一段时间内的使用频率最小)的算法来淘汰
-
volatile-ttl:对带过期时间的 key 中选择最早要过期的 key 进行淘汰
需要设置ttl 来确定数据过期顺序,这个策略比较合适
-
volatile-random:它是对带过期时间的 key 中随机选择 key 进行淘汰
如果有一些数据一直放在内存数据库中,一些数据可以被淘汰 可以使用这种策略
-
-
第二种策略:全部数据检测
-
allkeys-lru:从内存库中所有的key中,挑选最近最少使用的数据淘汰 (一部分数据访问频率比较高,一部分比较低,这个策略相对比较合适)
如果某一个key设置了过期时间,这种情况下,这个策略比较好,可以高效利用内存
-
allkeLyRs-lfu:从内存库中所有的key中,挑选最近使用次数最少的数据淘汰
-
allkeys-random:从内存库中所有的key中,任意选择数据淘汰,相当于随机 (如果所有的数据访问频率大概相等,这个策略比较合适)
-
-
第三种:放弃数据淘汰
-
no-enviction(驱逐):禁止驱逐数据(redis4.0中默认策略),当内存不足以容纳新的数据时,新写入操作就好报错,会引发OOM(Out Of Memory)
-
10、redis做分布式锁
11、主从复制
12、哨兵模式