【笔记】《Redis设计与实现》chapter14 服务器

14.1 命令请求的执行过程

读取命令请求

命令执行器(1):查找命令实现

在命令表(command table)中查找参数所指定的命令,并将找到的命令保存到客户端状态的cmd属性里面

image-20201012133920371

image-20201012133944697

命令执行器(2):执行预备操作

14.2 serverCron函数

更新服务器时间缓存

struct redisServer{
    //...
    // 保存了秒级精度的系统当前UNIX时间戳
    time_t unixtime;
    
    // 保存了毫秒级精度的系统当前UNIX时间戳
    long long mstime;
    
    // 默认10秒更新一次的时间缓存, 用于计算键的空转时间
    unsigned lruclock:22;
    
};

struct redisObject{
    //...
    
    // 对象最后一次被命令访问的时间
    unsigned lru:22;
    
    //...
};

更新服务器每秒执行命令次数

serverCron函数中的trackOperationsPerSecond函数会以每100毫秒一次的频率执行,这个函数的功能是以抽样计算的方式,估算并记录服务器在最近一秒处理的命令请求数量

struct redisServer{
    //...
    
    // 上一次进行抽样的时间
    long long ops_sec_last_sample_time;
    
    // 上一次抽样时,服务器已执行命令的数量
    long long ops_sec_last_sample_ops;
    
    // REDIS_OPS_SEC_SAMPLES大小(默认值为16)的环形数组
    // 数组中的每个项都记录了一次抽样结果
    long long ops_sec_samples[REDIS_OPS_SEC_SAMPLES];
    
    // ops_sec_samples数组的索引值
    // 每次抽样后将值自增1
    // 在值等于16时重置为0
    int ops_sec_idx;
    
    //...
};

更新服务器内存峰值记录

struct redisServer{
    //...
    
    // 已使用内存峰值
    size_t stat_peaak_memory;
    
    //...
};

处理SIGTERM信号

管理客户端资源

serverCron函数每次执行都会调用clientsCron函数,clientsCron函数会对一定数量的客户端进行以下两个检查:

  • 如果客户端与服务器之间的连接已经超时,那么程序释放这个客户端
  • 如果客户端在上一次执行命令请求之后,输入缓冲区的大小超过了一定的长度,那么程序会释放客户端当前的输入缓冲区,并重新创建一个默认大小的输入缓冲区

管理数据库资源

serverCron函数每次执行都会调用databasesCron函数,这个函数会对服务器中的一部分数据库进行检查,删除其中的过期键,并在有需要时,对字典进行收缩操作

执行被延迟的BGREWRITEAOF

服务器的aof_rewrite_scheduled标识记录了服务器是否延迟了BGREWRITEAOF命令:

struct redisServer{
    //...
    
    //如果值为1, 那么标识有 BGREWRITEAOF 命令被延迟了
    int aof_rewrite_scheduled;
    
    //...
};

检查持久化操作的运行状态

服务器状态使用rdb_child_pid 属性和 aof_child_pid 属性记录执行BGSAVE命令和 BGREWRITEAOF 命令的子进程的ID

struct redisServer{
    //...
    
    // 记录执行BGSAVE命令的子进程的ID
    // 如果服务器没有在执行BGSAVE
    // 那么这个属性的值为-1
    pid_t rdb_child_pid;
    
    // 记录执行BGREWRITEAOF 命令的子进程的ID
    // 如果服务器没有在执行BGREWRITEAOF
    // 那么这个属性的值为-1
    pid_t aof_child_pid;
    
    //...
};

image-20201013004459625

将AOF缓冲区中的内容写入AOF文件

关闭异步客户端

增加cronloops计数器的值

struct redisServer{
    //...
    
    // serverCron函数的运行次数计数器
    int cronloops;
    
    //...
};

14.3 初始化服务器

void initServerConfig(void) {
    int j;

    updateCachedTime(1);

    // 设置服务器运行id
    getRandomHexChars(server.runid,CONFIG_RUN_ID_SIZE);

    // 设置默认服务器频率
    server.hz = CONFIG_DEFAULT_HZ; /* Initialize it ASAP, even if it may get
                                      updated later after loading the config.
                                      This value may be used before the server
                                      is initialized. */
    server.timezone = getTimeZone(); /* Initialized by tzset(). */

    // 设置默认配置文件路径
    server.configfile = NULL;

    // 设置服务器的运行架构
    server.arch_bits = (sizeof(long) == 8) ? 64 : 32;
    
    //...
}

载入配置选项

初始化服务器数据结构

initServerConfig函数主要负责初始化一般属性

initServer函数主要负责初始化数据结构

除了初始化数据结构之外,initServer还进行了一些非常重要的设置操作,其中包括:

  • 为服务器设置进程信号处理器
  • 创建共享对象:这些对象包含Redis服务器经常用到的一些值,比如包含“OK”回复的自负床对象,包含整数1 到 10000 的字符串对象等等,服务器通过重用这些共享对象来避免反复创建相同的对象
  • 打开服务器的监听端口,并为监听套接字关联连接应答事件处理器,等待服务器正式运行时接收客户端的连接
  • 为serverCron函数创建时间事件,等待服务器正式运行时执行serverCron函数
  • 如果AOF持久化功能已经打开,那么打开现有的AOF文件,如果AOF文件不存在,那么创建并打开一个新的AOF文件,为AAOF写入做好准备
  • 初始化服务器的后台IO模块,为将来的IO操作做好准备

还原数据库状态

根据服务器是否启用了AOF持久化功能,服务器载入数据时所使用的目标文件会有所不同:

  • 如果服务器启用了AOF持久化功能,那么服务器使用AOF文件来还原数据库状态
  • 否则使用RDB文件来还原数据库状态

执行事件循环

posted @ 2021-04-20 11:34  汉森伯逸  阅读(51)  评论(0)    收藏  举报