前言

main 函数是 Redis 整个运行程序的入口。源码主要在 server.c 文件中。

前面 6 篇文章分析了 Redis 的基础数据结构。

问题

  • Redis server 启动后具体会做哪些初始化操作?
  • Redis server 初始化时有哪些关键配置项?
  • Redis server 如何开始处理客户端请求?

阶段 1:基本初始化

基本的初始化工作,包括设置 server 运行的时区等。

//设置时区
setlocale(LC_COLLATE,"");
tzset();
...
//设置随机种子
char hashseed[16];
getRandomHexChars(hashseed,sizeof(hashseed));
dictSetHashFunctionSeed((uint8_t*)hashseed);

阶段 2:检查哨兵模式,执行 RDB 或 AOF 检测

Redis Server 可能以哨兵模式运行。哨兵模式需要额外的参数配置及初始化。

// 判断 server 是否为「哨兵模式」
if (server.sentinel_mode) {
// 初始化哨兵配置
initSentinelConfig();
// 初始化哨兵模式
initSentinel();
}

此外还会检查是否要执行 RDB 检测或 AOF 检查,这对应了实际运行的程序是 redis-check-rdb 或 redis-check-aof。

// 运行的是 redis-check-rdb
if (strstr(argv[0],"redis-check-rdb") != NULL)
// 检测 RDB 文件
redis_check_rdb_main(argc,argv,NULL);
// 运行的是 redis-check-aof
else if (strstr(argv[0],"redis-check-aof") != NULL)
// 检测 AOF 文件
redis_check_aof_main(argc,argv);

阶段 3:运行参数解析

main 函数会对命令行传入的参数进行解析,并且调用 loadServerConfig 函数,对命令行参数和配置文件中的参数进行合并处理,然后为 Redis 各功能模块的关键参数设置合适的取值。

int main(int argc, char **argv) {

//保存命令行参数
for (j = 0; j < argc; j++) server.exec_argv[j] = zstrdup(argv[j]);

if (argc >= 2) {

//对每个运行时参数进行解析
while(j != argc) {

}

loadServerConfig(configfile,options);
}

loadServerConfig 函数是在 config.c 文件中实现的,该函数是以 Redis 配置文件和命令行参数的解析字符串为参数,将配置文件中的所有配置项读取出来,形成字符串。

阶段 4:初始化 server

调用 initServer 函数,对 server 运行时的各种资源进行初始化工作。这主要包括:

  • server 资源管理所需的数据结构初始化
  • 键值对数据库初始化
  • server 网络框架初始化

接着会再次判断是否为「哨兵模式」:

  • 是哨兵模式,调用 sentinelIsRunning 函数,设置启动哨兵模式
  • 不是哨兵模式,调用 loadDataFromDisk 函数,从磁盘加载 AOF 或 RDB 文件,恢复之前的数据
// 初始化 server
initServer();
…… if (!server.sentinel_mode) {
……
InitServerLast();
// 从磁盘加载数据
loadDataFromDisk();
……
} else {
……
sentinelIsRunning();
……
}

资源管理

和 server 连接的客户端、从库等,Redis 用作缓存时的替换候选集,以及 server 运行时的状态信息,这些资源的管理信息都会在 initServer 函数中进行初始化。

初始化数据库

因为一个 Redis 实例可以同时运行多个数据库,所以 initServer 函数会使用一个循环,依次为每个数据库创建相应的数据结构。

for (j = 0; j < server.dbnum; j++) {
// 创建全局哈希表
server.db[j].dict = dictCreate(&dbDictType,NULL);
// 创建过期 key 的信息表
server.db[j].expires = dictCreate(&dbExpiresDictType,NULL);
server.db[j].expires_cursor = 0;
// 为被 BLPOP 阻塞的 key 创建信息表
server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);
// 为将执行 PUSH 的阻塞 key 创建信息表
server.db[j].ready_keys = dictCreate(&objectKeyPointerValueDictType,NULL);
// 为被 MULTI/WATCH 操作监听的 key 创建信息表
server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
……
}

创建事件驱动框架

针对每个监听 IP 上可能发生的客户端连接,都创建了监听事件,用来监听客户端连接请求。同时,initServer 为监听事件设置了相应的处理函数 acceptTcpHandler。

这样一来,只要有客户端连接到 server 监听的 IP 和端口,事件驱动框架就会检测到有连接事件发生,然后调用 acceptTcpHandler 函数来处理具体的连接。

//创建事件循环框架
server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);

//开始监听设置的网络端口
if (server.port != 0 &&
listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR)
exit(1);

//为 server 后台任务创建定时事件
if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
serverPanic("Can't create event loop timers.");
exit(1);
}

阶段 5:执行事件驱动框架

高效处理高并发的客户端连接请求,Redis 采用了事件驱动框架,来并发处理不同客户端的连接和读写请求。main 函数最后会调用 aeMain 函数进入事件驱动框架,循环处理各种触发的事件。

// 事件驱动框架,循环处理各种触发的事件
aeMain(server.el);
// 循环结束,删除 eventLoop
aeDeleteEventLoop(server.el);

aeMain 函数核心调用了 aeProcessEvents 函数。aeProcessEvents 函数的具体源码将在之后的文章中分析。

