引言
Redis 是一款基于键值对的数据结构存储系统,它的特点是 基于内存操作、单线程解决命令、IO 多路复用模型解决网络申请、键值对存储与简略丰盛的数据结构 等等
本篇文章次要围绕 Redis 中 IO 多路复用模型解决网络申请的特点 来先从介绍 IO 模型,IO 多路复用模型以及客户端与服务端的通信
IO 模型
-
IO 申请(读)数据会切换至操作系统内核态来实现真正数据读取,而读取又分为两个阶段,别离为:
- 期待数据:调用后须要期待数据筹备好
- 复制数据:当筹备好数据后,将数据从内核空间复制到用户空间
常见 IO 模型
-
同步阻塞 IO:收回 IO 申请(零碎调用)后,阻塞期待内核筹备数据,数据筹备好了再把数据从内核空间拷贝到用户空间
- 一个线程解决一个客户端,同时解决大量网络申请时须要的线程太多,且线程 IO 申请时阻塞
<!—->
-
同步非阻塞 IO:线程轮循发动 IO 申请,如果没筹备好数据返回告知数据未筹备好,这样就会下次再轮循拜访,如果数据筹备好了就可能将数据从内核空间复制到用户空间
- 一个线程解决一个客户端,同时解决大量网络申请时须要的线程太多,尽管线程 IO 申请时不阻塞,然而轮循发动 IO 申请会节约 CPU(CPU 空转)
<!—->
-
IO 多路复用:应用选择器(select)阻塞期待事件,当监听 accept 事件阐明要建设连贯(与对应客户端建设套接字连贯能力进行读写事件),一次监听可能携带多个事件须要解决
![image-20221129073737746]()
- 一个线程监听多个客户端,轮循 select 阻塞,监听到套接字触发读 / 写事件时再进行解决(循环解决可能有多个客户端同时触发读写事件)
没看懂 IO 多路复用模型的同学能够持续往下看,下文会具体介绍 IO 多路复用模型的流程
通信
通信流程次要划分为:服务端要进行初始化,初始化后才开始循环处理事件,服务端在处理事件期间会保护客户端相干信息
服务端初始化
初始化
- 初始化服务端默认配置
- 依据启动命令更改配置
- 初始化数据结构
- 依据 AOF 或 RDB 复原数据(依据长久化策略复原数据,后续长久化文章会具体介绍)
- 开始事件循环(处理事件)
处理事件
处理事件能够看成解决客户端申请与保护治理服务端本身的资源
事件被分为文件事件和工夫工夫
文件事件常是解决客户端申请,工夫事件常是定时、周期工作来查看 / 治理服务端资源
文件事件
Redis 应用 IO 多路复用模型 监听多个客户端的套接字,当感知到套接字上产生事件时,将事件放入队列中,由文件事件分派器顺次取出事件并交给对应事件处理器解决
事件类型能够分为 读事件 AE_READABLE、写事件 AE_WRITEABLE,读写是以服务器为核心(起始)的,比方客户端发动连贯申请、发送命令申请都是触发读事件,而客户端须要读响应时是触发写事件
事件处理器有 连贯应答处理器(解决连贯的读事件),命令申请处理器(解决读事件),命令回复处理器(解决写事件),复制处理器(用于主从复制) 等等,本文次要应用连贯应答、命令申请、回复三种处理器
-
流程
- 服务端初始化时,连贯应答处理器与服务端监听套接字的读事件关联
- 客户端申请连贯时,服务端套接字触发读事件,服务端监听到读事件并放入队列中,事件分派器取出后交给连贯应答处理器解决,并将客户端套接字的读事件与命令申请处理器关联
- 客户端发送命令申请时,客户端套接字触发读事件,服务端监听到读事件并放入队列,事件分派器交给命令申请处理器解决,执行命令,筹备回复,将客户端套接字的写事件与命令回复处理器关联
- 客户端筹备读回复时,客户端套接字触发写事件,服务端监听到写事件并放入队列,事件分派器交给命令回复处理器解决,返回响应,勾销命令回复处理器与客户端套接字写事件的关联
![image-20221117172239493]()
工夫事件
工夫事件分为 定时工夫事件和周期时间事件,定时为规定事件做一次,周期为以多少工夫为周期做一次
工夫事件处理器 应用链表治理定时、周期事件,定期遍历链表,判断工夫事件是否到期,到期则执行,执行完判断工夫事件如果为定时则删除,为周期则更改下个周期达到工夫
工夫事件较少,基本上都是做一些定期检查,次要解决文件事件
服务器优先解决文件事件再解决工夫事件
客户端信息
服务端应用RedisClient 对象来存储客户端相干信息,应用链表治理 RedisClient(所有连贯的客户端)
-
redis client 信息
-
套接字描述符,判断客户端是否为伪客户端
- aof 伪客户端:aof 客户端执行 aof 文件,执行完敞开
- lua 脚本伪客户端:执行 lua 脚本,整个生命周期都存在
- 客户端名字、客户端标记(主从,状态等)、是否身份验证
- 输出缓冲区:保留序列化的命令申请
- 命令 argv 与 参数个数 args:解析序列化命令申请 失去命令与参数个数
- 命令相干信息 cmd : 依据 argv 查问字典 失去命令相干的信息 rediscommand
- 输入缓冲区:保留回复响应,如果短字符串应用固定缓冲区(字节数组),如果长字符串应用动静缓冲区(链表 + 字符串)
- 工夫:记录连接时间等信息
-
通信流程
-
服务端解决申请流程
- 用户发送命令到客户端,客户端序列化后发送给服务端(客户端与服务端建设连贯时,连贯应答处理器解决,让客户端套接字读事件关联到命令申请处理器)
-
服务端读取命令申请(监听到读事件产生,最终由命令申请处理器解决)
- 服务端接管序列化申请,解析出命令和参数个数填充属性 argv、args 参数
- 通过命令 argv 与字典查问该命令相干信息 cmd 指向该 rediscommand
-
服务端执行命令(执行完放到缓冲区,让客户端套接字写事件关联到命令回复处理器)
- 执行前查看参数个数、身份验证等操作
- 执行并将回复保留在输入缓冲区
- 执行后查看慢查问、写 AOF 缓冲等操作
- 服务端回复响应给客户端,客户端反序列化展现给用户(客户端筹备读取触发写事件,命令回复处理器解决响应回去,勾销关联)
定时工作通常用来治理服务器资源:更新缓冲工夫、每秒执行命令数量、已应用内存峰值,解决 sigterm 信号敞开前 RDB,治理客户端连贯、数据库资源,判断是否须要长久化等
总结
本文以 Redis 应用 IO 多路复用模型解决网络申请的为终点,介绍了 IO 模型,服务端初始化,服务端解决文件、工夫事件,客户端信息以及残缺的通信流程
同步阻塞 IO 模型,在解决大量网络申请时须要消耗一比一的线程,且产生零碎调用读数据时线程会阻塞
同步非阻塞 IO 模型,尽管不阻塞但存在 CPU 空转,节约性能
IO 多路复用模型应用 select 监听套接字上的读写事件,select 会阻塞,当监听到客户端套接字触发读写事件时,遍历解决所有套接字的读写事件
服务端初始化时次要是依据配置文件以及启动命令进行资源、数据结构的初始化,同时会依据长久化策略寻找 RDB、AOF 文件进行数据恢复,初始化完才开始循环处理事件
事件能够分为文件事件和工夫事件,文件事件罕用来解决客户端申请,分为读、写事件,当客户端套接字触发读、写事件时,将事件放入队列,文件事件分派器将队列中的事件顺次交给对应的事件处理器;工夫事件常是定时、周期工作,用来查看 / 治理服务端本身资源等
服务端处理事件期间,会应用链表治理保护客户端相干信息:输出缓冲区(序列化的命令申请)、命令与命令参数个数、命令相干信息(通过这些可能执行命令)、输入缓冲区(保留回复响应)
整体流程:
- 服务端依据配置文件、启动命令初始化数据结构,将连贯应答处理器与服务端监听套接字的读事件关联
- 客户端发动申请建设连贯时,服务端监听套接字读事件触发,连贯应答处理器将客户端套接字读事件与命令申请处理器关联
-
当客户端发送到服务端时,触发读事件,由命令申请处理器解决
- 解析输出缓冲区的序列化申请,解析完保留欠缺客户端信息(命令相干信息)
- 执行前查看参数个数、身份验证等
- 依据客户端保留命令相干信息执行函数
- 执行后还可能须要查看一些操作(如:查看慢查问、是否要写 AOF 缓冲区等),执行后将后果保留在输入缓冲区,让客户端套接字写事件关联命令回复处理器
- 当客户端筹备读时触发写事件,命令回复处理器将输入缓冲区响应返回
最初(一键三连求求拉~)
本篇文章笔记以及案例被支出 gitee-StudyJava、github-StudyJava 感兴趣的同学能够 stat 下继续关注喔 \~
有什么问题能够在评论区交换,如果感觉菜菜写的不错,能够点赞、关注、珍藏反对一下 \~
关注菜菜,分享更多干货,公众号:菜菜的后端私房菜
本文由博客一文多发平台 OpenWrite 公布!