Redis 源码剖析与实战
蒋德钧
中科院计算所副研究员
17049 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 47 讲
Redis 源码剖析与实战
15
15
1.0x
00:00/00:00
登录|注册

08 | Redis server启动后会做哪些操作?

你好,我是蒋德钧。从这节课开始,我们就来到了课程的第二个模块,在这个模块里,我会带你了解和学习与 Redis 实例运行相关方面的知识,包括 Redis server 的启动过程、基于事件驱动框架的网络通信机制以及 Redis 线程执行模型。今天,我们先来学习下 Redis server 的启动过程。
我们知道,main 函数是 Redis 整个运行程序的入口,并且 Redis 实例在运行时,也会从这个 main 函数开始执行。同时,由于 Redis 是典型的 Client-Server 架构,一旦 Redis 实例开始运行,Redis server 也就会启动,而 main 函数其实也会负责 Redis server 的启动运行。
我在第 1 讲给你介绍过 Redis 源码的整体架构。其中,Redis 运行的基本控制逻辑是在server.c文件中完成的,而 main 函数就是在 server.c 中。
你平常在设计或实现一个网络服务器程序时,可能会遇到一个问题,那就是服务器启动时,应该做哪些操作、有没有一个典型的参考实现。所以今天这节课,我就从 main 函数开始,给你介绍下 Redis server 是如何在 main 函数中启动并完成初始化的。通过这节课内容的学习,你可以掌握 Redis 针对以下三个问题的实现思路:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Redis 源码剖析与实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(12)

  • 最新
  • 精选
  • Kaito
    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
    31
  • 曾轼麟
    感谢老师的文章,先回答老师提出的问题:文章中代码片段的作用是?根据关键词我找到代码位于,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
  • 木几丶
    简易版启动流程: 初始化默认配置->解析启动参数和配置文件覆盖默认配置->初始化server->启动事件驱动框架
    2
  • 零点999
    server.supervised = redisIsSupervised(server.supervised_mode);int background = server.daemonize && !server.supervised;if (background) daemonize();...} Redis 可以配置以守护进程的方式启动(配置文件 daemonize = yes)
    归属地:北京
  • 零点999
    mac环境下使用clion软件debug redis源码的配置过程: https://www.toutiao.com/article/7214017532637004346/?log_from=bc6912dd0e87f_1679699758013
    归属地:英国
  • 瞭望站在风口的猪
    老师好,我发现有一处逻辑错了,是先检查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
    在这一讲中大部分逻辑都是在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
    在这一讲中大部分逻辑都是在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
    老师的这些图是用什么软件画的啊
    1
  • 末日,成欢
    起始处设置随机种子是为了做什么?
    3
收起评论
显示
设置
留言
12
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部