Redis源码剖析与实战
蒋德钧
中科院计算所副研究员
新⼈⾸单¥59.9
2382 人已学习
课程目录
已更新 13 讲 / 共 33 讲
0/4登录后,你可以任选4讲全文学习。
课前导读 (2讲)
开篇词 | 阅读Redis源码能给你带来什么?
免费
01 | 带你快速攻略Redis源码的整体架构
数据结构模块 (6讲)
02 | 键值对中字符串的实现,用char*还是结构体?
03 | 如何实现一个性能优异的Hash表?
04 | 内存友好的数据结构该如何细化设计?
05 | 有序集合为何能同时支持点查询和范围查询?
06 | 从ziplist到quicklist,再到listpack的启发
07 | 为什么Stream使用了Radix Tree?
事件驱动框架和执行模型模块 (5讲)
08 | Redis server启动后会做哪些操作?
09 | Redis事件驱动框架(上):何时使用select、poll、epoll?
10 | Redis事件驱动框架(中):Redis实现了Reactor模型吗?
11 | Redis事件驱动框架(下):Redis有哪些事件?
12 | Redis真的是单线程吗?
Redis源码剖析与实战
15
15
1.0x
00:00/00:00
登录|注册

12 | Redis真的是单线程吗?

你好,我是蒋德钧。今天这节课,我们来聊聊 Redis 的执行模型。
所谓的执行模型,就是指 Redis 运行时使用的进程、子进程和线程的个数,以及它们各自负责的工作任务。
你在实际使用 Redis 的时候,可能经常会听到类似“Redis 是单线程”“Redis 的主 IO 线程”,“Redis 包含多线程”等不同说法。我也听到不少同学提出困惑和疑问:Redis 到底是不是一个单线程的程序?
其实,彻底理解这个问题,有助于指导我们保持 Redis 高性能、低延迟的特性。如果说 Redis 就是单线程程序,那么,我们就需要避免所有容易引起线程阻塞的操作;而如果说 Redis 不只是单线程,还有其他线程在工作,那么,我们就需要了解多线程各自负责什么任务,负责请求解析和数据读写的线程有几个,有哪些操作是后台线程在完成,而不会影响请求解析和数据读写的。
所以,今天这节课,我就从 Redis server 启动后运行的进程开始,带你一边学习 Redis 源码中子进程和线程的创建方式,一边掌握 Redis server 运行时涉及到的进程、子进程和线程情况。
下面,我们先来看 Redis server 启动时的进程运行。

从 shell 命令执行到 Redis 进程创建

我们在启动 Redis 实例时,可以在 shell 命令行环境中,执行 redis-server 这个可执行文件,如下所示:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/1000字
划线
笔记
复制
该试读文章来自付费专栏《Redis源码剖析与实战》,如需阅读全部文章,
请订阅文章所属专栏新⼈⾸单¥59.9
立即订阅
登录 后留言

精选留言(5)

  • Darren
    今天这节课收获满满,以前看源码的时候,没注意过daemonize()方法,因为不是做C语言的,因此只是想着后台启动,没想到原始是这么启动起来的。

    回答下问题,其实这个问题Redis的作者在源码中已经注释了
    struct bio_job {
        time_t time; /* Time at which the job was created. */
        /* Job specific arguments pointers. If we need to pass more than three
         * arguments we can just pass a pointer to a structure or alike. */
        void *arg1, *arg2, *arg3;
    };
    void*代表任意类型的指针,因此当参数多于三个时,可以传递数组或者结构。
    2021-08-21
    3
  • Kaito
    1、很多人认为 Redis 是单线程,这个描述是不准确的。准确来说 Redis 只有在处理「客户端请求」时,是单线程的。但整个 Redis Server 并不是单线程的,还有后台线程在辅助处理一些工作

    2、Redis 选择单线程处理请求,是因为 Redis 操作的是「内存」,加上设计了「高效」的数据结构,所以操作速度极快,利用 IO 多路复用机制,单线程依旧可以有非常高的性能

    3、但如果一个请求发生耗时,单线程的缺点就暴露出来了,后面的请求都要「排队」等待,所以 Redis 在启动时会启动一些「后台线程」来辅助工作,目的是把耗时的操作,放到后台处理,避免主线程操作耗时影响整体性能

    4、例如关闭 fd、AOF 刷盘、释放 key 的内存,这些耗时操作,都可以放到后台线程中处理,对主逻辑没有任何影响

    5、后台线程处理这些任务,就相当于一个消费者,生产者(主线程)把耗时任务丢到队列中(链表),消费者不停轮询这个队列,拿出任务就去执行对应的方法即可:

    - BIO_CLOSE_FILE:close(fd)
    - BIO_AOF_FSYNC:fsync(fd)
    - BIO_LAZY_FREE:free(obj) / free(dict) / free(skiplist)

    课后题:Redis 后台任务使用 bio_job 结构体来描述,该结构体用了三个指针变量来表示任务参数,如果我们创建的任务,所需要的参数大于 3 个,你有什么应对方法来传参么?

    最直接的方法就是,把参数换成数组类型,这样就可以传递任意数量参数了。因为这里 Redis 的后台任务都比较简单,最多 3 个参数就足够满足需求,所以 job 直接写死了 3 个参数变量,这样做的好处是维护起来简单直接。
    2021-08-21
    1
    2
  • Milittle
    这节课我学到了什么:
    1. 第一、redis不是单线程的,而是一个主线程,处理IO,另外有三个线程分别处理关闭fd、异步AOF刷盘、延迟释放。
    2. 我们从bio文件中可以看到函数之间的配合。

    回答一下课后题目:
    可以看到最新版的代码,redis开发人员已经把这个重构了:
    bio_job里面包含了fd(给关闭文件和异步刷盘用的),lazy_free_fn、free_args给延迟释放用的,一个是函数,一个是函数所需要用的参数。
    备注:结合老师讲的源码版本和自己结合最新的版本看,你会在这个过程里面学到不少,有一些时候问题,就被解决了,你也可以从中学习到一些。
    2021-08-23
    1
  • 一步
    后台线程有3个,后台进程有几个的?
    2021-08-22
    1
  • 可怜大灰狼
    如果所需要参数大于3个,我想可以把多个参数都封装到一个list或者dict中,然后占用arg1向实际业务方法传,只不过实际业务方法代码需要从list或dict再拆解出参数。
    2021-08-21
收起评论
5
返回
顶部