单机数据库
·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持久化
RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中。
·RDB文件用于保存和还原Redis服务器所有数据库中的所有键值对数据。
·SAVE命令由服务器进程直接执行保存操作,所以该命令会阻塞服务器。
·BGSAVE令由子进程执行保存操作,所以该命令不会阻塞服务器。
·服务器状态中会保存所有用save选项设置的保存条件,当任意一个保存条件被满足时,服务器会自动执行BGSAVE命令。
·RDB文件是一个经过压缩的二进制文件,由多个部分组成。
·对于不同类型的键值对,RDB文件会使用不同的方式来保存它们。
AOF持久化
除了RDB持久化功能之外,Redis还提供了AOF(Append Only File)持久化功能。与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。
·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文件重写操作。
事件
·文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象。服务器与客户端(或者其他服务器)的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信操作。
·时间事件(time event):Redis服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对这类定时操作的抽象。
·文件事件处理器是基于Reactor模式实现的网络通信程序。
·文件事件是对套接字操作的抽象:每次套接字变为可应答(acceptable)、可写(writable)或者可读(readable)时,相应的文件事件就会产生。
·文件事件分为AE_READABLE事件(读事件)和AE_WRITABLE事件(写事件)两类。
·时间事件分为定时事件和周期性事件:定时事件只在指定的时间到达一次,而周期性事件则每隔一段时间到达一次。
·服务器在一般情况下只执行serverCron函数一个时间事件,并且这个事件是周期性事件。
·文件事件和时间事件之间是合作关系,服务器会轮流处理这两种事件,并且处理事件的过程中也不会进行抢占。
·时间事件的实际处理时间通常会比设定的到达时间晚一些。
客户端
·服务器状态结构使用clients链表连接起多个客户端状态,新添加的客户端状态会被放到链表的末尾。
·客户端状态的flags属性使用不同标志来表示客户端的角色,以及客户端当前所处的状态。
·输入缓冲区记录了客户端发送的命令请求,这个缓冲区的大小不能超过1GB。
·命令的参数和参数个数会被记录在客户端状态的argv和argc属性里面,而cmd属性则记录了客户端要执行命令的实现函数。
·客户端有固定大小缓冲区和可变大小缓冲区两种缓冲区可用,其中固定大小缓冲区的最大大小为16KB,而可变大小缓冲区的最大大小不能超过服务器设置的硬性限制值。
·输出缓冲区限制值有两种,如果输出缓冲区的大小超过了服务器设置的硬性限制,那么客户端会被立即关闭;除此之外,如果客户端在一定时间内,一直超过服务器设置的软性限制,那么客户端也会被关闭。
·当一个客户端通过网络连接连上服务器时,服务器会为这个客户端创建相应的客户端状态。网络连接关闭、发送了不合协议格式的命令请求、成为CLIENT KILL命令的目标、空转时间超时、输出缓冲区的大小超出限制,以上这些原因都会造成客户端被关闭。
·处理Lua脚本的伪客户端在服务器初始化时创建,这个客户端会一直存在,直到服务器关闭。
·载入AOF文件时使用的伪客户端在载入工作开始时动态创建,载入工作完毕之后关闭。
服务器
·一个命令请求从发送到完成主要包括以下步骤:1)客户端将命令请求发送给服务器;2)服务器读取命令请求,并分析出命令参数;3)命令执行器根据参数查找命令的实现函数,然后执行实现函数并得出命令回复;4)服务器将命令回复返回给客户端。
·serverCron函数默认每隔100毫秒执行一次,它的工作主要包括更新服务器状态信息,处理服务器接收的SIGTERM信号,管理客户端资源和数据库状态,检查并执行持久化操作等等。
·服务器从启动到能够处理客户端的命令请求需要执行以下步骤:1)初始化服务器状态;2)载入服务器配置;3)初始化服务器数据结构;4)还原数据库状态;5)执行事件循环。
引用
《Redis 设计与实现》