Redis 面试题整理

redis过期数据删除的机制

过期键的删除策略

  • 立即删除:(对CPU不友好)
  • 惰性删除:取值的时候,先检查是否过期,过期再删除(浪费内存)
  • 定时删除:每隔一段时间对,expires字典进行检查,删除里面的过期键

redis使用的策略

  • 惰性删除+定期删除

redis的数据结构有哪些

  • String(字符串)
  • List(列表)->双向链表
  • Hash(字典)->一般有两个hashtable ,通常就一个hashtable有值;在字典缩容扩容时,需要分配新的hashtable ,然后渐进式搬迁
    • 大字典的扩容比较费时间,徐娅重新申请新的数组,把旧字典的所有链表的元素连接到新的数组下面,O(n),对于单线程的redis,难以承受,所以采用渐进式rehash小步搬迁
    • 当元素的个数等于第一维数组的长度,就会开始扩容,扩容到原数组的两倍,如果redis正在bgsave,为了减少内存也过多分离,redis尽量不去扩容,如果达到长度的五倍,强制扩容;元素少于10%缩容,不考虑是否bgsave
  • Set(集合)
  • Sorted Set(有序集合)

为什么要用跳跃表

  • 要实现随机的插入和删除,不宜使用数组实现
  • **性能考虑:**在高并发的情况,树形结构要考虑rebalance的操作,而跳跃表只涉及局部
  • **实现考虑:**在复杂度和红黑树相同的情况下,跳跃表实现更简单直观

分布式锁

场景

  1. 避免不同的节点重复相同的工作
  2. 避免破坏数据的正确性

锁超时

额外设置一个超时时间,来保证服务的可用性

布隆过滤器

布隆过滤器说值存在->这个值可能不存在

布隆过滤器说不存在->一定不存在

场景

  • 大数据判断是否存在
  • 解决缓存穿透
  • 爬虫/邮箱等系统的过滤
  • 推荐去重

