事件
一、文件事件
文件事件处理器使用I/O多路复用程序来同时监听多个套接字,
监听套接字,分配对应的处理事件。
四个组成部分:套接字 、I/O多路复用 、 文件事件分派器 、 事件处理器
连接应答处理器:redis服务器初始化,将连接应答处理器和服务器监听套接字的事件惯量,当客户端使用connect 函数链接服务器,套接字产生事件,触发连接应答处理器。
命令请求处理器:客户端向服务器发送命令请求的时候,套接字产生事件,触发命令请求处理器处理请求。
命令回复处理器:服务器命令回复传给客户端,服务器将命令回复处理器和事件关联,客户端准备接收回传命令后,触发事件引发回复处理器执行。
二、时间事件
当被监听的套接字准备好执行链接应答、读取、写入、关闭等操作时,
与操作相对性的文件事件就会产生。
定时事件:指定时间执行一次程序
周期事件:隔一定时间执行一次程序
id -- 服务器为时间事件创建的全局唯一ID,递增
when -- 毫秒,记录事件的触发时间
timeProc -- 时间事件处理器
客户端
struct redisServer { /* General */ pid_t pid; /* Main process pid. */ char *configfile; /* Absolute config file path, or NULL */ int hz; /* serverCron() calls frequency in hertz */ redisDb *db; dict *commands; /* Command table */ dict *orig_commands; /* Command table before command renaming. */ aeEventLoop *el; unsigned lruclock:REDIS_LRU_BITS; /* Clock for LRU eviction */ int shutdown_asap; /* SHUTDOWN needed ASAP */ int activerehashing; /* Incremental rehash in serverCron() */ char *requirepass; /* Pass for AUTH command, or NULL */ char *pidfile; /* PID file path */ int arch_bits; /* 32 or 64 depending on sizeof(PORT_LONG) */ int cronloops; /* Number of times the cron function run */ char runid[REDIS_RUN_ID_SIZE+1]; /* ID always different at every exec. */ int sentinel_mode; /* True if this instance is a Sentinel. */ /* Networking */ int port; /* TCP listening port */ int tcp_backlog; /* TCP listen() backlog */ char *bindaddr[REDIS_BINDADDR_MAX]; /* Addresses we should bind to */ int bindaddr_count; /* Number of addresses in server.bindaddr[] */ char *unixsocket; /* UNIX socket path */ mode_t unixsocketperm; /* UNIX socket permission */ int ipfd[REDIS_BINDADDR_MAX]; /* TCP socket file descriptors */ int ipfd_count; /* Used slots in ipfd[] */ int sofd; /* Unix socket file descriptor */ int cfd[REDIS_BINDADDR_MAX];/* Cluster bus listening socket */ int cfd_count; /* Used slots in cfd[] */ list *clients; /* List of active clients */ list *clients_to_close; /* Clients to close asynchronously */ list *slaves, *monitors; /* List of slaves and MONITORs */ redisClient *current_client; /* Current client, only used on crash report */ int clients_paused;
一、输入缓冲区
客户端状态的输入缓冲区(sds querybuf)用于保存客户端发送的命令请求
命令:robj **argv 命令参数
int argc 命令参数个数
从服务器协议中分析参数和个数,根据argv[0]查找对应的命令函数
二、输出缓冲区
执行命令后的回复被保存再客户端状态的输出缓冲区里面。
--固定缓冲区,长度较小的回复
--可变缓冲区,长度较大的回复
三、身份验证
int authenticated
==0 未验证 ; ==1 客户端通过了验证
四、时间
timt_t ctime --创建客户端的时间,可计算连接时长(秒)
timt_t lastinteraction --客户端和服务器最后一次通信时间,可用来计算客户端空转时间
time_t obuf_soft_limit_reached_time --输出缓冲区第一次到达软性限制的时间
五、客户端的创建与关闭
服务器使用不同的方式来创建和关闭不同类型的客户端
5.1 创建普通客户端
5.2 关闭普通客户端
--客户端进程退出或者杀死
--客户端向服务器发送不符合协议格式的命令请求
--客户端设置了timeout 配置选项
--客户端发送的命令请求大小超过了输出缓冲区限制大小,默认1G (硬性限制和软性限制)
5.3 Lua脚本的伪客户端
服务器初始化创建负责执行Lua脚本中包含redis命令的伪客户端
5.4 AOF 文件的伪客户端
服务器再载入AOF文件时,创建用于执行AOF文件包含的redis命令的伪客户端,并在载入完成后关闭。
六、服务器
6.1 命令请求的执行过程
客户端发送命令 set key value 收到回复 ok
1、客户端发送 set key value
2、服务端接收处理客户端的命令请求,产生回复ok
3、将命令回复给客户端
4、客户端接收回复,打印展示
6.2 发送命令请求
用户-> 请求-> 客户端-> 协议转换-> 服务器
6.3读取命令请求
读取命令->保存到客户状态的缓冲区->分析命令->调用命令执行器
6.4 将命令回复发给客户端
6.5客户端接收并打印命令回复
服务器->客户端->用户
七、serverCron函数
serverCron 默认100毫秒执行一次,管理服务器资源。
7.1、更新服务器时间缓存
因为获取系统当前时间操作比较频繁,所以缓存系统时间。
所以缓存当前时间:
unixtime //秒级
mstime //毫秒
7.2、更新LRU时钟
lruclock 服务器的LRU时钟
7.3、更新服务器每秒执行命令次数
trackOperationsPerSecond //估算服务器再最近一秒钟的处理请求数量
7.4、更新服务器内存峰值记录
程序会查看当前使用的内存的数量
7.5、处理sigterm信号
7.6、管理客户端资源
超时--释放资源
超出输入缓冲区长度--释放资源
7.7、管理服务器资源
删除过期键,收缩字典
7.8、执行延迟的bgrewriteaof
执行延迟的重写aof操作
7.9、检查持久化操作的运行状态
rdb_child_pid -- bgsave命令子进程id
aof_child_pid --bgrewriteaof命令子进程id
可以检查是否有正在执行以上命令。
7.10 AOF缓冲区的内容写入AOF文件
启动持久化,会将缓冲区内容写入到aof文件
7.11 关闭异步客户端
7.12 增加 cronloops 计数器值
cronloops --记录serverCron函数执行次数
八、初始化服务器
redis 服务器启动到接受客户端命令,需要一系列初始化和设置过程。
8.1 初始化服务器状态结构
创建一个 redisServer结构,并赋值默认值initServerConfig函数。
struct redisServer
void initServerConfig(void) { int j; getRandomHexChars(server.runid,REDIS_RUN_ID_SIZE); server.configfile = NULL; server.hz = REDIS_DEFAULT_HZ; server.runid[REDIS_RUN_ID_SIZE] = '