Redis常见面试题

文章目录

项目中是如何使用缓存的

参考:redis常用数据结构和应用场景

redis效率为什么这么高

Redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 Redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 Socket,根据 Socket 上的事件来选择对应的事件处理器进行处理。

多个 Socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会监听多个 socket,会将 socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,把该事件交给对应的事件处理器进行处理。

除了利用IO多路复用模型外,redis还有以下几个方面可以提高效率:

  • 纯内存操作:Redis 为了达到最快的读写速度,将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以 Redis 具有快速和数据持久化的特征。
  • 单线程 ,避免了多线程的频繁上下文切换问题
    Redis 利用队列技术,将并发访问变为串行访问,消除了传统数据库串行控制的开销。
    实际上,Redis 4.0 开始,也开始有了一些异步线程,用于处理一些耗时操作。例如说,异步线程,实现惰性删除(解决大 KEY 删除,阻塞主线程)和异步 AOF (解决磁盘 IO 紧张时,fsync 执行一次很慢)等等。
  • 丰富的数据结构
    例如哈希表和跳表,这是它实现高性能的一个重要原因

Redis 6.x之后有哪些新特性

多线程

Redis 一直被大家熟知的就是它的单线程架构,虽然有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF 重写),但是,从网络 IO 处理到实际的读写命令处理,都是由单个线程完成的。

随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 IO 的处理上,也就是说,

单个主线程处理网络请求的速度跟不上底层网络硬件的速度。

为了解决这个问题,Redis采用多个 IO 线程来处理网络请求,提高网络请求处理的并行度。

但Redis 的多 IO 线程只是用来处理网络请求的,对于读写命令,Redis 仍然使用单线

程来处理。这是因为,Redis 处理请求时,网络处理经常是瓶颈,通过多个 IO 线程并行处

理网络操作,可以提升实例的整体处理性能。而继续使用单线程执行命令操作,就不用为

了保证 Lua 脚本、事务的原子性,额外开发多线程互斥机制了。这样一来,Redis 线程模

型实现就简单了。

在 Redis 6.0 中,主线程和 IO 线程具体是怎么协作完成请求处理的?

阶段一:服务端和客户端建立 Socket 连接,并分配处理线程

首先,主线程负责接收建立连接请求。当有客户端请求和实例建立 Socket 连接时,主线程

会创建和客户端的连接,并把 Socket 放入全局等待队列中。紧接着,主线程通过轮询方法

把 Socket 连接分配给 IO 线程。

阶段二:IO 线程读取并解析请求

主线程一旦把 Socket 分配给 IO 线程,就会进入阻塞状态,等待 IO 线程完成客户端请求

读取和解析。因为有多个 IO 线程在并行处理,所以,这个过程很快就可以完成。

阶段三:主线程执行请求操作

等到 IO 线程解析完请求,主线程还是会以单线程的方式执行这些命令操作。下面这张图显

示了刚才介绍的这三个阶段

阶段四:IO 线程回写 Socket 和主线程清空全局队列

当主线程执行完请求操作后,会把需要返回的结果写入缓冲区,然后,主线程会阻塞等待

IO 线程把这些结果回写到 Socket 中,并返回给客户端。

和 IO 线程读取和解析请求一样,IO 线程回写 Socket 时,也是有多个线程在并发执行,

所以回写 Socket 的速度也很快。等到 IO 线程回写 Socket 完毕,主线程会清空全局队

列,等待客户端的后续请求。

其他新增特性总结如下:

缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,造成数据库的压力倍增的情况

例:发起为id值为 -1 的数据或 id 为特别大不存在的数据

解决方案:

  • 接口层增加校验,比如用户鉴权校验,参数做校验 比如:id 做基础校验,id <=0的直接拦截
  • 对于像ID为负数的非法请求直接过滤掉,采用布隆过滤器(Bloom Filter)
  • 针对在数据库中找不到记录的,我们仍然将该空数据存入缓存中,当然一般会设置一个较短的过期时间

缓存雪崩

缓存服务器宕机或者大量缓存集中某个时间段失效,导致请求全部去到数据库,造成数据库压力倍增的情况,这个是针对多个key而言

造成缓存雪崩的原因主要有两个

  1. 缓存中有大量数据同时过期,导致大量请求无法得到处理。

针对这个原因,可以有两个解决方案:

  • 避免给大量的数据设置相同的过期时间,给这些数据的过期时间增加一个较小的随机数(例如,随机增加 1~3 分钟)
  • 通过服务降级来解决:当业务应用访问的是非核心数据(例如电商商品属性)时,暂时停止从缓存中查询这些数据,而是直接返回预定义信息、空值或是错误信息;
    当业务应用访问的是核心数据(例如电商商品库存)时,仍然允许查询缓存,如果缓存
    缺失,也可以继续通过数据库读取。这样一来,就只有部分请求到数据库中,数据库压力就没那么大了。
  1. 缓存雪崩的另外一个原因是,Redis缓存实例发生故障宕机了,无法处理请求,这就会导致大量请求一下子积压到数据库层,从而发生缓存雪崩。

此时有下面解决方法:

  • 业务系统中实现服务熔断或请求限流机制:所谓的服务熔断,是指在发生缓存雪崩时,为了防止引发连锁的数据库雪崩,甚至是整个系统的崩溃,我们暂停业务应用对缓存系统的接口访问。再具体点说,就是业务应用调用缓存接口时,缓存客户端并不把请求发给 Redis 缓存实例,而是直接返回,等到 Redis 缓存实例重新恢复服务后,再允许应用请求发送到缓存系统
  • 服务熔断虽然可以保证数据库的正常运行,但是暂停了整个缓存系统的访问,对业务应用的影响范围大。为了尽可能减少这种影响,我们也可以进行请求限流。这里说的请求限流,就是指,我们在业务系统的请求入口前端控制每秒进入系统的请求数,避免过多的请求被发送到数据库。
  • 过主从节点的方式构建 Redis 缓存高可靠集群。如果 Redis 缓存的主节点故障宕机了,从节点还可以切换成为主节点,继续提供缓存服务,避免了由于缓存实例宕机而导致的缓存雪崩问题。

缓存击穿

redis过期后的一瞬间,有大量用户请求同一个缓存数据,导致这些请求都去请求数据库,造成数据库压力倍增的情,针对一个key而言

缓存击穿与缓存雪崩的区别是这里针对的是某一热门key缓存,而雪崩针对的是大量缓存集中失效

解决方案

  • 设置热点数据永远不过期。
  • 用互斥锁(mutex key)
相关推荐
cyt涛32 分钟前
MyBatis 学习总结
数据库·sql·学习·mysql·mybatis·jdbc·lombok
Rookie也要加油1 小时前
01_SQLite
数据库·sqlite
liuxin334455661 小时前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
看山还是山,看水还是。2 小时前
MySQL 管理
数据库·笔记·mysql·adb
fishmemory7sec2 小时前
Koa2项目实战2(路由管理、项目结构优化)
数据库·mongodb·koa
momo小菜pa2 小时前
【MySQL 09】表的内外连接
数据库·mysql
Jasonakeke2 小时前
【重学 MySQL】四十九、阿里 MySQL 命名规范及 MySQL8 DDL 的原子化
数据库·mysql
程序猿小D2 小时前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
小宇成长录3 小时前
Mysql:数据库和表增删查改基本语句
数据库·mysql·数据库备份
团儿.3 小时前
解锁MySQL高可用新境界:深入探索MHA架构的无限魅力与实战部署
数据库·mysql·架构·mysql之mha架构