乐趣区

关于后端:深入浅出Redis二Redis单线程模型与通信流程

引言

Redis 是一款基于键值对的数据结构存储系统,它的特点是 基于内存操作、单线程解决命令、IO 多路复用模型解决网络申请、键值对存储与简略丰盛的数据结构 等等

本篇文章次要围绕 Redis 中 IO 多路复用模型解决网络申请的特点 来先从介绍 IO 模型,IO 多路复用模型以及客户端与服务端的通信

IO 模型

  • IO 申请(读)数据会切换至操作系统内核态来实现真正数据读取,而读取又分为两个阶段,别离为:

    1. 期待数据:调用后须要期待数据筹备好
    2. 复制数据:当筹备好数据后,将数据从内核空间复制到用户空间

常见 IO 模型

  • 同步阻塞 IO:收回 IO 申请(零碎调用)后,阻塞期待内核筹备数据,数据筹备好了再把数据从内核空间拷贝到用户空间

    • 一个线程解决一个客户端,同时解决大量网络申请时须要的线程太多,且线程 IO 申请时阻塞

<!—->

  • 同步非阻塞 IO:线程轮循发动 IO 申请,如果没筹备好数据返回告知数据未筹备好,这样就会下次再轮循拜访,如果数据筹备好了就可能将数据从内核空间复制到用户空间

    • 一个线程解决一个客户端,同时解决大量网络申请时须要的线程太多,尽管线程 IO 申请时不阻塞,然而轮循发动 IO 申请会节约 CPU(CPU 空转)

<!—->

  • IO 多路复用:应用选择器(select)阻塞期待事件,当监听 accept 事件阐明要建设连贯(与对应客户端建设套接字连贯能力进行读写事件),一次监听可能携带多个事件须要解决

    ![image-20221129073737746]()

    • 一个线程监听多个客户端,轮循 select 阻塞,监听到套接字触发读 / 写事件时再进行解决(循环解决可能有多个客户端同时触发读写事件)

没看懂 IO 多路复用模型的同学能够持续往下看,下文会具体介绍 IO 多路复用模型的流程

通信

通信流程次要划分为:服务端要进行初始化,初始化后才开始循环处理事件,服务端在处理事件期间会保护客户端相干信息

服务端初始化

初始化

  1. 初始化服务端默认配置
  2. 依据启动命令更改配置
  3. 初始化数据结构
  4. 依据 AOF 或 RDB 复原数据(依据长久化策略复原数据,后续长久化文章会具体介绍)
  5. 开始事件循环(处理事件)

处理事件

处理事件能够看成解决客户端申请与保护治理服务端本身的资源

事件被分为文件事件和工夫工夫

文件事件常是解决客户端申请,工夫事件常是定时、周期工作来查看 / 治理服务端资源

文件事件

Redis 应用 IO 多路复用模型 监听多个客户端的套接字,当感知到套接字上产生事件时,将事件放入队列中,由文件事件分派器顺次取出事件并交给对应事件处理器解决

事件类型能够分为 读事件 AE_READABLE、写事件 AE_WRITEABLE,读写是以服务器为核心(起始)的,比方客户端发动连贯申请、发送命令申请都是触发读事件,而客户端须要读响应时是触发写事件

事件处理器有 连贯应答处理器(解决连贯的读事件),命令申请处理器(解决读事件),命令回复处理器(解决写事件),复制处理器(用于主从复制) 等等,本文次要应用连贯应答、命令申请、回复三种处理器

  • 流程

    1. 服务端初始化时,连贯应答处理器与服务端监听套接字的读事件关联
    2. 客户端申请连贯时,服务端套接字触发读事件,服务端监听到读事件并放入队列中,事件分派器取出后交给连贯应答处理器解决,并将客户端套接字的读事件与命令申请处理器关联
    3. 客户端发送命令申请时,客户端套接字触发读事件,服务端监听到读事件并放入队列,事件分派器交给命令申请处理器解决,执行命令,筹备回复,将客户端套接字的写事件与命令回复处理器关联
    4. 客户端筹备读回复时,客户端套接字触发写事件,服务端监听到写事件并放入队列,事件分派器交给命令回复处理器解决,返回响应,勾销命令回复处理器与客户端套接字写事件的关联

![image-20221117172239493]()

工夫事件

工夫事件分为 定时工夫事件和周期时间事件,定时为规定事件做一次,周期为以多少工夫为周期做一次

工夫事件处理器 应用链表治理定时、周期事件,定期遍历链表,判断工夫事件是否到期,到期则执行,执行完判断工夫事件如果为定时则删除,为周期则更改下个周期达到工夫

工夫事件较少,基本上都是做一些定期检查,次要解决文件事件

服务器优先解决文件事件再解决工夫事件