void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
// 循环调用
while (!eventLoop->stop) {
// 核心函数,处理事件的逻辑
aeProcessEvents(eventLoop, AE_ALL_EVENTS|
AE_CALL_BEFORE_SLEEP|
AE_CALL_AFTER_SLEEP);
}
}

参考链接

Redis 源码简洁剖析系列

最简洁的 Redis 源码剖析系列文章

Java 编程思想-最全思维导图-GitHub 下载链接,需要的小伙伴可以自取~

原创不易,希望大家转载时请先联系我,并标注原文链接。

Redis 源码简洁剖析 07 - main 函数启动的更多相关文章

  1. Redis 源码简洁剖析 09 - Reactor 模型

    Reactor 模型 事件驱动框架 Redis 如何实现 Reactor 模型 事件的数据结构:aeFileEvent 主循环:aeMain 函数 事件捕获与分发:aeProcessEvents 函数 ...

  2. Redis 源码简洁剖析 02 - SDS 字符串

    C 语言的字符串函数 C 语言 string 函数,在 C 语言中可以使用 char* 字符数组实现字符串,C 语言标准库 string.h 中也定义了多种字符串操作函数. 字符串使用广泛,需要满足: ...

  3. Redis 源码简洁剖析 11 - 主 IO 线程及 Redis 6.0 多 IO 线程

    Redis 到底是不是单线程的程序? 多 IO 线程的初始化 IO 线程运行函数 IOThreadMain 如何推迟客户端「读」操作? 如何推迟客户端「写」操作? 如何把待「读」客户端分配给 IO 线 ...

  4. Redis 源码简洁剖析 03 - Dict Hash 基础

    Redis Hash 源码 Redis Hash 数据结构 Redis rehash 原理 为什么要 rehash? Redis dict 数据结构 Redis rehash 过程 什么时候触发 re ...

  5. Redis 源码简洁剖析 04 - Sorted Set 有序集合

    Sorted Set 是什么 Sorted Set 命令及实现方法 Sorted Set 数据结构 跳表(skiplist) 跳表节点的结构定义 跳表的定义 跳表节点查询 层数设置 跳表插入节点 zs ...

  6. Redis 源码简洁剖析 06 - quicklist 和 listpack

    quicklist 为什么要设计 quicklist 特点 数据结构 quicklistCreate quicklistDelIndex quicklistDelEntry quicklistInse ...

  7. Redis 源码简洁剖析 10 - aeEventLoop 及事件

    aeEventLoop IO 事件处理 IO 事件创建 读事件处理 写事件处理 时间事件处理 时间事件定义 时间事件创建 时间事件回调函数 时间事件的触发处理 参考链接 Redis 源码简洁剖析系列 ...

  8. Redis 源码简洁剖析 12 - 一条命令的处理过程

    命令的处理过程 Redis server 和一个客户端建立连接后,会在事件驱动框架中注册可读事件--客户端的命令请求.命令处理对应 4 个阶段: 命令读取:对应 readQueryFromClient ...

  9. Redis 源码简洁剖析 13 - RDB 文件

    RDB 是什么 RDB 文件格式 Header Body DB Selector AUX Fields Key-Value Footer 编码算法说明 Length 编码 String 编码 Scor ...

随机推荐

  1. vue create 初步解析以及定制化修改

    版本说明 $ vue --version @vue/cli 4.5.9 $ node --version v14.0.0 $ npm --version 7.6.1 源码位置-mac /usr/loc ...

  2. Chapter 10 Random Variability

    目录 10.1 Identification versus estimation 10.2 Estimation of causal effects 10.3 The myth of the supe ...

  3. <数据结构>图的最短路径问题

    目录 最短路径问题 Dijstra算法:中介点优化 基本步骤 伪代码 在实现过程中的关键问题 代码实现 邻接矩阵版 邻接表版 时间复杂度:O(VlogV+E) 算法存在的问题:存在负权边时会失效 Be ...

  4. 「艺蜂酒店管理系统」 · Java Swing + mysql 开发 学生毕业设计项目

    Java  Swing在社会上基本用不到,但是任有学校拿来当做结课设计,只是博主在校期间的一个项目.如果在部署过程中有问题可以加我qq68872185. 码云仓库地址:https://gitee.co ...

  5. Swoole 中使用 PDO 连接池、Redis 连接池、Mysqli 连接池

    连接池使用说明 所有连接池的实现均基于 ConnectionPool 原始连接池: 连接池的底层原理是基于 Channel 的自动调度: 开发者需要自己保证归还的连接是可重用的: 若连接不可重用,需要 ...

  6. js 图片跟随鼠标移动效果 案例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. oracle 之 while循环月份

    需求 需要跑一个数据,时间从17年5月到21年3月. 代码(简单粗暴实现) DECLARE i number; BEGIN i:= 201705; WHILE i <202104 LOOP if ...

  8. 使用springboot devtools工具实现热部署

    一.在maven父工程pom文件中添加依赖 二.在子工程中添加依赖 三.在IDEA中勾选 Build project automatically项 四. Shift+Ctrl+Alt+/,选择Regi ...

  9. Java读写XML代码示例

    采用技术:dom4j 需要jar包:dom4j-1.6.1.jar 主类如下---- public class dom4jTestXML { /**  *   * 方法描述:读取XML文件示例 备 注 ...

  10. Spark本地环境实现wordCount单词计数

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6814778610788860424/ 编写类似MapReduce的案例-单词统计WordCount 要统计的文件为 ...