从架构图及源码分析redis单体服务架构

文章目录:
[TOC]

    本章从全局角度来看下redis服务设计的架构,从整体感官感受下redis 的各个数据结构、线程模型等之间的关联关系。希望整体的认识能给我们后续的redis 细分模块领域的学习做好铺垫。
我们可以带着问题去思考学习:
1.redis 的服务性能为什么处理的快?
2.reids 的服务性能为什么可以支撑高并发?

先看下整体的模块图:


redis 架构图.png

1. 顶层域划分:

首先大图分为三个域: 客户端、系统内核域、redis域。
我们需要描述清楚三者之间的关系,客户端是redisClient 发起的请求,属于跨进程的调用,redis域的 与客户端通信交互 需要 依赖
操作系统内核的 eventLoop 事件机制, 如此构成了整体的大模块的结构。

2. redis 模块划分:

模块 功能
1.ae模块 负责网络事件 IO多路复用的
2.bio模块 负责后台job 执行
3.iothread多线程模块 负责并发读,并发写
4.zmalloc内存管理模块 负责内存管理
5.协议模块 负责客户端 和 服务端报文通信协议
6.DB模块 数据存储及命令执行模块
7.数据磁盘模块 AOF、RDB
8. ACL权限模块 访问控制权限

3. redis 启动流程:(main 线程)

  1. 执行启动命令: ./redis-server -选项
  2. 执行.initServerConfig 函数:
    2.1 构造server单例,数据结构 server代表redis,里面包含了db,配置项等,所有和服务关联的数据。
    2.2 挂载命令
    2.3 初始化配置,从配置文件及命令中;
  3. 执行 initServer 函数:
    3.1 分配客户端列表
    3.2 分配读写等待队列
    3.3 db 内存分配
    3.4 创建redis共享对象
    3.5 createSocketAcceptHandler .aeCreateFileEvent 把新建接受链接的处理函数注册到 el 上;
    3.6 设置 轮询中的 睡眠 前后 执行函数aeSetBeforeSleepProc(server.el,beforeSleep);
  4. InitServerLast 服务最后的初始化动作;
    4.1 bioInit(); /// backgroud 后台io 进程初始化
    4.2 initThreadedIO(); // redis 引入的多线程
  5. loadDataFromDisk 从磁盘中加载redis 数据(AOF+RDB)
  6. mian.aeMain 事件循环函数,进入无限循环中执行函数 :aeProcessEvents
    6.1 eventLoop->beforesleep 休眠前执行
    6.1.1 执行并发读
    6.1.2 执行命令执行
    6.1.3 执行并发写
    6.2 numevents = aeApiPoll(eventLoop, tvp); 如果没有事件,可能导致休眠,直到超时:
    6.3 eventLoop->aftersleep(eventLoop); 休眠后执行函数:暂无耗时操作;
    6.4 for 循环执行 events 事件; 事件执行 , 产生新的连接及读事件。

4. eventLoop 机制:

这个是实现我么你常说的IO多路复用的功能,网络事件(建立连接、收到数据、连接关闭) 会更新触发 eventLoop 产生对应的事件。 事件注册的时候,会把对应的回调处理函数hook 也写到 事件属性里面。

这样,在redis 域内,main 线程会不断轮询去取 eventList ,然后调用event 关联的proc,去处理回调。这里需要注意有哪些事件。
eventLoop的底层原理是 IO多路复用技术, 编译时会看执行的平台,选择不同平台的 多路复用函数。

参考: IO多路复用实现方式 select, poll ,epoll :
https://blog.csdn.net/fengyuyeguirenenen/article/details/124234675

5. 事件类型

  1. 文件事件->监听的端口的新链接事件;其中建立连接后,把连接的fd 会注册到 el上,当文件有读事件后,会触发 2.
  2. 文件事件->socket 有数据可读事件;
  3. 文件事件-> 连接关闭事件;
  4. 时间事件-> 轮询然后判断时间间隔,判断规则是否产生时间

6. redis 所有事件异步驱动逻辑点

  1. 网络事件: eventLoop 借助内核 实现网络事件的 异步及IO多路复用。
  2. 可读、可写客户端队列: 准备好的客户端都排在队列里面;
  3. 并发读写时间:读写队列执行前,main 线程会把任务分派给每个线程来执行;
  4. 时间事件: AOF 异步写等;
  5. 后台事件: 发送到对应类型job 的实践队列中;

实现的方式:数据结构分割数据,多线程根据数据及锁、标识写作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容