• Kaito
    2021-08-12
    Redis 启动流程,主要的工作有: 1、初始化前置操作(设置时区、随机种子) 2、初始化 Server 的各种默认配置(server.c 的 initServerConfig 函数),默认配置见 server.h 中的 CONFIG_DEFAULT_XXX,比较典型的配置有: - 默认端口 - 定时任务频率 - 数据库数量 - AOF 刷盘策略 - 淘汰策略 - 数据结构转换阈值 - 主从复制参数 3、加载配置启动参数,覆盖默认配置(config.c 的 loadServerConfig 函数): - 解析命令行参数 - 解析配置文件 3、初始化 Server(server.c 的 initServer 函数),例如会初始化: - 共享对象池 - 客户端链表 - 从库链表 - 监听端口 - 全局哈希表 - LRU 池 - 注册定时任务函数 - 注册监听请求函数 4、启动事件循环(ae.c 的 aeMain 函数) - 处理请求 - 处理定时任务 这里补充一下,初始化 Server 完成后,Redis 还会启动 3 类后台线程(server.c 的 InitServerLast 函数),协助主线程工作(异步释放 fd、AOF 每秒刷盘、lazyfree)。 课后题:Redis 源码的 main 函数在调用 initServer 函数之前,会执行如下的代码片段,你知道这个代码片段的作用是什么吗? int main(int argc, char **argv) { ... server.supervised = redisIsSupervised(server.supervised_mode); int background = server.daemonize && !server.supervised; if (background) daemonize(); ... } Redis 可以配置以守护进程的方式启动(配置文件 daemonize = yes),也可以把 Redis 托管给 upstart 或 systemd 来启动 / 停止(supervised = upstart|systemd|auto)。
    展开
    共 6 条评论
    30
  • 曾轼麟
    2021-08-13
    感谢老师的文章,先回答老师提出的问题:文章中代码片段的作用是?根据关键词我找到代码位于,main函数中loadServerConfig之后执行的,那么这块代码主要任务和顺序如下所示: 1、此时redis的config是已经初始化完成的 2、执行redisIsSupervised其目底主要是判断当redis进程是否运行中 3、判断daemonize是否开启(如果启动设置了daemonize参数那么这里参数已经被填充) 4、之前并没有存活的redis实例,并且开启了daemonize配置,那么执行daemonize函数挂起后台运行 这里需要解释一下,执行daemonize()函数的时候本质是fork()进程,并不是大多文章说的那样是守护线程,父亲fork成功后是直接退出(在前端的效果就是,启动命令任务完成但是ps是有一个redis的进程),剩余的任务是交给fork出的子进程完成的(可以参考《深入理解操作系统》 第8章-异常控制流-进程中的内容) 读完这篇文章后,我个人尝试画出整个redis启动的时序图,发现整个思路就很清晰了,建议同样阅读文章的同学可以尝试画一下,我总结一下我读完文章后的理解: 1、redis的整体启动流程是按照 【初始化默认配置】->【解析启动命令】->【初始化server】->【初始化并启动事件驱动框架】 进行 2、整个运行中的redis,其实就是一个永不停歇的while循环,位于aeMain中(运行中的事件驱动框架) 3、在事件驱动框架中有两个钩子函数 beforeSleep 和 aftersleep,在每次while循环中都会触发这两个函数,后面用来实现事件触发的效果 此外我发现了一个细节点:我在近期版本的redis6的分支上,发现在启动事件驱动框架之前(执行aeMain之前)会执行一个redisSetCpuAffinity函数,其效果有点类似于绑核的效果,那么是否可以认为从redis6开始其实不需要运维帮忙绑核redis自身就能做到绑核的效果呢?
    展开
    共 2 条评论
    10
  • 木几丶
    2021-08-29
    简易版启动流程: 初始化默认配置->解析启动参数和配置文件覆盖默认配置->初始化server->启动事件驱动框架
    
    2
  • 零点999
    2023-03-25 来自北京
    server.supervised = redisIsSupervised(server.supervised_mode);int background = server.daemonize && !server.supervised;if (background) daemonize();...} Redis 可以配置以守护进程的方式启动(配置文件 daemonize = yes)
    
    
  • 零点999
    2023-03-25 来自英国
    mac环境下使用clion软件debug redis源码的配置过程: https://www.toutiao.com/article/7214017532637004346/?log_from=bc6912dd0e87f_1679699758013
    
    
  • 瞭望站在风口的猪
    2022-09-27 来自北京
    老师好,我发现有一处逻辑错了,是先检查RBD再检查AOF吧 if (strstr(argv[0],"redis-check-rdb") != NULL) redis_check_rdb_main(argc,argv,NULL); else if (strstr(argv[0],"redis-check-aof") != NULL) redis_check_aof_main(argc,argv);
    
    
  • lzh2nix
    2021-08-23
    在这一讲中大部分逻辑都是在initSerer中完成,所以对initSerer函数的理解也是重中之重。 initSerer(void initServer(void)) \ 1. server 结构体的初始化 2. sharedObject 创建(createSharedObjects()) 3. 创建事件驱动框架(aeCreateEventLoop()) 4. 监听tcp端口(listenToPort()) 5. 监听unix socket(anetUixServer()) 6. redis DB 初始化 7. 系统状态设置(staat/cron/aof/rdb 等状态) 8. 将timer事件添加到eventLoop中(aeCreateTimeEvent(...serverCron)) 9. 接受tcp连接事件添加到eventLoop中(aeCreateFileEvent(...acceptTcpEVent)) 10. 接受到unix socket连接的事件添加到eventLoop中(aeCreateFileEvent(acceptUnixHandler)) 11. server中cluster 相关配置的初始化 12. replicationScriptCacheInit()/scriptingInit()/scriptingInit()/latencyMonitorInit()
    展开
    
    
  • lzh2nix
    2021-08-23
    在这一讲中大部分逻辑都是在initSerer中完成,所以对initSerer函数的理解也是重中之重。 initSerer(void initServer(void)) \ 1. server 结构体的初始化 2. sharedObject 创建(createSharedObjects()) 3. 创建事件驱动框架(aeCreateEventLoop()) 4. 监听tcp端口(listenToPort()) 5. 监听unix socket(anetUixServer()) 6. redis DB 初始化 7. 系统状态设置(staat/cron/aof/rdb 等状态) 8. 将timer事件添加到eventLoop中(aeCreateTimeEvent(...serverCron)) 9. 接受tcp连接事件添加到eventLoop中(aeCreateFileEvent(...acceptTcpEVent)) 10. 接受到unix socket连接的事件添加到eventLoop中(aeCreateFileEvent(acceptUnixHandler)) 11. server中cluster 相关配置的初始化 12. replicationScriptCacheInit()/scriptingInit()/scriptingInit()/latencyMonitorInit()
    展开
    
    
  • haha
    2021-08-21
    老师的这些图是用什么软件画的啊
    共 1 条评论
    
  • 末日,成欢
    2021-08-12
    起始处设置随机种子是为了做什么?
    共 3 条评论
    