跳转至

运作

Redis 的内存模型

image-20241231205246380

事实上,内存中有一块位置存储了 String 的字符内容,如上图中 dict 中其实存储的是指向 String 的指针,每个这个 String 指针会对应一个 timpstamp

redis 线程

核心执行流程是单线程的

为什么使用单线程

  • 上下文切换的时间成本
  • 同步机制(加锁等)会有一定的开销
  • 节省内存

redis 的性能瓶颈在于 IO 而不是 CPU

为什么 redis 快

redis 可以达到 8 ~ 10w/s

  • 内存数据库,内存访问快
  • 数据结构设计得很高效
  • IO 多路复用,网络IO操作中可以提高吞吐量

哪里用到了多线程

工作流程如下:

在 IO 多路复用模型中,还是主线程去监听(遍历)所有的 fd 事件,随后再将具体的读取和写回操作交给多个线程执行

  • 当客户端发送请求时,I/O 线程从 Socket 读取数据并将其存储在 queryBuf 中。
    • I/O 线程从客户端的 Socket 中读取数据。
    • 将读取的数据存储到客户端的输入缓冲区(queryBuf)中
  • 主线程从 queryBuf 中获取请求并执行相应的命令。
  • 执行结果存储在 reply 中,然后由 I/O 线程将响应发送回客户端。
    • I/O 线程从客户端的输出缓冲区(reply)中获取数据。
    • 将数据通过 Socket 发送给客户端。

Redis 持久化

为什么需要持久化

持久化就是将内存数据存入磁盘

  • Redis 在很多场景下作为缓存使用,但如果碰到重启情况之后缓存都不在了,这样请求会一下都打到存储上
  • Redis 本身也可以作为存储使用,这个时候对于数据保存的安全性要求较高

RDB 和 AOF 的本质区别是什么

RDB 是全量的二进制快照保存,而 AOF 则是追加日志文件进行记录

  • 文件类型:RDB 生成的都是二进制文件(快照),AOF 生成的是文本文件(追加日志)
  • 安全性:缓存宕机时,RDB 会损失较多的数据,AOF 则会根据配置的刷盘策略(比如1s刷一次)决定
  • 文件恢复速度:由于 RDB 是二进制文件,所以其恢复速率比 AOF 更快
  • 操作开销:如果以每一次的操作作为单位,RDB 每次的保存都是全量保存,而 AOF 刷盘是一次追加操作

RDB 和 AOF 选谁

  • 如果能接受分钟级别的丢失,选 RDB(这也是官方的默认选择)
  • 如果选择 AOF ,则开启每秒刷盘一次的 AOF

二者同时开启时,使用哪种载入策略

image-20250101154405214

同时开启时,无论 AOF 日志是否丢失,都只会使用 AOF,因为既然选择一定要开启 AOF ,说明对于数据的可靠性要求较高,此时如果发生异常需要即时暴露出来进行处理

RDB 详解

image-20250102185907031

RDB 开启

定时持久化

前一个参数表示每过多久检查一次;后一个参数表示这段时间内的更新数达到多少才能快照(这些命令不是需要手动执行的)

save 900 1
save 300 10
save 60 10000

手动持久化

# 阻塞式
save

# 后台持久化
bgsave

RDB 的写入方式

后台持久化时:

  • Redis 首先调用 fork 开启一个子进程
  • 子进程开始将所有数据写入到 临时 RDB 文件中
  • 当子进程写入完成后,替换掉原有的 RDB 文件

这里的 fork 使用 copy on write ,并且注意到随后进行数据更新操作的必定是父进程(子进程不会接受命令)

  • 在写入的过程中新来的数据是父进程新开了的内存接收的
  • 复制的是快照一瞬间的数据

面试问题

RDB 的本质是什么

RDB 的本质是二进制形式的快照

如何开启 RDB

  • 定时,使用后台持久化
  • 主动命令 save / bgsave(实际生产中少)

RDB 对主流程有什么影响

  • 阻塞式持久化时,由主进程进行快照保存,会阻塞主进程
  • 后台持久化时,由 fork 出来的子进程来执行快照
    • 特别地,当数据量比较大时,会导致 fork 子进程这个操作比较耗时,从而阻塞主进程
    • 和阻塞相比,如果子进程执行拷贝时又有新的数据改写,会由主进程执行

AOF 详解

image-20250102185647406

如何开启 AOF

找到 redis 配置文件 redis.conf

默认的配置为 appendonly no,改为 yes 即可

刷盘策略

  • always 每次请求都刷入 AOF
  • everysec 每秒刷一次盘(崩溃时会丢失 1s 的数据)
  • no 不主动刷盘,让操作系统自己刷(linux 一般是 30s 刷一次盘,这里是只从内核缓存中写入磁盘)

AOF 落盘

先写入缓冲,再根据策略刷盘

image-20250102175213753

AOF 面试

AOF 重写是解决什么问题的

重写用于解决 AOF 不断膨胀的问题,随着命令越来越多,AOF 文件越来越大,但是记录的指令中存在指令的覆盖,此时前面的命令就没有记录的必要了。

简述 AOF 重写的流程

  • 主进程 fork() 出来一个子进程,然后这个子进程读取 RedisDB 中的数据,以字符串的形式写入到新的 AOF 文件中
  • 当新的 AOF 文件重建完毕,主进程会把重写缓冲区的内容追加到新的 AOF 文件中

    注意,重写缓冲区专门为重写服务,普通缓冲区使用相应的刷盘策略进行刷盘。在重写的过程中,主进程会同时向普通缓冲区的重写缓冲区追加数据

AOF 对主流程有什么影响

  • always 需要阻塞主线程,每次主线程都需要等待从缓冲区写入磁盘
  • everysec 一般不会阻塞主线程,主线程会使用 fork 创建子线程刷盘
  • no 依赖操作系统将缓冲区的内容写入磁盘