Redis Server 相关源码阅读笔记,源码文件 server.h
& server.c
。
从 Redis 的 main 函数中,可以发现在 Redis 启动时主要做了以下几个工作:
- 加载配置:先调用 initServerConfig 使用默认配置,再调用 loadServerConfig 使用配置文件中的配置项覆盖默认配置
- 调用 initServer 和 InitServerLast 初始化服务器
- 调用 loadDataFromDisk 加载先前可能存在的数据集
- 调用 aeMain 启动 event loop
initServer
- 设置信号处理函数:setupSignalHandlers
- 初始化
server
结构体中相应 fields - 初始化共享的 Redis 数据对象列表
shared
: createSharedObjects - 根据 open file limit 设置真实的最大客户端连接数
server.maxclients
:adjustOpenFilesLimit - 初始化服务器的 event loop
server.el
:aeCreateEventLoop - 初始化
server.db
- 监听配置的地址,接收来自用户的请求
- TCP port: listenToPort
- TCP port with TLS: listenToPort
- Unix domain socket: anetUnixServer
- 初始化 eviction pool:evictionPoolAlloc
- 重置 AOF rewrite buffer: aofRewriteBufferReset
- 重置服务器状态:resetServerStats
- 添加事件至服务器 event loop:
- 添加 time event serverCron 至服务器 event loop
server.el
- 添加 file event (acceptTcpHandler or acceptTLSHandler or acceptUnixHandler) 处理客户端连接及请求
- Register a readable event for the pipe used to awake the event loop when a blocked client in a module needs attention.
- Register before (beforeSleep) and after (afterSleep) sleep handlers (note this needs to be done before loading persistence since it is used by processEventsWhileBlocked)
- 添加 time event serverCron 至服务器 event loop
- Open the AOF file if needed.
- 如为 cluster 模式,则调用 clusterInit 进行相应的初始化操作
- Initialize the script cache: replicationScriptCacheInit
- Initialize the scripting environment: scriptingInit
- Initialize the slow log: slowlogInit
- Latency monitor initialization: latencyMonitorInit
event
有关 File event acceptTcpHandler
(acceptTLSHandler
/acceptUnixHandler
) 的内容会在客户端相关笔记中介绍,本次仅介绍 Time event serverCron
和 beforeSleep
。
serverCron
Redis 在初始化时,会添加一个 time event serverCron
至 event loop,其运行频率为 server.hz
。如果配置项 dynamic_hz 设置为 yes
,则该频率会随着当前客户端连接数的增加而增加,上限为 CONFIG_MAX_HZ
(500)。不过该函数内实际工作的运行频率由 run_with_period(milliseconds){...}
中的 milliseconds
和 server.hz
共同确定。
在该定期执行的任务中,主要做了以下工作:
- 更新服务器状态,可通过
INFO
命令查看这些状态 - 如收到
SIGTERM
则会调用 prepareForShutdown 后关闭服务器 - 执行客户端相关定期任务:clientsCron
- 执行数据库相关定期任务:databasesCron
- 当前子进程无任务且有 AOF rewrite 需求时,调用 rewriteAppendOnlyFileBackground 在后台执行 AOF rewrite
- 检查后台 RDB saving 或 AOF rewrite 进程是否已结束
- 当前子进程无任务时:
- 根据 save 相关配置项决定是否要调用 rdbSaveBackground 保存当前数据集状态
- 根据配置项 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 决定是否要调用 rewriteAppendOnlyFileBackground 开始 AOF rewrite 以减少 AOF 文件磁盘空间占用
- 如此前有推迟的 AOF 落盘任务或 AOF 写入发生错误,则调用
flushAppendOnlyFile
- Clear the paused clients flag if needed: clientsArePaused
- 执行主从同步相关定期任务:replicationCron
- 执行集群相关定期任务:clusterCron
- Run the Sentinel timer if we are in sentinel mode: sentinelTimer
- Cleanup expired MIGRATE cached sockets: migrateCloseTimedoutSockets
- Stop the I/O threads if we don’t have enough pending work: stopThreadedIOIfNeeded
- Resize tracking keys table if needed: trackingLimitUsedSlots
- 当前子进程无任务且有 BGSAVE 需求时,调用 rdbSaveBackground 在后台执行 BGSAVE
- Fire the cron loop modules event: moduleFireServerEvent
clientsCron
TODO
databasesCron
在此定期执行的任务中,主要做了以下工作:
- 清理过期 key: activeExpireCycle
- 碎片整理: activeDefragCycle
- 当前子进程无任务时:
- Resize:若当前 keyspace
redisDb->dict
中 slot 数量大于DICT_HT_INITIAL_SIZE
(4),且哈希表元素个数低于 slot 数量的 $10\%$,则调整 slot 数量 (redisDb->expires
同理) - 渐进式 Rehash:若配置项 activerehashing 为
yes
,且当前数据库正在进行 Rehash,则尝试进行时长为 $1ms$ 的 Rehash 操作
- Resize:若当前 keyspace
replicationCron
TODO
clusterCron
TODO
beforeSleep
TODO