你不知道的Redis

目录

1.Redis过期key是怎么样清理的?

2.如何解决Redis缓存穿透问题

3.如何解决Redis缓存击穿问题

4.如何解决Redis缓存雪崩问题

5.如何解决缓存与数据库的数据一致性问题?

6. Redis的持久化

7.Redis主从同步如何实现的?

8. Redis哨兵系统是怎么实现自动故障迁移的?


1.Redis过期key是怎么样清理的?

1. 惰性清理

在访问key时,如果发现key已经过期,那么会将key删除

2. 定时清理

Redis配置项hz定义了serverCron任务的执行周期,默认每次清理时间为25ms,每次清理会依次遍历所有DB,从db的expires字典(里面保存了设置了过期时间的键值对,key就是指向键对象,value是过期时间)中随机取出20个key,如果过期就删除,如果其中有5个key过期,说明过期率超过了25%,那么就继续对这个db进行清理,否则开始清理下一个db。

3. 内存不够的时候清理

当执行写入命令时,如果发现内存不够,那么会按照配置的淘汰策略清理内存

  •  第一类:不处理,等报错(默认)
    • noeviction,发现内存不够时,不删除key,执行写入命令,直接报错
  • 第二类:在所有结果集中进行挑选,淘汰key
    • allkeys-random  就是从所有的key中随机淘汰key
    • allkeys-lru 就是从所有的key中找使用时间距离现在最远的key,进行淘汰
    • allkeys-lfu 就是从所有的key中找使用频率最少的key,进行淘汰
  • 第三类:在设置了过期时间的结果集中进行挑选,淘汰key
    • volatile-random 从设置过期时间的key中随机挑选,进行淘汰
    • volatile-lru 从设置过期时间的结果集中找使用时间距离现在最远的key,进行淘汰
    • volatile-lfu 从设置过期时间的结果集中找使用频率最少的key,进行淘汰
    • volatile-ttl 从设置过期时间的结果集中找存活时间最短的key,进行淘汰

LRU算法

LRU算法的设计原则是如果一个数据近期没有被访问到,那么之后一段时间都不会被访问到。所以当元素个数达到限制的值时,优先移除距离上次使用时间最久的元素。

LFU算法

LFU算法的设计原则时,如果一个数据在最近一段时间被访问的时次数越多,那么之后被访问的概率会越大,实现是每个数据都有一个引用计数,每次数据被访问后,引用计数加1,需要淘汰数据时,淘汰引用计数最小的数据。在Redis的实现中,每次key被访问后,引用计数是加一个介于0到1之间的数p,并且访问越频繁p值越大,而且在一定的时间间隔内,如果key没有被访问,引用计数会减少。

2.如何解决Redis缓存穿透问题

Redis 缓存穿透指的是攻击者故意大量请求一些Redis缓存中不存在key的数据,导致请 求打到数据库上,导致数据库压力过大。

解决方案如下:

1.做好参数校验,无效的请求直接返回,只能避免一部分情况,攻击者总是可以找到一些没有覆盖的情况。

2.对缓存中找不到的key,需要去数据库查找的key,缓存到Redis中,但是可能会导致Redis中缓存大量无效的key,可以设置一个很短的过期时间,例如1分钟。

3.也可以使用布隆过滤器,将所有可能的存在的数据通过去hash值的方式存入到一个足够大的bitmap中去,处理请求时,通过在bitmap中查找,可以将不存在的数据拦截掉。

3.如何解决Redis缓存击穿问题

缓存击穿主要指的是某个热点key失效,导致大量请求全部转向数据库,导致数据库压力过大。

解决方案:

1.对热点key设置永不过期。

2.加互斥锁(分布式锁),缓存中没有热点key对应的数据时,等待100ms,由获得锁的线程去读取数据库然后设置缓存。

4.如何解决Redis缓存雪崩问题

缓存雪崩主要指的是短时间内大量key失效,导致所有请求全部转向数据库,导致数据库压力过大。

解决方案:

1.在给缓存设置失效时间时加一个随机值,避免集体失效。

2.双缓存机制,缓存A的失效时间为20分钟,缓存B的失效时间会比A长一些,从缓存A读取数据,缓存A中没有时,去缓存B中读取数据,并且启动一个异步线程来更新缓存A(如果已经有异步线程正在更新了,就不用重复更新了)。以及更新缓存B,以便延迟B的过期时间。

5.如何解决缓存与数据库的数据一致性问题?

为什么是删除缓存而不是更新缓存呢?

  1. 线程A先发起一个写操作,第一步先更新数据库
  2. 线程B发起一个写操作,第二部更新了数据库
  3. 由于网络原因,线程A更新缓存的时候卡住了,导致线程B先更新了缓存
  4. 网络好了,线程A更新缓存。最终会导致数据不一致

更新缓存相对于删除缓存还有以下优势

  1. 如果你写入的缓存之是经过复杂计算得到的,更新缓存频率高的话,会浪费性能。

