Redis设计与实现--02--单机数据库-01-数据库

总体
  • 该部分包括数据库的结构、过期键的删除策略、数据库通知
1. 服务器中的数据库
  • redis服务器的数据库结构都是redis.h/redisDb结构
struct redisServer{
	...
	//一个数组,保存这服务器中的所有数据库
	redisDb *db

	//服务器的数据库数量
	int dbnum;
	...
}
  • 数据库的个数由dbnum属性决定,该值是由服务器配置的database选项决定,该值默认为16。
  • 结构图
    在这里插入图片描述
2. 切换数据库
  • Redis默认的数据库为0号数据库,客户端可以通过select语句来切换数据库
  • 客户端状态redisClient结构如下,其中db属性记录了客户端当前的目标数据库
typedef struct redisClient{
	...
	//记录客户端当前正在使用的数据库
	redisDb *db;
	...
}
  • redisClient->select 2
    在这里插入图片描述
3. 数据库键空间
  • 服务其中的每个数据库都是由redisDb数据结构表示,而其中,dict字典保存了数据库中所有的键值对,称dict字典为键空间。
typedef struct redisDb{
	...
	//数据库键空间,保存着数据库中的所有键值对
	dict *dict;

	//过期字典
	dict *expires;
	...
}
  • 键空间的键值
    • 键空间中的键就是数据库的键,每个键都是一个字符串对象
    • 键空间中的值就是数据库的值,对应着不同的redis对象。
    • 图中展示了 list(alphabet)、hash(book)、string(message)
      在这里插入图片描述
  • 键空间的增加、删除、更新、取值
    • 增加-》SET date “2013.12.1”在这里插入图片描述
    • 删除-》DEL book在这里插入图片描述
    • 更新-》SET message “blah blah”在这里插入图片描述
    • 取值-》GET message在这里插入图片描述
4. 设置键的过期时间
  • redis中,过期时间是一个UNIX的时间戳,过期时间来临,服务器会自动删除这个键。
  • SETEX 命令可以为字符串键设置过期时间,但是不可以对其他redis对象设置过期时间。但是底层原理和EXPIRE原理一致。
  • 设置过期时间的通用命令,虽然命令存在四种,但是最后1,2,3都会转换为第四种,将具体的过期时间转换成毫秒保存到redis中,即使1,2传的是秒数和毫秒数,redis内部会转换成当前时间+秒/毫秒之后对应的毫秒,然后作为key的过期时间。
    1. EXPIRE key ttl
    2. PEXPIRE key ttl
    3. EXPIREAT key timestamp
    4. PEXPIREAT key timestamp
  • redis中通过过期字典expires,保存了数据库中所有键的过期时间
  • 过期字典的结构
    • 过期字典的键是一个指针,这个指正指向键空间中的某个键对象(也即是某个数据库键)
    • 过期字典的值是一个Long类型的整数,保存了键所指向的数据库键的过期时间(一个毫秒精度的UNIX时间戳)
  • 示意图,其中为了表示方便,写了两次alphabet和book实质,在过期字典中是指向键空间中的键对象的指针,而非键对象,图中也表示出来在这里插入图片描述
  • 过期时间的操作,新增、删除、获取
    1. 新增:PEXPIREAT message 1391234400000在这里插入图片描述
    2. 删除:PERSIST message在这里插入图片描述
    3. 获取:TTL
  • 过期键的判定
    1. 检查给定键是否存在于过期字典:如果存在,那么取得键的过期时间
    2. 检查当前UNIX时间戳是否大于键的过期时间:如果是的话,那么键已经过期;否则的话,键未过期。
5. 过期键的删除策略
  • 过期删除策略存在三种:
    1. 定时删除:创建一个定时器,在键的过期时间来临时,立即执行键的删除工作
    2. 惰性删除:暂时放任键过期不管,但是每次从键空间获取键时,都检查取得的键是否过期,如果过期就删除,没有则返回该键
    3. 定期删除:每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。
5.1 定时删除
  • 优点:对内存友好,可以保证键可以尽快的删除掉,不会长时间的堆积在内存中,造成内存的浪费
  • 缺点:对CPU不友好,在过期键比较多的情况下,占用相当一部分的CPU资源,影响服务器的吞吐量和响应时间。除此之外,需要用到redis服务器中的时间事件,当前时间事件的实现方式–无序链表,查找的时间复杂度O(N)
5.2 惰性删除
  • 优点:对CPU友好的,程序只在取出键时进行过期检查,删除的目标也仅限于当前处理的键,不会在其他的键上耗费时间
  • 缺点:对内存不友好,导致,很多无用的垃圾占用大量的内存
5.3 定期删除
  • 优点:
    1. 通过限制删除操作执行的时长和频率来减少删除操作对CPU的影响
    2. 通过定期删除,可以减少因为过期键太多导致的内存浪费
  • 确定:
    • 定期删除操作的时长和频率的确定
      1. 如果频率太高,势必会加重CPU的耗费时间
      2. 如果频率太少,或者执行时长太短,则会和惰性删除一样导致,内存的浪费