客户端信息

服务端应用RedisClient 对象来存储客户端相干信息,应用链表治理 RedisClient(所有连贯的客户端)

  • redis client 信息

    • 套接字描述符,判断客户端是否为伪客户端

      • aof 伪客户端:aof 客户端执行 aof 文件,执行完敞开
      • lua 脚本伪客户端:执行 lua 脚本,整个生命周期都存在
    • 客户端名字、客户端标记(主从,状态等)、是否身份验证
    • 输出缓冲区:保留序列化的命令申请
    • 命令 argv 与 参数个数 args:解析序列化命令申请 失去命令与参数个数
    • 命令相干信息 cmd : 依据 argv 查问字典 失去命令相干的信息 rediscommand
    • 输入缓冲区:保留回复响应,如果短字符串应用固定缓冲区(字节数组),如果长字符串应用动静缓冲区(链表 + 字符串)
    • 工夫:记录连接时间等信息

通信流程

  • 服务端解决申请流程

    1. 用户发送命令到客户端,客户端序列化后发送给服务端(客户端与服务端建设连贯时,连贯应答处理器解决,让客户端套接字读事件关联到命令申请处理器)
    2. 服务端读取命令申请(监听到读事件产生,最终由命令申请处理器解决)

      • 服务端接管序列化申请,解析出命令和参数个数填充属性 argv、args 参数
      • 通过命令 argv 与字典查问该命令相干信息 cmd 指向该 rediscommand
    3. 服务端执行命令(执行完放到缓冲区,让客户端套接字写事件关联到命令回复处理器)

      • 执行前查看参数个数、身份验证等操作
      • 执行并将回复保留在输入缓冲区
      • 执行后查看慢查问、写 AOF 缓冲等操作
    4. 服务端回复响应给客户端,客户端反序列化展现给用户(客户端筹备读取触发写事件,命令回复处理器解决响应回去,勾销关联)

定时工作通常用来治理服务器资源:更新缓冲工夫、每秒执行命令数量、已应用内存峰值,解决 sigterm 信号敞开前 RDB,治理客户端连贯、数据库资源,判断是否须要长久化等

总结

本文以 Redis 应用 IO 多路复用模型解决网络申请的为终点,介绍了 IO 模型,服务端初始化,服务端解决文件、工夫事件,客户端信息以及残缺的通信流程

同步阻塞 IO 模型,在解决大量网络申请时须要消耗一比一的线程,且产生零碎调用读数据时线程会阻塞

同步非阻塞 IO 模型,尽管不阻塞但存在 CPU 空转,节约性能

IO 多路复用模型应用 select 监听套接字上的读写事件,select 会阻塞,当监听到客户端套接字触发读写事件时,遍历解决所有套接字的读写事件

服务端初始化时次要是依据配置文件以及启动命令进行资源、数据结构的初始化,同时会依据长久化策略寻找 RDB、AOF 文件进行数据恢复,初始化完才开始循环处理事件

事件能够分为文件事件和工夫事件,文件事件罕用来解决客户端申请,分为读、写事件,当客户端套接字触发读、写事件时,将事件放入队列,文件事件分派器将队列中的事件顺次交给对应的事件处理器;工夫事件常是定时、周期工作,用来查看 / 治理服务端本身资源等

服务端处理事件期间,会应用链表治理保护客户端相干信息:输出缓冲区(序列化的命令申请)、命令与命令参数个数、命令相干信息(通过这些可能执行命令)、输入缓冲区(保留回复响应)

整体流程:

  1. 服务端依据配置文件、启动命令初始化数据结构,将连贯应答处理器与服务端监听套接字的读事件关联
  2. 客户端发动申请建设连贯时,服务端监听套接字读事件触发,连贯应答处理器将客户端套接字读事件与命令申请处理器关联
  3. 当客户端发送到服务端时,触发读事件,由命令申请处理器解决

    • 解析输出缓冲区的序列化申请,解析完保留欠缺客户端信息(命令相干信息)
    • 执行前查看参数个数、身份验证等
    • 依据客户端保留命令相干信息执行函数
    • 执行后还可能须要查看一些操作(如:查看慢查问、是否要写 AOF 缓冲区等),执行后将后果保留在输入缓冲区,让客户端套接字写事件关联命令回复处理器
  4. 当客户端筹备读时触发写事件,命令回复处理器将输入缓冲区响应返回

最初(一键三连求求拉~)

本篇文章笔记以及案例被支出 gitee-StudyJava、github-StudyJava 感兴趣的同学能够 stat 下继续关注喔 \~

有什么问题能够在评论区交换,如果感觉菜菜写的不错,能够点赞、关注、珍藏反对一下 \~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

本文由博客一文多发平台 OpenWrite 公布!

退出移动版