先更新数据库,在删除缓存

 流程:

  1. 先更新数据库
  2. 删除缓存

 

缓存延时双删

延迟双删流程:

  1. 先删除缓存
  2. 再更新数据库
  3. 休眠一会(比如1秒),再删除缓存

这种方案还算可以,只有休眠那一会,可能会有脏数据,一般业务也会接收。但是如果第二次删除缓存失败,此时缓存和数据库就不一致,可以给key设置一个过期时间,但是在这个时间内都是脏数据,看业务是否接口咯。接下来解决这个问题!

删除缓存重试机制

延时双删策略,会存在第二步的删除缓存失败,导致数据不一致问题。

删除缓存重试机制流程:

  1. 写请求更新数据库
  2. 缓存因为某些原因,删除失败
  3. 把删除失败的key放到消息队列中
  4. 消费消息队列的消息,获取要删除的key
  5. 重试删除缓存操作

6. Redis的持久化

RDB持久化:

        RDB 持久化指的是在满足一定的触发条件时(在一个的时间间隔内执行修改命令达到一定的数量,或者手动执行SAVE和BGSAVE命令),对这个时间点的数据库所有键值对信息生成一个压缩文件dump.rdb,然后将旧的 rbd文件删除,进行替换。

        实现原理是fork一个子进程,然后对键值对进行遍历,生成rdb文件,在生成过程中,父进程会继续处理客户端发来的写请求,当父进程要对数据修改时,会对相关的页内存进行拷贝复制,修改拷贝后的数据(即写时复制技术),修改完成后会覆盖原来的数据。

AOF持久化:

       AOF持久化主要是Redis在修改相关的命令后,将命令添加到aof_buf缓存区(aof_buf是Redis中的SDS结构,SDS结构可以认为是对C语言中字符串的扩展)的末尾,然后在每次事件循环结束时,根据appendfsync的配置(always是每次事件循环都将aof_buf缓冲区的内容写入,everysec是每秒写入,no是根据操作系统来决定何时写入),判断是否需要将aof_buf写入AOF文件。生产环境中一般用默认配置everysec,也就是每秒写入一次,一旦挂机会丢掉1分钟的数据。

7.Redis主从同步如何实现的?

主从节点建立连接后,从节点会判断:

1. 如何从节点之前没有同步数据,属于初次复制,会进行全量重同步,从节点会给主节点发命令,请求主节点进行全量同步

2.如果从节点不是初次复制(例如掉线重连),会判断Replication ID(主节点的id)和当前的Replication ID是否一致

        如果不一致,进行全量重同步

        如果一致,进行部分重同步

全量重同步:

        主节点会fork一个子进程执行 BGSAVE命令,fork出一个子进程,在后台生成一个RDB持久化文件,完成后,发送给从节点,从节点会载入rdb文件。如果在生成RDB文件期间,主节点也会使用一个缓冲区来记录这个期间执行的所有写命令,从节点载入RDB文件结束后,从节点会执行缓冲区中的命令。

部分重同步:

        因为此时从节点只是落后主节点一小段时间的数据修改,并且偏移量在复制缓冲区buffer中可以找到,所以主节点把从节点落后的这部分数据修改命令发送给从节点,完成同步。

命令传播:

        在执行全量重同步或者部分重同步以后,主从节点的数据库状态达到一致后,会进入到命令传播阶段。主节点执行修改命令后,会将修改命令添加到内存中的buffer缓冲区(是一个定长的环形数组,满了时就会覆盖前面的数据),然后异步地将buffer缓冲区的命令发送给从节点。

8. Redis哨兵系统是怎么实现自动故障迁移的?

1.哨兵认定主节点主观下线

        每隔2s,哨兵节点会给主节点发送ping命令,如果在一定时间间隔内,没有收到回复,那么该哨兵节点就认为节点主观下线

2. 认定节点主节点客观下线

        哨兵节点认定主节点主观下线后,会向其他哨兵节点发送命令,获取其他哨兵节点对该主节点的状态,当认定主节点下线的哨兵数量达到一定阈值时,就认为主节点客观下线

3.进行哨兵领导选举

        认定主节点客观下线后,各个哨兵之间通信,选举出一个哨兵领导者,由它俩完成故障转移。一般最先认定主节点主观下线的哨兵,会成为领导者

4.哨兵领导者进行故障迁移

领导者哨兵节点首先会从从节点中选出一个节点作为新的主节点。选择的规则是:

  • 1.首先排除一些不健康的节点。(下线的,断线的,最近5s没有回复哨兵节点的INFO命令的,与旧的主服务器断开连接时间较长的)

  • 2.然后根据优先级,复制偏移量,runid最小,来选出一个从节点作为主节点。

向这个从节点发送slaveof no one命令,让其成为主节点,通过slaveof 命令让其他从节点成为它的从节点,将已下线的主节点更新为新的主节点的从节点,将其他从节点的复制目标改完新的主节点,将旧的主服务器改为从服务器。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值