《Redis设计与实现》读书笔记-第二部分:单机数据库的实现-4:客户端与服务端

目录

1、客户端

1.1客户端属性

1.1.1套接字描述符

1.1.2名字

1.1.3标志

1.1.4输入缓冲区 

1.1.5命令与命令参数

 1.1.6命令的实现函数

 1.1.7输出缓冲区

1.1.8身份验证

1.1.9时间

1.2客户端的创建与关闭

1.2.1创建普通客户端

1.2.2关闭普通客户端 

1.2.3Lua脚本的伪客户端 

1.2.4AOF文件的伪客户端

2、服务器

2.1命令请求的执行过程

1.1.1发送命令请求 

2.1.2读取请求命令

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

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

2.1.5命令执行器(3):调运命令的实现函数

2.1.6命令执行器(4):执行后续工作

2.1.7将命令回复发送给客户端

2.1.8客户端接收并打印命令回复

2.2severCron函数

2.2.2更新LRU时钟

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

2.2.4更新服务器内存峰值记录

​ 2.2.5处理SIGTERM信号

​ 2.2.6管理客户端资源

2.2.7管理数据库资源 

 2.2.8执行被延迟的BGREWRITEAOF

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

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

2.2.11关闭异步客户端 

2.2.12增加cronloops计数器的值

 2.3初始化服务器

 2.3.1初始化服务器状态结构

2.3.2载入配置选项 

2.3.3初始化服务器数据结构 

2.3.4还原数据库状态

2.3.5执行时间循环


1、客户端

redis服务器是典型的一对多服务器程序:一个服务器可以与多个客户端建立起网络连接,每个客户端可以向服务器发送命令请求,而服务器则接收并处理客户端发送的命令请求,并向客户端返回命令回复。

 redis服务器状态结构的clients属性是一个链表,这个链表保存了所有与服务器连接的客户端状态结构,对客户端执行批量操作或者查找某个指定的客户端,都可以通过遍历clients链表完成:

1.1客户端属性

1.1.1套接字描述符

客户端状态的fd属性记录了客户端正在使用的套接字描述符:

typedef struct redisClient {
    //...
    int fd;
    //...
}redisClient

1.1.2名字

在默认情况下,一个连接到服务器的客户端是没有名字的。

使用CLIENT setname 命令可以为客户端设置一个名字,让客户党的身份变得更加清晰。

客户端的名字记录在客户端状态的name属性里面:

typedef struct redisClient {
    //...
    robj *name;
    //...
}redisClient

如果客户端没有为自己设置名字,那么相应客户端状态的name属性指向NULL指针;相反的,就会指向一个字符串对象。

1.1.3标志

客户端的标志属性flags记录了客户端的角色,以及客户端目前所处的状态

typedef struct redisClient {
    //...
    int flags;
    //...
}redisClient

每个标志使用一个常量表示,一部分标志记录了客户端的角色: 

而另一部分标志则记录了客户端目前所处的状态: 

 

1.1.4输入缓冲区 

客户端状态的输入缓冲区用于保存客户端发送的命令请求:

typedef struct redisClient {
    //...
    sds querybuf;
    //...
}redisClient

1.1.5命令与命令参数

 1.1.6命令的实现函数

针对命令表的朝族不区分输入字母的大小写

 1.1.7输出缓冲区

执行命令所得的命令回复会被保存在客户端状态的输出缓冲区里面,每个客户端都有两个输出缓冲区可用,一个缓冲区的大小是固定的,另一个缓冲区的大小是可变的。

1.1.8身份验证

客户端状态的authenticated 属性用于记录客户端是否通过了身份验证:如果这个属性的值为0那么代表客户端未通过身份验证,如果为1则表示已经通过了身份验证。

typedef struct redisClient {
    //...
    int authenticated;
    //...
}redisClient

1.1.9时间

1.2客户端的创建与关闭

服务器使用不同的方式来创建和关闭不同类型的客户端,本节将介绍服务器创建和关闭客户端的方法。

1.2.1创建普通客户端

1.2.2关闭普通客户端 

一个客户端可以因为多种原因而被关闭:

1.2.3Lua脚本的伪客户端 

1.2.4AOF文件的伪客户端

2、服务器

 

 

2.1命令请求的执行过程

1.1.1发送命令请求 

2.1.2读取请求命令

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

 

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

在真正执行命令之前,程序还需要进行一些预备操作,从而确保命令可以正确、顺利地被执行,这些操作包括: 

2.1.5命令执行器(3):调运命令的实现函数

2.1.6命令执行器(4):执行后续工作

 

2.1.7将命令回复发送给客户端

 命令实现函数会将回复保存到客户端的输出缓冲区里面,并为客户端的套接字关联命令回复处理器,当客户端套接字变为可写状态时,服务器就会执行命令回复处理器,将保存在客户端输出缓冲区中的命令回复发送给客户端。当命令回复发送完毕之后,回复处理器会清空客户端状态的输出缓冲区的,为处理下一个命令请求做好准备。

2.1.8客户端接收并打印命令回复

2.2severCron函数

redis服务器中有不少功能需要获取系统的当前时间,而每次获取系统的当前时间都需要执行一次系统调用,为了减少系统调用的执行次数,服务器状态中的unixtime属性和mstime属性被用作当前时间的缓存:

struct redisServe{
    //...
    //保存了秒级进度的系统当前UNIX时间戳
    time_t unixtime
    //保存了毫秒级进度的系统当前UNIX时间戳
    long long mstime;
    //...   
};

 因为serveCron函数默认会以每100毫秒一次的频率更新unixtime属性和mstime属性,所以这两个属性记录的时间的精确度并不高:

2.2.2更新LRU时钟

 

当服务器要计算一个数据库的空转时间(也即是数据空键对应的值对象的空转时间),程序会用服务器的lruclock属性记录的时间减去对象的lru属性记录的时间,得出的计算结果就是这个对象的空转时间: 

 

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

 

2.2.4更新服务器内存峰值记录

 2.2.5处理SIGTERM信号

 

 2.2.6管理客户端资源

2.2.7管理数据库资源 

 2.2.8执行被延迟的BGREWRITEAOF

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

 

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

 

2.2.11关闭异步客户端 

在这一步,服务器会关闭那些输出缓冲区大小超出限制的客户端。

2.2.12增加cronloops计数器的值

 2.3初始化服务器

 2.3.1初始化服务器状态结构

初始化服务器的第一步就是创建一个struct redisServe类型的实例变量server作为服务器的状态,并为结构中各个属性设置默认值。

2.3.2载入配置选项 

 

2.3.3初始化服务器数据结构 

 

2.3.4还原数据库状态

在完成了对服务器状态server变量的初始化之后,服务器需要载入RDB文件或者AOF文件,并根据文件记录的内容来还原服务器的数据库状态。

2.3.5执行时间循环

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值