type
Post
status
Published
date
Jul 2, 2021
slug
redis-read2-record
summary
Redis设计与实现-阅读笔记(第二部分)
tags
Redis
category
爱技术
icon
password
Property
Feb 24, 2023 10:58 PM
《Redis设计与实现》第二部分阅读笔记

数据库

1.服务器中的数据库

Redis服务器所有数据库都保存在redisServer结构的db数组中,db数组的每一项都是一个数据库
notion image

2.切换数据库

SELECT 2
notion image

3.数据库键空间

notion image
redisDb是db数组的元素,每个数据库中都有字典类型的键空间,保存所有的键值对
其中键空间的键都是字符串对象,而值则是redis的任意一种对象
notion image
在对redis数据库进行读操作时会进行一些额外维护工作, 1.判断键是否过期,过期则删除 2.更新键的LRU 3更新miss_hit和hit次数 4.修改键会对脏键计数器+1,用于后续的复制和持久化。 5如果开启数据库通知功能则会发送相应的通知给数据库

4.设置键的生存时间或过期时间

设置过期时间的命令有4个,分别是
❑EXPIRE<key><ttl>命令用于将键key的生存时间设置为ttl秒。
❑PEXPIRE<key><ttl>命令用于将键key的生存时间设置为ttl毫秒。
❑EXPIREAT<key><timestamp>命令用于将键key的过期时间设置为timestamp所指定的秒数时间戳。
❑PEXPIREAT<key><timestamp>命令用于将键key的过期时间设置为timestamp所指定的毫秒数时间戳。
P开头的EXPIRE都是毫秒相关
AT结尾都是设置过期的时间戳,其他那俩是设置几秒/毫秒过期
 

5.过期键删除策略

Redis在设置过期键时,会维护一个过期键字典,字典中记录键和过期时间
三种不同的删除策略,在三种策略中,1和3为主动删除策略,2为被动策略
1.定时删除:设置键过期的同时,创建一个Timer定时器让定时器在过期时删除键
2.惰性删除:放任键过期不管,每次从空间中获取键时,检查键是否过期,如果过期就删除改键,没有过期就返回该键
3.定期删除:每隔一段时间,程序对数据库进行一次检查,删除里面的过期键,至于删除多少过期键,检查多少数据库则由算法决定。
 
定时删除:对内存最友好,能保证过期键尽快删除,释放内存,但对CPU时间不友好,会对redis服务吞吐造成影响
惰性删除:对CPU时间最友好,程序只会在取出键时才对键进行过期检查。缺点对内存不友好,如果一个键ta长时间没有被访问,那么就约等于内存泄露
定期删除:定期删除是前两者的整合和折中,定期删除策略是每隔一段时间执行一次国期键操作,并且限制删除操作的执行时长,减少删除操作对CPU时间的影响。有效减少了因过期键带来的内存浪费

6.Redis的过期键删除策略

过期删除默认从16个库分别选20个键进行删除。如果超出运行时间就会返回,不过会记录当前执行的进度。下次执行会接着上次进度进行(current_db属性记录插件进度,为0时检查完毕,可开始新一轮的检查)。 惰性删除则是在执行命令前执行函数判断键是否过期没过期继续走。如果过期则删除键同时走键不存在的逻辑。
 

7.AOF、RDB和复制功能对过期键的处理

1、redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。 2、RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上; 3、AOF,则是换了一个角度来实现持久化,那就是将redis执行过的所有写指令记录下来,在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了
4.复制 当服务器运行在复制模式下,从服务器的过期动作由主服务器控制,主服务器删除过期键后会向所有从服务器发送DEL命令,告知删除过期键;从服务器执行读取命令时即使获取的是已经过期的键也不会处理,而是正常返回,只有主服务器通知DEL命令时才会删除
 

8.数据库通知

数据库通知分为两种 1)key-space notification:键空间通知,订阅某个键被执行的所有指令 2)key-event notification:键事件通知,订阅某个命令被什么键执行
 

9.重点回顾

❑Redis服务器的所有数据库都保存在redisServer.db数组中,而数据库的数量则由redisServer.dbnum属性保存。
❑客户端通过修改目标数据库指针,让它指向redisServer.db数组中的不同元素来切换不同的数据库。
❑数据库主要由dict和expires两个字典构成,其中dict字典负责保存键值对,而expires字典则负责保存键的过期时间。
❑因为数据库由字典构成,所以对数据库的操作都是建立在字典操作之上的。
❑数据库的键总是一个字符串对象,而值则可以是任意一种Redis对象类型,包括字符串对象、哈希表对象、集合对象、列表对象和有序集合对象,分别对应字符串键、哈希表键、集合键、列表键和有序集合键。
❑expires字典的键指向数据库中的某个键,而值则记录了数据库键的过期时间,过期时间是一个以毫秒为单位的UNIX时间戳。
❑Redis使用惰性删除和定期删除两种策略来删除过期的键:惰性删除策略只在碰到过期键时才进行删除操作,定期删除策略则每隔一段时间主动查找并删除过期键。
❑执行SAVE命令或者BGSAVE命令所产生的新RDB文件不会包含已经过期的键。
❑执行BGREWRITEAOF命令所产生的重写AOF文件不会包含已经过期的键。
❑当一个过期键被删除之后,服务器会追加一条DEL命令到现有AOF文件的末尾,显式地删除过期键。
❑当主服务器删除一个过期键之后,它会向所有从服务器发送一条DEL命令,显式地删除过期键。
❑从服务器即使发现过期键也不会自作主张地删除它,而是等待主节点发来DEL命令,这种统一、中心化的过期键删除策略可以保证主从服务器数据的一致性。
❑当Redis命令对数据库进行修改之后,服务器会根据配置向客户端发送数据库通知。
 

