Redis学习

本文最后更新于:2024年8月24日 下午

之前写的项目里用过redis,但是没有专门学习过,现在系统学习一下。

Redis

redis是典型的非关系型数据库。以key-value形式存储。

NoSQL也有说法“Not Only SQL”。

优点:对数据高并发读写(内存操作)单线程操作(原子性)

Redis为什么不用多线程?

Redis并没有采用多线程的方式来提高性能,而是采用了单线程+异步IO模型

  1. 单线程模型避免了多线程的上下文切换开销
  2. 多线程需要增加锁机制,增加系统的复杂性和开销,和redis的设计理念不符
  3. Redis使用事件驱动模型,在单个线程中通过IO多路复用技术同时监听多个IO事件,并在事件发生时进行处理

场景设计:热点事件,某个网页点击量短时间内飙升

将数据缓存在redis中,前端访问时,直接从内存中查数据;等到请求量下降时,再将点击量等等数据同步到关系型数据库中。保持数据的最终一致性即可。

Redis事务

事务相当于执行批量的redis操作命令,事务的操作不是原子性的,当中间的操作出错时,不会停止执行命令,也不会回滚到出错前的状态。

Redis持久化机制

Redis不定时的将数据持久到硬盘中,Redis启动时,会提前将硬盘中的数据加载到内存。

RDB方式

快照方式,将内存数据以快照方式写入到二进制文件中(dump.rdb)。触发RDB持久化过程分为手动触发和自动触发。

触发机制:

手动触发:

  1. save命令:会阻塞当前Redis服务器,无法接收其他请求,如果内存中数据较多,会造成长时间的阻塞,不建议在生产环境中使用
  2. bgsave命令:异步操作,不会阻塞主进程。redis执行fork指令开启一个子进程,由子进程实现RDB持久化。

bgsave命令就一定不会阻塞主进程吗?

不一定,bgsave命令中,fork子进程这个操作是同步的,如果fork一个子进程花费时间太久(一般很快),basave命令仍然有阻塞其他客户的请求的可能。

自动触发:

使用save相关配置:save m n,表示m秒内数据集存在n次修改时会自动触发bgsave命令。

  • 优点:压缩紧凑的二进制文件,使用于备份、全量复制等场景。开发中可以按照每6小时执行一次bgsave备份。
  • 缺点:RDB无法做到实时持久化,每次bgsave时都需要fork子进程,消耗时间

AOF方式

AOF(Append-only file)

与RDB存储某个时刻的快照不同,AOF持久化方式会记录客户端对服务器的每一次写操作命令,并将这些写操作以Redis协议追加保存到以后缀为aof文件末尾,在Redis服务器重启时,会加载并运行aof文件的命令,以达到恢复数据的目的。

Redis默认不开启AOF持久化方式,我们可以在配置文件中开启并进行更加详细的配置,如下面的redis.conf文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 开启aof机制
appendonly yes

# aof文件名
appendfilename "appendonly.aof"

# 写入策略,always表示每个写操作都保存到aof文件中,也可以是everysec或no
appendfsync always

# 默认不重写aof文件
no-appendfsync-on-rewrite no

# 保存目录
dir ~/redis/

三种写入策略

  1. always:保存每一个写操作,很安全也很慢,因为写文件需要进行IO操作
  2. everysec:默认写入策略,每秒写入一次AOF文件,所以最多刚要写入就宕机,最多丢失1s数据
  3. no:交给OS来处理,最快,最不安全。

AOF文件重写

AOF将客户端的每一个写操作都追加到aof文件末尾,比如对一个key多次执行incr命令,这时候,aof保存每一次命令到aof文件中,aof文件会变得非常大。

1
2
3
4
5
6
7
8
incr num 1
incr num 2
incr num 3
incr num 4
incr num 5
incr num 6
...
incr num 100000

aof文件太大,加载aof文件恢复数据时,就会非常慢,为了解决这个问题,Redis支持aof文件重写,通过重写aof,可以生成一个恢复当前数据的最少命令集,比如上面的例子中那么多条命令,可以重写为:

1
set num 100000

aof文件是一个二进制文件,并不是像上面的例子一样,直接保存每个命令,而使用Redis自己的格式,上面只是方便演示。

AOF重写方式也是异步操作,即如果要写入aof文件,则Redis主进程会forks一个子进程来处理

重写AOF文件的好处

  • 压缩aof文件,减少磁盘占用量。
  • 将aof的命令压缩为最小命令集,加快了数据恢复的速度。

混合持久化

混合持久化是Redis 4.0之后新增的方式,结合了RDB和AOF的优点。

  • 在写入的时候,先把当前数据以RDB形式写入文件的开头,再将后续的操作命令以AOF的格式存入文件。这样既能保证Redis重启时的速度,又能降低数据丢失的风险。
  • 混合持久化的缺点是,在Redis重启时需要同时处理两个文件(RDB文件和AOF文件),可能会比单一持久化机制的恢复速度慢。

混合模式兼并了RDB重启后的快速恢复能力和AOF丢失数据风险低的能力,具体操作流程如下:

  1. 子进程会通过BGSAVE 写入AOF中
  2. 触发BGREWRITEAOF后,会将AOF写入到文件
  3. 将含有RDB和AOF的数据覆盖旧的AOF文件(这时AOF文件一半为RDB,一半为AOF)

AOF重写和RDB持久化的冲突

在Redis中,AOF重写和RDB持久化可能会同时发生,这会导致一些冲突和问题。例如:

  • AOF重写和RDB持久化都需要fork子进程,如果两个子进程同时存在,会增加内存的消耗和系统的负载。
  • AOF重写和RDB持久化都需要写入磁盘,如果两个文件同时写入,会增加磁盘的压力和IO的开销。
  • AOF重写和RDB持久化都需要在完成后通知主进程,如果两个信号同时到达,可能会造成信号丢失或者处理错误。

为了解决这些冲突和问题,Redis采用了以下策略:

  • 如果AOF重写和RDB持久化同时被触发,那么只有一个子进程会被创建,优先执行RDB持久化,然后再执行AOF重写。这样可以避免同时存在两个子进程的情况。
  • 如果AOF重写正在进行,而此时又收到了RDB持久化的请求,那么RDB持久化会被延迟到AOF重写完成后再执行。这样可以避免同时写入两个文件的情况。
  • 如果AOF重写和RDB持久化都完成了,那么主进程会先处理RDB持久化的信号,然后再处理AOF重写的信号。这样可以避免信号丢失或者处理错误的情况。

总之,Redis通过优先级、延迟和顺序等方式来协调AOF重写和RDB持久化的冲突和问题,保证了数据的完整性和一致性,下图为简要说明。

场景 策略
AOF重写与RDB持久化同时被触发 优先RDB
AOF重写正在进行 优先AOF
AOF重写和RDB持久化都完成 优先RDB

三种模式的选择建议

具体的选择建议如下:

  • 如果对数据完整性要求不高,可以只使用RDB,或者将AOF的同步频率设置为每秒一次
  • 如果想让数据尽可能不丢失,可以只使用AOF,并将AOF的同步频率设置为每次写入操作都同步
  • 如果对数据完整性和性能都有要求,可以同时使用AOF和RDB,并将AOF的同步频率设置为每秒一次。这样既可以保证数据的安全性,又可以利用RDB进行快速的数据恢复
  • 如果既想节省磁盘空间,又想提高数据恢复速度,可以只使用RDB,并适当调整RDB的快照频率

Redis内存淘汰机制


Redis学习
https://3xsh0re.github.io/2024/06/05/Redis学习/
作者
3xsh0re
发布于
2024年6月5日
许可协议