6 Redis过期键删除策略
  • redis中使用的是惰性删除和定期删除两种策略
6.1 惰性删除的实现
  • 惰性删除策略是由db.c/expireIfNeed函数实现,所有的读写数据库的Redis命令在执行之前都会调用expireIfNeed函数进行检查
    1. 如果输入键已经过期,那么expireIfNeed将输入键从数据库中删除
    2. 如果输入建未过期,那么不做任何动作在这里插入图片描述
  • expireIfNeed函数会对键进行删除,所以每个命令的实现都应该包括键存在和键不存在两个处理方式
    在这里插入图片描述
6.2 定期删除策略实现
  • 由redis.c/activeExpireCycle函数实现
  • 该函数会在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键。
  • 执行过程
    1. 函数每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查,并删除过期的。
    2. 在函数中会自己上次执行到哪个数据库,使用current_db来记录,在下次执行定期删除时,从current_db之后的数据库进行删除工作
    3. 随着activeExpireCycle函数的执行,势必服务器中有限的数据库都会被检查一遍,这个时间current_db会重置为一开始的0数据库,进行下一次的执行。
7 AOF RDB 和复制功能对过期键的处理
7.1 RDB
  1. 生成RDB文件
    • 在执行SAVE或者BGSAVE命令时,程序会对数据库中的键进行检查,已过期的键不会被保存到新创建的RDB文件中。
    • 数据库中包含过期键不会对新的RDB文件造成影响。
  2. 载入RDB文件
    • 在服务器启动的时候,在启动RDB文件的情况下,服务器对RDB文件进行载入
      1. 服务器是主服务器,在载入RDB文件时,会对键进行过期检查,未过期才会记录到数据库中,过期会被忽略,所以过期键对主数据库不会有影响
      2. 服务器是从服务器,在载入RDB文件时,文件保存所有的键,不论是否过期,都会被载入数据库中。不过在主数据库进行数据同步的时候,从服务器的数据库会被清空。所以一般来讲,过期键对载入RDB文件的从服务器不会造成影响。
7.2 AOF
  1. AOF文件写入
    1. 当服务器以AOF持久化模式运行时,如果数据库中的某个键过期了,但还没有执行惰性删除和定期删除,那么AOF文件不会因为这个过期键而发生任何影响
    2. 当过期键被惰性删除或者定期删除之后,程序会向AOF文件追加一条DEL命令,来显式记录该键被删除
  2. AOF重写
    1. 执行AOF重写的过成中,程序会对数据库中的过期键进行检查,已经过期的不会放到重新的AOF文件中。数据库中包含过期键不会对AOF重写造成影响。此时可能存在数据库中包含过期键,而AOF中没有。
7.2 复制
  • 当服务器运行在复制模式下,从服务器的过期键删除动作是由主服务器控制的
    1. 主服务器在删除一个过期键后,会显示的向所有的从服务器发送一条DEL命令,告知从服务器删除这个过期键
    2. 从服务器在执行客户端发送的读命令时,即使碰到过期键也不会将过期键删除,而是继续像处理未过期的键一样来处理过期键。
    3. 从服务器只有在主服务器发来的DEL命令之后,才会删除过期键
  • 通过由主服务器来控制从服务器统一删除过期键,可以保证主从服务器数据的一致性。
8 数据库通知
  • 概念:可以让客户端通过订阅给定的频道或模式,来获知数据中键的变化,以及数据库中命令的执行情况
  • 分为两类
    1. 键空间通知:某个键执行了什么命令,语法
    SUBSCRIBE _ _keyspace@数据库id_ _:键名称
    
    1. 键事件通知:某个命令被什么键执行了,语法
    SUBSCRIBE _ _keyevent@数据库id_ _:命令
    
  • 服务器配置的notify-keyspace-events选项决定了服务器所发送通知的类型
    1. AKE:发送键空间通知和键事件通知
    2. AK:发送键空间通知
    3. AE:发送键事件通知
8.1 发送通知
  • 发送通知是由notify.c/notifyKeyspaceEvent函数实现
void notifyKeyspaceEvent(int type,char *event,robj *key,int dbid)
8.2 发送通知的实现
  1. server.notify_keyspace_events属性就是服务器配置notify-keyspace-events选项锁设置的值,如果给定的通知类型type不是服务器允许的通知类型,那么函数直接返回不做任何操作
  2. 如果给定的通知是服务器允许发送的通知,那么下一步函数会检测服务器是否允许发送键空间通知,如果允许的话,程序就会构建并发送事件通知
  3. 最后,函数检测服务器是否允许发送键事件通知,如果允许的话,程序就会构建并发送事件通知。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、 1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READmE.文件(md如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值