redis知识总结

本人小白一个,不能保证博客中内容都准确,如果博客中有错误的地方,望各位多多指教,请指正。欢迎找我一起讨论

 

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、哨兵模式

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值