RDB持久化

1. RDB文件的创建与载入

Redis有两个命令可以生成RDB,一个是SAVE,一个是BGSAVE
SAVE 阻塞Redis服务线程,直到RDB文件创建完毕,阻塞其他服务器不处理任何命令请求
BGSAVE fork子进程,由子进程创建RDB文件,服务器进程继续处理命令请求
notion image
载入:Redis并有没有载入RDB文件命令,只要Redis服务在启动的时候监测到RDB的文件存在就会自动加载,载入其他进程阻塞,直到加载完成
另外AOF的更新频率比RDB文件的更新频率高,如果服务器开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原服务器状态,只有AOF关闭时才会采用RDB
 
当SAVE命令在执行的时候所有的客户端请求都会拒绝
BGSAVE的命令在执行其他,客户端发送SAVE、BGSAVE命令会被拒绝,而客户端发送BGREWRITEAOF命令则是被推迟到BGSAVE命令结束之后,反之亦是如此,当BGREWRITEAOF命令在运行时客户端发送BGSAVE命令,则是要等待BGREWRITEAOF命令结束才能执行
 

2.自动间隔性保存

Redis允许用户设置多个BGSAVE的保存条件,只要一个条件满足就会执行BGSAVE
notion image
❑服务器在900秒之内,对数据库进行了至少1次修改。
❑服务器在300秒之内,对数据库进行了至少10次修改。
❑服务器在60秒之内,对数据库进行了至少10000次修改。
redisServer中有saveparams数组、dirty和lastsave
saveparams保存用户自定义的保存条件
dirty 自上次保存后,进行了多少次修改
lastsave上次保存时间
redis可以根据dirty和lastsave 进行与saveparams中的条件进行比对,达到条件执行bgsave命令
 

3. RDB文件结构

完整的RDB文件包含各个部分
notion image
1.redis: 开头部分是保存的是字符”REDIS“的二进制📢不是C字符串,仅仅是5个字符的二进制没有\0结尾
2.db_version: 记录了RDB文件的版本号,比如”0006“ 就代表RDB文件的第六版
3.database: 包含着零个或多个数据库,如果数据库都是空的,这部分也为空,长度0字节
4.EOF 常量,长度为1字节,表示RDB文件正文内容结束
5.check_sum:一个8字节长的无符号证书,保存着一个校验值,校验值由前面各个部分通过计算得出,以此来检查文件是否损坏
notion image
每个database中都可以保存为SELECTDB、db_number、key_value_pairs
notion image
SELECTDB常量的长度为1字节,当程序读取到这个值的时候,接下来读入的是个数据库号码
db_number 保存着数据库号码,这个部分长度可以是1字节、2字节或者5字节,当程序读取db_number后,服务器会调用SELECT命令
key_value_pairs 保存了数据库中所有的键值对
而key_value_pairs部分则是由type、key、value组成
notion image
 
TYPE记录了value的类型,长度为1字节,值可以是以下常量的其中一个:❑REDIS_RDB_TYPE_STRING
❑REDIS_RDB_TYPE_LIST
❑REDIS_RDB_TYPE_SET
❑REDIS_RDB_TYPE_ZSET
❑REDIS_RDB_TYPE_HASH
❑REDIS_RDB_TYPE_LIST_ZIPLIST
❑REDIS_RDB_TYPE_SET_INTSET
❑REDIS_RDB_TYPE_ZSET_ZIPLIST
❑REDIS_RDB_TYPE_HASH_ZIPLIST
notion image
带有过期时间的
EXPIRETIME_MS 常量,告知程序接下来读取毫秒单位的过期时间
ms 一个8字节长的带符号整数,记录着一个时间戳
 

4.分析RDB文件

演示一个空数据库的RDB文件
notion image
notion image
rdb由一下4部分组成
❑五个字节的"REDIS"字符串。
❑四个字节的版本号(db_version)
❑一个字节的EOF常量。
❑八个字节的校验和(check_sum)
最开头的是“REDIS”字符串,之后的0006是版本号,再之后的一个字节377代表EOF常量,最后的334 263 C 360 Z 334 362 V八个字节则代表RDB文件的校验和。
 
包含字符串键值的RDB文件
notion image
notion image
 

5.重点回顾

