单机数据库的实现
一、Redis数据库实现原理
1.键的生存时间或过期时间
- expire :将键key的生存时间设置为ttl秒
- pexpire :将键key的生存时间设置为ttl毫秒
- expireat :将键key的过期时间设置为timestamp所指定的秒数时间戳
- pexpireat :将键key的过期时间设置为timestamp所指定的毫秒数时间戳
无论客户端执行的是以上四个命令中的哪一个,经过转换之后,最终的执行效果都和执行PEXPIREAT命令一样。
2. 关于生存时间的命令
-
persist移除键的过期时间
-
TTL:以秒为单位返回键的剩余生存时间,
-
PTTL:以毫秒为单位返回键的剩余生存时间
-
SETEX:可以在设置一个字符串键的同时为键设置过期时间
-
TTL命令和PTTL命令接受一个带有生存时间或者过期时间的键,返回这个键的剩余生存时间
3. 过期键删除策略
- 定时删除占用太多CPU时间,影响服务器的响应时间和吞吐量。
- 惰性删除浪费太多内存,有内存泄漏的危险。
- 定期删除策略是前两种策略的一种整合和折中:
- 定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响。
- 除此之外,通过定期删除过期键,定期删除策略有效地减少了因为过期键而带来的内存浪费。
- 定期删除策略的难点是确定删除操作执行的时长和频率:
- 如果删除操作执行得太频繁,或者执行的时间太长,定期删除策略就会退化成定时删除策略,以至于将CPU时间过多地消耗在删除过期键上面。
- 如果删除操作执行得太少,或者执行的时间太短,定期删除策略又会和惰性删除策略一样,出现浪费内存的情况。
- 因此,如果采用定期删除策略的话,服务器必须根据情况,合理地设置删除操作的执行时长和执行频率。
- Redis服务器实际使用的是惰性删除和定期删除两种策略:
- 通过配合使用这两种删除策略,服务器可以很好地在合理使用CPU时间和避免浪费内存空间之间取得平衡
4. AOF、RDB和复制功能对过期键的处理
1) 生成RDB文件
- 在执行SAVE命令或者BGSAVE命令创建一个新的RDB文件时,程序会对数据库中的键进行检查
- 已过期的键不会被保存到新创建的RDB文件中
2) 载入RDB文件
- 在启动Redis服务器时,如果服务器开启了RDB功能,那么服务器将对RDB文件进行载入
- 服务器以主服务器模式运行,那么在载入RDB文件时,程序会对文件中保存的键进行检查,未过期的键会被载入到数据库中,而过期键则会被忽略
- 所以过期键对载入RDB文件的主服务器不会造成影响。
- 服务器以从服务器模式运行,那么在载入RDB文件时,文件中保存的所有键,不论是否过期,都会被载入到数据库中。
- 不过,因为主从服务器在进行数据同步的时候,从服务器的数据库就会被清空
- 所以一般来讲,过期键对载入RDB文件的从服务器也不会造成影响。
- 服务器以主服务器模式运行,那么在载入RDB文件时,程序会对文件中保存的键进行检查,未过期的键会被载入到数据库中,而过期键则会被忽略
3)AOF文件写入
- 当服务器以AOF持久化模式运行时
- 如果数据库中的某个键已经过期,但它还没有被惰性删除或者定期删除,那么AOF文件不会因为这个过期键而产生任何影响。
- 当过期键被惰性删除或者定期删除之后,程序会向AOF文件追加(append)一条DEL命令,来显式地记录该键已被删除。
- eg:如果客户端使用GET message命令,试图访问过期的message键,那么服务器将执行以下三个动作:
- (1)从数据库中删除message键。
- (2)追加一条DEL message命令到AOF文件。
- (3)向执行GET命令的客户端返回空回复。
4)AOF重写
- 和生成RDB文件时类似,在执行AOF重写的过程中,程序会对数据库中的键进行检查,已过期的键不会被保存到重写后的AOF文件中。
- eg:如果数据库中包含三个键k1、k2、k3,并且k2已经过期,那么在进行重写工作时,程序只会对k1和k3进行重写,而k2则会被忽略。因此,数据库中包含过期键不会对AOF重写造成影响。
5) 复制
- 当服务器运行在复制模式下时,从服务器的过期键删除动作由主服务器控制:
- 主服务器在删除一个过期键之后,会显式地向所有从服务器发送一个DEL命令,告知从服务器删除这个过期键。
- 从服务器在执行客户端发送的读命令时,即使碰到过期键也不会将过期键删除,而是继续像处理未过期的键一样来处理过期键。
- 从服务器只有在接到主服务器发来的DEL命令之后,才会删除过期键。
- 通过由主服务器来控制从服务器统一地删除过期键,可以保证主从服务器数据的一致性
- 也正是因为这个原因,当一个过期键仍然存在于主服务器的数据库时,这个过期键在从服务器里的复制品也会继续存在。
5. 数据库通知
- 数据库通知是Redis 2.8版本新增加的功能
- 这个功能可以让客户端通过订阅给定的频道或者模式,来获知数据库中键的变化,以及数据库中命令的执行情况
6. 重点回顾
- Redis服务器的所有数据库都保存在redisServer.db数组中,而数据库的数量则由redisServer.dbnum属性保存。
- 客户端通过修改目标数据库指针,让它指向redisServer.db数组中的不同元素来切换不同的数据库。
- 数据库主要由dict和expires两个字典构成,其中dict字典负责保存键值对,而expires字典则负责保存键的过期时间。
- 因为数据库由字典构成,所以对数据库的操作都是建立在字典操作之上的。
- 数据库的键总是一个字符串对象,而值则可以是任意一种Redis对象类型,包括字符串对象、哈希表对象、集合对象、列表对象和有序集合对象,分别对应字符串键、哈希表键、集合键、列表键和有序集合键。
- expires字典的键指向数据库中的某个键,而值则记录了数据库键的过期时间,过期时间是一个以毫秒为单位的UNIX时间戳。
- Redis使用惰性删除和定期删除两种策略来删除过期的键:惰性删除策略只在碰到过期键时才进行删除操作,定期删除策略则每隔一段时间主动查找并删除过期键。
- 执行SAVE命令或者BGSAVE命令所产生的新RDB文件不会包含已经过期的键。
- 执行BGREWRITEAOF命令所产生的重写AOF文件不会包含已经过期的键。
- 当一个过期键被删除之后,服务器会追加一条DEL命令到现有AOF文件的末尾,显式地删除过期键。
(搞不动了,敲字敲的手酸,开始复制粘贴式的整理=。=)
二、RDB持久化
- Redis是内存数据库,它将自己的数据库状态储存在内存里面,所以如果不想办法将储存在内存中的数据库状态保存到磁盘里面,那么一旦服务器进程退出,服务器中的数据库状态也会消失不见。
- 为了解决这个问题,Redis提供了RDB持久化功能,这个功能可以将Redis在内存中的数据库状态保存到磁盘里面,避免数据意外丢失。
- RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中
- RDB持久化功能所生成的RDB文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态
- 因为RDB文件是保存在硬盘里面的,所以即使Redis服务器进程退出,甚至运行Redis服务器的计算机停机,但只要RDB文件仍然存在,Redis服务器就可以用它来还原数据库状态。
1. 保存和载入RDB文件的方法
- SAVE命令和BGSAVE命令
SAVE
- SAVE命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求
BGSAVE
- BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求
RDB文件的载入
- RDB文件的载入工作是在服务器启动时自动执行的,
- 所以Redis并没有专门用于载入RDB文件的命令
- 只要Redis服务器在启动时检测到RDB文件存在,它就会自动载入RDB文件
因为AOF文件的更新频率通常比RDB文件的更新频率高
如果服务器开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据库状态。
只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数据库状态。
2. 自动间隔性保存
- Redis允许用户通过设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令。
- 用户可以通过save选项设置多个保存条件
- 当任意一个保存条件被满足时,服务器会自动执行BGSAVE命令。
3. RDB文件结构
- RDB文件是一个经过压缩的二进制文件,由多个部分组成。
- 对于不同类型的键值对,RDB文件会使用不同的方式来保存它们。
三、AOF持久化(Append Only File)
- AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态
1. AOF持久化的实现
- AOF持久化功能的实现可以分为命令追加(append)、文件写入、文件同步(sync)三个步骤
1)追加
- 当AOF持久化功能处于打开状态时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾
2)写入
- 服务器在处理文件事件时可能会执行写命令,使得一些内容被追加到aof_buf缓冲区里面,所以在服务器每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区中的内容写入和保存到AOF文件里面
- flushAppendOnlyFile函数的行为由服务器配置的appendfsync选项的值来决定
- 如果用户没有主动为appendfsync选项设置值,那么appendfsync选项的默认值为everysec
- 文件的写入和同步
- 为了提高文件的写入效率,在现代操作系统中,当用户调用write函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满、或者超过了指定的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。
- 这种做法虽然提高了效率,但也为写入数据带来了安全问题,因为如果计算机发生停机,那么保存在内存缓冲区里面的写入数据将会丢失。
- 为此,系统提供了fsync和fdatasync两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性。
- AOF持久化的效率和安全性
- 服务器配置appendfsync选项的值直接决定AOF持久化功能的效率和安全性
- 值为always:
- 服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件,并且同步AOF文件
- always的效率是appendfsync选项三个值当中最慢的一个,但从安全性来说,always也是最安全的,因为即使出现故障停机,AOF持久化也只会丢失一个事件循环中所产生的命令数据。
- 值为everysec:
- 服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件,并且每隔一秒就要在子线程中对AOF文件进行一次同步。
- 从效率上来讲,everysec模式足够快,并且就算出现故障停机,数据库也只丢失一秒钟的命令数据。
- 值为no:
- 服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件,至于何时对AOF文件进行同步,则由操作系统控制。
- 因为处于no模式下的flushAppendOnlyFile调用无须执行同步操作,所以该模式下的AOF文件写入速度总是最快的
- 不过因为这种模式会在系统缓存中积累一段时间的写入数据,所以该模式的单次同步时长通常是三种模式中时间最长的。
- 从平摊操作的角度来看,no模式和everysec模式的效率类似
- 当出现故障停机时,使用no模式的服务器将丢失上次同步AOF文件之后的所有写命令数据。
- 值为always:
- 服务器配置appendfsync选项的值直接决定AOF持久化功能的效率和安全性
2. AOF文件的载入与数据还原
- AOF文件里面包含了重建数据库状态所需的所有写命令,所以服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态。
- Redis读取AOF文件并还原数据库状态的详细步骤如下:
- 1)创建一个不带网络连接的伪客户端(fake client):
- 因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令,
- 伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样。
- 2)从AOF文件中分析并读取出一条写命令。
- 3)使用伪客户端执行被读出的写命令。
- 4)一直执行步骤2和步骤3,直到AOF文件中的所有写命令都被处理完毕为止。
- 1)创建一个不带网络连接的伪客户端(fake client):
3. AOF重写
- 为了解决AOF文件体积膨胀的问题,Redis提供了AOF文件重写(rewrite)功能
- 原理:首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是AOF重写功能的实现原理
注意:
在实际中,为了避免在执行命令时造成客户端输入缓冲区溢出,重写程序在处理列表、哈希表、集合、有序集合这四种可能会带有多个元素的键时,会先检查键所包含的元素数量,如果元素的数量超过了redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD常量的值,那么重写程序将使用多条命令来记录键的值,而不单单使用一条命令。
-
Redis服务器设置了一个AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令之后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区
-
这也就是说,在子进程执行AOF重写期间,服务器进程需要执行以下三个工作:
- 1)执行客户端发来的命令。
- 2)将执行后的写命令追加到AOF缓冲区。
- 3)将执行后的写命令追加到AOF重写缓冲区。
- 这样一来可以保证:
- AOF缓冲区的内容会定期被写入和同步到AOF文件,对现有AOF文件的处理工作会如常进行。
- 从创建子进程开始,服务器执行的所有写命令都会被记录到AOF重写缓冲区里面。
-
当子进程完成AOF重写工作之后,它会向父进程发送一个信号,父进程在接到该信号之后,会调用一个信号处理函数,并执行以下工作:
- 1)将AOF重写缓冲区中的所有内容写入到新AOF文件中,这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致。
- 2)对新的AOF文件进行改名,原子地(atomic)覆盖现有的AOF文件,完成新旧两个AOF文件的替换。
-
这个信号处理函数执行完毕之后,父进程就可以继续像往常一样接受命令请求了。
-
在整个AOF后台重写过程中,只有信号处理函数执行时会对服务器进程(父进程)造成阻塞,在其他时候,AOF后台重写都不会阻塞父进程,这将AOF重写对服务器性能造成的影响降到了最低。
-
AOF文件后台重写过程
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文件重写操作。
- 在执行BGREWRITEAOF命令时
四、事件
- Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件:
- 文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象。服务器与客户端(或者其他服务器)的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信操作。
- 时间事件(time event):Redis服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对这类定时操作的抽象。
1. 文件事件
- 文件事件处理器使用I/O多路复用(multiplexing)程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
- 当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
- 虽然文件事件处理器以单线程方式运行,但通过使用I/O多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与Redis服务器中其他同样以单线程方式运行的模块进行对接,这保持了Redis内部单线程设计的简单性
1) 文件事件处理器组成部分
- 分别是套接字、I/O多路复用程序、文件事件分派器(dispatcher),以及事件处理器
2) I/O多路复用程序的实现
- Redis的I/O多路复用程序的所有功能都是通过包装常见的select、epoll、evport和kqueue这些I/O多路复用函数库来实现的,每个I/O多路复用函数库在Redis源码中都对应一个单独的文件,比如ae_select.c、ae_epoll.c、ae_kqueue.c,诸如此类。
- 因为Redis为每个I/O多路复用函数库都实现了相同的API,所以I/O多路复用程序的底层实现是可以互换的
- Redis在I/O多路复用程序的实现源码中用#include宏定义了相应的规则,程序会在编译时自动选择系统中性能最高的I/O多路复用函数库来作为Redis的I/O多路复用程序的底层实现
3) 事件的类型
- I/O多路复用程序可以监听多个套接字的ae.h/AE_READABLE事件和ae.h/AE_WRITABLE事件,这两类事件和套接字操作之间的对应关系如下:
- 当套接字变得可读时(客户端对套接字执行write操作,或者执行close操作),或者有新的可应答(acceptable)套接字出现时(客户端对服务器的监听套接字执行connect操作),套接字产生AE_READABLE事件。
- 当套接字变得可写时(客户端对套接字执行read操作),套接字产生AE_WRITABLE事件。
- I/O多路复用程序允许服务器同时监听套接字的AE_READABLE事件和AE_WRITABLE事件,如果一个套接字同时产生了这两种事件,那么文件事件分派器会优先处理AE_READABLE事件,等到AE_READABLE事件处理完之后,才处理AE_WRITABLE事件。
- 这也就是说,如果一个套接字又可读又可写的话,那么服务器将先读套接字,后写套接字
2.时间事件
- Redis的时间事件分为以下两类:
- 定时事件:让一段程序在指定的时间之后执行一次。比如说,让程序X在当前时间的30毫秒之后执行一次。
- 周期性事件:让一段程序每隔指定时间就执行一次。比如说,让程序Y每隔30毫秒就执行一次。一个时间事件主要由以下三个属性组成:
- id:服务器为时间事件创建的全局唯一ID(标识号)。ID号按从小到大的顺序递增,新事件的ID号比旧事件的ID号要大。
- when:毫秒精度的UNIX时间戳,记录了时间事件的到达(arrive)时间。
- timeProc:时间事件处理器,一个函数。当时间事件到达时,服务器就会调用相应的处理器来处理事件。
- 一个时间事件是定时事件还是周期性事件取决于时间事件处理器的返回值:
- 如果事件处理器返回ae.h/AE_NOMORE,那么这个事件为定时事件:该事件在达到一次之后就会被删除,之后不再到达。
- 如果事件处理器返回一个非AE_NOMORE的整数值,那么这个事件为周期性时间:当一个时间事件到达之后,服务器会根据事件处理器返回的值,对时间事件的when属性进行更新,让这个事件在一段时间之后再次到达,并以这种方式一直更新并运行下去。比如说,如果一个时间事件的处理器返回整数值30,那么服务器应该对这个时间事件进行更新,让这个事件在30毫秒之后再次到达。
- 目前版本的Redis只使用周期性事件,而没有使用定时事件。
3.重点回顾
-
- Redis服务器是一个事件驱动程序,服务器处理的事件分为时间事件和文件事件两类。
-
- 文件事件处理器是基于Reactor模式实现的网络通信程序。
-
- 文件事件是对套接字操作的抽象:每次套接字变为可应答(acceptable)、可写(writable)或者可读(readable)时,相应的文件事件就会产生。
-
- 文件事件分为AE_READABLE事件(读事件)和AE_WRITABLE事件(写事件)两类。
-
- 时间事件分为定时事件和周期性事件:定时事件只在指定的时间到达一次,而周期性事件则每隔一段时间到达一次。
-
- 服务器在一般情况下只执行serverCron函数一个时间事件,并且这个事件是周期性事件。
-
- 文件事件和时间事件之间是合作关系,服务器会轮流处理这两种事件,并且处理事件的过程中也不会进行抢占。
-
- 时间事件的实际处理时间通常会比设定的到达时间晚一些。
五、客户端
- Redis服务器是典型的一对多服务器程序:
- 一个服务器可以与多个客户端建立网络连接,每个客户端可以向服务器发送命令请求,而服务器则接收并处理客户端发送的命令请求,并向客户端返回命令回复。
- 通过使用由I/O多路复用技术实现的文件事件处理器,Redis服务器使用单线程单进程的方式来处理命令请求,并与多个客户端进行网络通信。
- 对于每个与服务器进行连接的客户端,服务器都为这些客户端建立了相应的redis.h/redisClient结构(客户端状态),这个结构保存了客户端当前的状态信息,以及执行相关功能时需要用到的数据结构,其中包括:
- 客户端的套接字描述符。
- 客户端的名字。
- 客户端的标志值(flag)。
- 指向客户端正在使用的数据库的指针,以及该数据库的号码。❑客户端当前要执行的命令、命令的参数、命令参数的个数,以及指向命令实现函数的指针。
- 客户端的输入缓冲区和输出缓冲区。
- 客户端的复制状态信息,以及进行复制所需的数据结构。
- 客户端执行BRPOP、BLPOP等列表阻塞命令时使用的数据结构。
- 客户端的事务状态,以及执行WATCH命令时用到的数据结构。
- 客户端执行发布与订阅功能时用到的数据结构。
- 客户端的身份验证标志。
- 客户端的创建时间,客户端和服务器最后一次通信的时间,以及客户端的输出缓冲区大小超出软性限制(soft limit)的时间。
重点
- 服务器状态结构使用clients链表连接起多个客户端状态,新添加的客户端状态会被放到链表的末尾。
- 客户端状态的flags属性使用不同标志来表示客户端的角色,以及客户端当前所处的状态。
- 输入缓冲区记录了客户端发送的命令请求,这个缓冲区的大小不能超过1GB。
- 命令的参数和参数个数会被记录在客户端状态的argv和argc属性里面,而cmd属性则记录了客户端要执行命令的实现函数。
- 客户端有固定大小缓冲区和可变大小缓冲区两种缓冲区可用,其中固定大小缓冲区的最大大小为16KB,而可变大小缓冲区的最大大小不能超过服务器设置的硬性限制值。
- 输出缓冲区限制值有两种,如果输出缓冲区的大小超过了服务器设置的硬性限制,那么客户端会被立即关闭;除此之外,如果客户端在一定时间内,一直超过服务器设置的软性限制,那么客户端也会被关闭。
- 当一个客户端通过网络连接连上服务器时,服务器会为这个客户端创建相应的客户端状态。网络连接关闭、发送了不合协议格式的命令请求、成为CLIENT KILL命令的目标、空转时间超时、输出缓冲区的大小超出限制,以上这些原因都会造成客户端被关闭。
- 处理Lua脚本的伪客户端在服务器初始化时创建,这个客户端会一直存在,直到服务器关闭。
- 处理Lua脚本的伪客户端在服务器初始化时创建,这个客户端会一直存在,直到服务器关闭。
- 载入AOF文件时使用的伪客户端在载入工作开始时动态创建,载入工作完毕之后关闭
六、服务器
- Redis服务器负责与多个客户端建立网络连接,处理客户端发送的命令请求,在数据库中保存客户端执行命令所产生的数据,并通过资源管理来维持服务器自身的运转。
重点
- 一个命令请求从发送到完成主要包括以下步骤:
- 1 客户端将命令请求发送给服务器;
- 2 服务器读取命令请求,并分析出命令参数;
- 3 命令执行器根据参数查找命令的实现函数,然后执行实现函数并得出命令回复;
- 4 服务器将命令回复返回给客户端。
- serverCron函数默认每隔100毫秒执行一次,它的工作主要包括更新服务器状态信息,处理服务器接收的SIGTERM信号,管理客户端资源和数据库状态,检查并执行持久化操作等等。
- 服务器从启动到能够处理客户端的命令请求需要执行以下步骤:
- 1 初始化服务器状态;
- 2 载入服务器配置;
- 3 初始化服务器数据结构;
- 4 还原数据库状态;
- 5 执行事件循环。