- redisClient 中有输入输出缓冲区
- 输入缓冲区:命令处理器将用户输入的命令写入客户端输入缓冲区,该缓冲区可动态扩展,但最大不能超过 1G,否则服务器将关闭客户端;
- 输出缓冲区:命令执行器将命令执行生成的回复写入输出缓冲区,并关联回复响应处理器,待客户端产生可写事件时,回复响应处理器将输出缓冲区的内容发送给客户端,并清空输出缓冲区;
- 输入缓冲区的内容被解析后,生成命令、参数等信息,存入redisClient中的argv数组,并记录数组长度,以待后续命令检查及执行;
- serverCron(时间事件,默认每隔100ms执行一次):
- 更新服务器时间:unixtime/mstime(s/ms),默认100ms;
- 更新lru_time:默认10s;
- 更新服务器每秒执行命令数(大概值,取1ms次数乘以1000为一次样本,默认取16次样本平均值);
- 处理sigterm信号(不带参数的kill):redisServer.asap状态,serverCron每次执行,都将检测该标识,为1时,将关闭服务器,且关闭前将进行持久化操作;
- 管理客户端资源:每次serverCron都执行,释放过期客户端及清理客户端输入缓冲区;
- 管理数据库资源:每次都调用databaseCron,随机处理一部分数据的过期键,并在需要时,对字典(键空间)进行收宿操作;
- bgrewriteaof:redisServer.aof_rewrite_scheduled,BGSAVE期间,若收到bgrewriteaof命令,将修改此标识,延时到serverCron执行期间执行此命令;
- 检查子进程持久化操作的运行状态,以判断是否需要执行后续操作(替换rdb文件或者重写的aof文件等等),若无持久化状态,则检查是否满足持久化条件,进行持久化,或者aof重写;
- 将aof缓冲区中的内容写入aof文件(开启aof且缓冲区有数据),并按配置判断是否需要调用同步指令;
- 关闭异步客户端(输出缓冲区大小超过限制);
- 增加cronLoops计数值,该计数记录了serverCron执行次数(目前该计数唯一作用:在复制模块中实现,serverCron函数每执行N次,就执行一次指定代码);
- 服务器初始化
- 创建redisServer实例变量server;
- 调用initServerConfig,设置server默认值,并创建命令表;
- 载入配置项,并使用配置的值替换server中的默认值;
- 调用initServer函数,为创建相关数据结构分配内存,并按需设置或关联初始化值等,并进行一些设置:
- 数据结构:
- server.cliens 链表
- server.db 数组
- server.pubsub_channels 字典,用于保存频道订阅信息;
- server.pubsub_patterns 链表,保存模式订阅信息;
- server.lua 用于执行lua脚本的lua环境;
- server.slowlog 用于保存慢查询日志;
- 设置:
- 为服务器设置进程信号处理器;
- 创建共享对象(如服务器常用的"OK"等字符串常量,其中有表示整数1-10000的字符串对象);
- 打开服务器的监听端口,并为监听套接字关联【连接应答处理器】;
- 为serverCro函数件创建时间事件;
- 若AOF持久化功能打开,打开现有的AOF文件,若不存在,创建一个新的,为AOF写入做准备;
- 初始化服务器上后台IO(BIO)模块,
- initServer执行完后,打印redis图标及支行模式、服务器版本、端口号、PID等信息;
- 数据结构:
- 还原数据库状态:载入RDB或AOF文件(若启用AOF,就用AOF,否则用RDB),还原数据;
- 日志:载入文件并还原数据所耗时长;
- 执行事件循环;
- 日志:xxx The server is now ready to accept connections on port 6379;
- 简单描述初始化过程:
- 初始化服务器状态;
- 载入服务器配置;
- 初始化服务器数据结构;
- 还原数据库状态;
- 执行事件循环;
- 事件轮询:
- 获取到达时间最近的时间事件,假设是t事件;
- 获取t事件到达时间,若已到达(负数),置为0,做为获取文件事件的等待时间,设该时间为n;
- 以n为等待时间获取文件事件(有事件立即返回,无事件等待,直到有事件或超时);
- 若获取到文件事件,执行;
- 检查并执行所有已到达的时间事件(单机只有serverCron?)
- 重复这个过程;
- redis应用:
- main:初始化,然后调用aeMain;
- aeMain:死循环,调用aeProcessEvents
- aeProcessEvents:处理文件事件及时间事件(过程见上述:事件轮询);
一些结构:
redisServer
redisClient
redisDb
redisObject
redisCommand
执行命令时,如果客户端正在订阅频道或模式,那么服务器将只接受发布订阅相关的命令,其它命令会被拒绝; 因此,哨兵既要订阅消息,又要发出命令,需要建立两个 连接 到服务器;