likes
comments
collection
share

【Redis源码系列】Redis6.0 超详细多线程IO源码分析

作者站长头像
站长
· 阅读数 48

前言

上篇文章我们研究了Redis6的事件机制, 与之前版本相比, 事件处理机制并没有太大的变化。在6.0版本中最大的变化莫过于增加了多线程IO机制, 有效提升了Redis在处理网络IO方面的处理能力, 官方宣称性能可以提高至一倍, 本人未作具体性能测试, 大家可以参考: Redis6.0多线程性能测试。我们一起从源码探究多线程IO实现的具体流程。

事件机制回顾: Redis6.0事件机制详解

多线程设计

Redis6.0的多线程分为以下几个部分:

  1. server.c 中设置 beforesleep 回调函数, 文件事件回调函数等相关设置, 其中 beforesleep 中比较重要的有handleClientsWithPendingReadsUsingThreads, 下文我们将具体展开讲述
  2. 启动 IO Thread, 并设置 IO 线程的处理函数
  3. 执行事件轮询, 将 IO 事件分发给不同的线程处理

整体架构如下图所示: 【Redis源码系列】Redis6.0 超详细多线程IO源码分析

源码流程分析

设置事件处理函数

调用 initServer > aeSetBeforeSleepProc 设定 beforesleep 函数, 其中 handleClientsWithPendingReadsUsingThreads 将所有IO线程置为读状态,函数源码如下:

【Redis源码系列】Redis6.0 超详细多线程IO源码分析

启动多线程

initThreadedIO

server.c 文件中的main函数流程, 通过: InitServerLast() -> initThreadedIO(), 启动线程, 我们一起来看启动线程的详细流程:

【Redis源码系列】Redis6.0 超详细多线程IO源码分析

可以看到 redis 6.0 最多允许启动 128 个IO 线程, 启动时初始化每一个 io_threads_list 为双向链表, 用于保存任务信息, 并且为IO线程注册回调函数IOThreadMain, 这是一个比较重要的处理函数, 我们一起梳理其流程。

IOThreadMain

IOThreadMain 回调的处理流程相对比较简单, 就是根据当前任务标志位 (读|写), 遍历任务链表执行任务的处理操作。

【Redis源码系列】Redis6.0 超详细多线程IO源码分析

IOThreadMain 中会遍历当前线程的任务列表, 根据读写标识确定可执行的操作, 从源码可以看出在同一时刻, redis的IO线程只能处理读或者写操作, 通过上篇文章的分析可知道在 readQueryFromClient 函数在创建连接回调的时候一直执行过一次, 如此执行不是死循环吗, 答案就在 readQueryFromClient 函数中:

【Redis源码系列】Redis6.0 超详细多线程IO源码分析

至此和多线程启动相关的源码执行流程已经分析完毕, 完成服务的启动后就进入时间轮询中。

事件轮询

主线程调用: aeMian -> aeProcessEvents 进入事件轮询, redis服务启动完成, 开始接受并处理事件。在执行poll的过程中会执行 beforesleepaftersleep 两个钩子函数, 如果我们后续有插件需求也可以基于这两个函数来处理, beforesleep 中有两个比较重要的函数 handleClientsWithPendingWritesUsingThreadshandleClientsWithPendingReadsUsingThreads, 目的是为了进入下一次轮训前, 将 server.clients_pending_readserver.clients_pending_write 处理完成, 保证列表中不再有待处理任务。

【Redis源码系列】Redis6.0 超详细多线程IO源码分析

其中读事件回调:acceptTcpHandler|acceptTLSHandler|acceptUnixHandler|moduleBlockedClientPipeReadable 底层都调用了 acceptCommonHandler -> createClient -> connSetReadHandler(conn, readQueryFromClient) 设定连接的读事件处理函数。

至此整条线路梳理完成, 客户端连接读|写事件到来时, 调用回调函数将事件加入到 server.clients_pending_readserver.clients_pending_write,然后IO线程轮询处理每个客户端的等待事件, 完成后进入下一次轮询。

总结

【Redis源码系列】Redis6.0 超详细多线程IO源码分析

总结不易, 别忘了素质三连,下期开始研究服务的对象结构和数据结构, 求各位看官给个小小的赞 :)

转载自:https://juejin.cn/post/6992407136261128229
评论
请登录