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