持久化的过程

  1. 客户端向数据库发送写命令(数据在客户端的内存)
  2. 数据库接受客户端的写请求(数据在服务器的内存)
  3. 数据库调用系统API将数据写入硬盘(数据在内核缓冲区
  4. 操作系统将写缓冲区传输到磁盘控制器(数据在磁盘缓冲区)Linux默认30s后进入下一步
  5. 操作系统的磁盘控制器将数据写入实际的物理媒介中(数据在磁盘中)

30s不是redis可以承受的,如果发生故障,30s内写入的数据都可能丢失,解决方案:fsync:该命令强制内核将缓冲区写入磁盘,每次调用都会阻塞等待直到IO完成,一般1s左右执行一次。

Redis中的两种持久化方式

  • RDB快照

持久化的同时,内存数据结构还在变化,咋办?

使用系统多进程COW(copy on write)机制|fork函数

简单的说:在持久化的时候调用glibc的函数fork产生一个子进程(复制一个进程,主进程子进程共享内存里面的代码块和数据段)

快照持久化交给子进程处理,父进程继续处理客户端请求;此时子进程相应的页面是没有变化的,进程产生一瞬间的数据

  • AOF(Append Only File - 仅追加文件)

每次执行修改内存的写操作时,都会记录该操作

当Redis收到客户端修改指令时,先进行参数校验,逻辑处理如果没问题就立即将该指令文本存储到AOF日志中,(先执行指令再将日志存盘->与Mysql等不同)

AOF重写 bgrewriteaof

原理:开辟一个子线程对内存进行遍历转换成一系列的Redis操作指令,序列化到一个新的AOF日志文件。序列化完成后再将操作期间发生的增量AOF日志追加到这个新的 AOF日志文件

fsync 强制从内核缓存刷到磁盘

AOF日志进行写时,实质上时将内容写到内核为文件描述符分配的内存缓存中,然后内核会异步将脏数据刷回磁盘

Redis 主从复制

作用

  • 数据冗余
  • 故障恢复
  • 负载均衡
  • 高可用基石

img

三个阶段:准备阶段-数据同步阶段-命令传播阶段

SYNC(非常耗时)

  1. 主服务器 执行BGSAVE 生成RDB 消耗主服务器大量的CPU、内存、磁盘IO资源
  2. 主服务器将生成的RDB发送给从服务器 消耗大量的网络资源
  3. 从服务器载入主服务器法来的RDB文件,载入期间,从服务器因为阻塞而无法处理命令请求

断线重连再次调用SYNC不合理,于是引入PSYNC

  1. 全量复制
  2. 部分复制(主从节点分别维护一个复制偏移量)

Redis Sentinel 哨兵

哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的Redis节点,不存储数据

数据节点:主节点和从节点都是数据节点

哨兵的功能:

  • 监控:不断检测主节点、从节点是否运作正常
  • 自动故障转移:主节点不能工作算,自动故障专业,把其中的一个从节点升级为新的主节点
  • 配置提供者:客户端在初始化时,通过链接哨兵来获得当前Redis服务的主节点地址
  • 通知:哨兵可以将故障转移的结果发给客户端

选择新的主服务器的方法

  1. 在失效主服务器属下的从服务器当中, 那些被标记为主观下线、已断线、或者最后一次回复 PING 命令的时间大于五秒钟的从服务器都会被 淘汰
  2. 在失效主服务器属下的从服务器当中, 那些与失效主服务器连接断开的时长超过 down-after 选项指定的时长十倍的从服务器都会被 淘汰
  3. 经历了以上两轮淘汰之后 剩下来的从服务器中, 我们选出 复制偏移量(replication offset)最大 的那个 从服务器 作为新的主服务器;如果复制偏移量不可用,或者从服务器的复制偏移量相同,那么 带有最小运行 ID 的那个从服务器成为新的主服务器。

Redis集群

作用:

  1. 数据分区:突破单机内存大小限制,存储容量大大增加,提高响应能力
  2. 高可用:自动故障转移(类似于哨兵)

缓存雪崩

是什么?

同一时间大量缓存数据失效,导致原本访问Redis的请求全部去到数据库,造成数据库短期内CPU和内存压力变大,严重导致宕机

为什么

缓存数据设置的过期时间是相同的,并且Redis恰好将这部分数据全部删除

怎么解决

给缓存数据设置过期时间时加上一个随机值

ps:

另外对于 “Redis 挂掉了,请求全部走数据库” 这样的情况,我们还可以有如下的思路:

  • 事发前:实现 Redis 的高可用(主从架构 + Sentinel 或者 Redis Cluster),尽量避免 Redis 挂掉这种情况发生。
  • 事发中:万一 Redis 真的挂了,我们可以设置本地缓存(ehcache) + 限流(hystrix),尽量避免我们的数据库被干掉(起码能保证我们的服务还是能正常工作的)
  • 事发后:Redis 持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据。

缓存穿透

是什么?

查询一个不存在数据库中的数据,缓存一定不存在,绕过Redis请求数据库

为什么?

请求的数据大量不命中缓存,导致走数据库

怎么解决

  1. 使用布隆过滤器提前拦截
  2. 把不存在的空对象也放到缓存中,

Redis早期版本为什么选择单线程?

  1. 单线程能带来更好的可维护性
  2. 单线程也能并发处理客户端请求(IO多路复用)
  3. redis服务中运行的绝大多数操作的性能瓶颈都不是CPU

Redis为什么这么快?

  1. 纯内存操作(不需要进行磁盘IO)
  2. 单线程,无锁竞争
  3. 多路I/O复用模型,非阻塞IO
  4. 高效的数据结构,加上底层做了大量优化

简述一下Redis常用的数据结构及实现[外链图片转存中…(img-416f5Fsl-1647871142317)]

Redis的SDS和C中的字符串相比有什么优势

  1. C获取字符串长度要O(n)
  2. C不能很好的杜绝缓冲区溢出/内存泄漏的问题
  3. C只能保存文本数据

SDS如何解决

  1. 多增加len表示当前字符串的长度0(1)
  2. 自动扩展空间
  3. 有效降低内存分配次数
  4. 二进制安全

字典如何实现?Rehash了解吗?

数组+链表 ;字典内部两个hashtable,通常情况只有一个hashtable有值 渐进式rehash

压缩列表

为什么节省内存,zset和hash容器对象会在元素个数较少的时候,采用压缩列表进行存储。压缩列表时一块连续的内存空间,元素之间紧紧挨着,没有任何冗余间隙。

参考:https://www.wmyskxz.com/2020/03/25/ma-ma-zai-ye-bu-dan-xin-wo-mian-shi-bei-redis-wen-de-lian-du-lu-liao/

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值