❑RDB文件用于保存和还原Redis服务器所有数据库中的所有键值对数据。
❑SAVE命令由服务器进程直接执行保存操作,所以该命令会阻塞服务器。
❑BGSAVE令由子进程执行保存操作,所以该命令不会阻塞服务器。
❑服务器状态中会保存所有用save选项设置的保存条件,当任意一个保存条件被满足时,服务器会自动执行BGSAVE命令。
❑RDB文件是一个经过压缩的二进制文件,由多个部分组成。
❑对于不同类型的键值对,RDB文件会使用不同的方式来保存它们。
 

AOF持久化

1.AOF持久化的实现

AOF持久化功能分为命令追加、文件写入、文件同步三个步骤
1)命令追加:
当AOF持久化功能打开状态时,服务器执行完一个写命令之后,会以协议格式将被执行的命令追加到aof_buf缓冲区的末尾
2)AOF文件的写入与同步
Redis服务器的进程是一个事件循环(loop),在这个循环中文件事件负责接受客户端的请求命令,以及向客户端发送命令回复,而时间事件则是负责执行像ServerCron函数
在处理文件事件时有可能执行写命令,使得一些内容追加到aof_buf缓冲区内,再服务器每次结束循环之前都会考虑是否将缓冲区的数据写入AOF文件中
notion image
flushAppendOnlyFile行为由服务器配置的appendfsync选项值来决定
notion image
 
由于现在的操作系统为了提升性能,当使用了write函数后不会立刻写入磁盘,而是将写入的数据暂时保存在内核缓冲区内,等缓冲区被填满、或超过了指定时限才会真正的将缓存区的数据刷入磁盘
这种做法在意外宕机的情况下有部分数据会丢失,所有系统提供了fsync和fdatasync函数,可以强制将缓冲区的数据刷入磁盘中确保数据安全。
redis 的aof_buf是redis的内存缓冲区,当redis使用write写入命令后不会立刻写入磁盘,而是被存放在内核缓冲区。而sync命令则是将内核缓冲区的数据全部刷入磁盘。也称为同步
 
appendfsync值为
always时最安全,也最慢
everysec,最多丢失1秒数据
no 速度最快,每个事件循环都将aof_buf缓冲区内容写入内核缓冲区,至于什么时候将缓冲区的内容写入的磁盘,则看系统心情(要看情况)。
 

2.AOF文件的载入与数据还原

AOF文件中包含了重建数据库状态的所有写命令,服务器只需要读入并重新执行一遍AOF中的所有写命令就可以恢复
恢复步骤
1)服务器创建一个不带网络连接的伪客户端
2)从AOF中分析并读取一条写命令
3)使用伪客户端执行被读出的写命令
4)重复步骤2和3直至AOF文件所有命令都处理完成
notion image
 

3.AOF重写

aof持久化是通过被执行的写命令来记录数据库状态的,随服务器运行时间的流逝,aof文件会越来越大,而aof文件过大,则恢复时间则越长
为了解决AOF文件体积膨胀的问题,Redis提供了AOF文件重写功能,服务器可以创建一个新的AOF文件代替现有的AOF文件,新旧的数据库状态相同,但新的AOF不会浪费任何空间和冗余的命令,所以新的AOF小的多
比如
notion image
若以上命令重建后只需要保存一条命令,但是元素数量超过64(Redis常量)个就不再是单单一条命令了
RPUSH list “A” “B” “C” “D” “E” “F” “G”
 
AOF后台重写
AOF是通过fork子进程来完成重写,此时父进程仍能继续处理客户端请求,同时也可以避免WRITE等命令竞争
缺点就是重写期间的数据子进程与父进程会存在差异,redis则是通过引入了一个额外的AOF缓冲区解决,通过双写缓冲区来避免数据差异
notion image
 

4.重点回顾

❑AOF文件通过保存所有修改数据库的写命令请求来记录服务器的数据库状态。
❑AOF文件中的所有命令都以Redis命令请求协议的格式保存。
❑命令请求会先保存到AOF缓冲区里面,之后再定期写入并同步到AOF文件。❑appendfsync选项的不同值对AOF持久化功能的安全性以及Redis服务器的性能有很大的影响。
❑服务器只要载入并重新执行保存在AOF文件中的命令,就可以还原数据库本来的状态。❑AOF重写可以产生一个新的AOF文件,这个新的AOF文件和原有的AOF文件所保存的数据库状态一样,但体积更小。
❑AOF重写是一个有歧义的名字,该功能是通过读取数据库中的键值对来实现的,程序无须对现有AOF文件进行任何读入、分析或者写入操作。
❑在执行BGREWRITEAOF命令时,Redis服务器会维护一个AOF重写缓冲区,该缓冲区会在子进程创建新AOF文件期间,记录服务器执行的所有写命令。当子进程完成创建新AOF文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新AOF文件的末尾,使得新旧两个AOF文件所保存的数据库状态一致。最后,服务器用新的AOF文件替换旧的AOF文件,以此来完成AOF文件重写操作。
 
💡
有关Redis上的问题,欢迎您在底部评论区留言,一起交流~
 
 
Java高并发核心编程 卷2-阅读笔记(一)Redis设计与实现-阅读笔记(第一部分)
Loading...