《Redis设计与实现》读书笔记(十六) ——Redis文件事件 (原创内容,转载请注明来源,谢谢)

《Redis设计与实现》读书笔记(十六) ——Redis文件事件

(原创内容,转载请注明来源,谢谢)

一、概述

redis服务器是一个事件驱动程序,服务器需要处理以下两类事件:

1)文件事件(fileevent),redis服务器与客户端通过socket连接,文件事件是对socket的抽象,服务器与客户端通信会产生文件事件,服务器通过监听文件事件产生一系列操作。

2)时间事件(timeevent),redis的部分操作需要定时执行,主要是serverCron函数,例如定时清理过期键、定时aof写入等,时间事件是服务器对此类的抽象。

二、文件事件

1、reactor模式

redis基于reactor模式开发网络事件处理器,将其称之为文件时间处理器。该处理器通过I/O多路复用,同时监听多个socket,并根据socket当前处理的任务来关联不同的事件处理器。

reactor模式如下图所示:

其是处理并发I/O比较常见的一种模式,用于同步I/O。中心思想是将所有要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程阻塞在多路复用器上。一旦有I/O事件到来或是准备就绪(区别在于多路复用器是边沿触发还是水平触发),多路复用器返回并将相应I/O事件分发到对应的处理器中。

reactor中文称为反应器,即其不是等套接字来调用,而是提前建立好,并主动去调用到来或就绪的套接字。

当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作,会产生相应的文件事件。此时,文件事件处理器(即reactor)会调用之前关联好的处理器来处理事件。

I/O多路复用的reactor模式,使得redis虽然是单线程处理,但是仍然具有高效率。

2、文件事件处理器的构成

文件事件处理器由四部分组成——套接字、I/O多路复用程序、文件事件分派器、事件处理器,如下图所示:

通常,一个服务器需要同时处理多个套接字,因此文件事件可能并发出现。I/O多路复用程序是通过监听多个套接字,并将准备好的套接字按准备好的时间顺序转发给文件时间分派器。由文件时间分派器根据具体的事件类型,分派给不同的事件处理器。

I/O多路复用程序将并发出现的多个套接字加入到队列中,以有序、同步、每次一个的方式,将事件发送给文件事件分派器,并且当事件处理完毕后,才会将下一个事件发送过去。如下图所示:

I/O多路复用程序会监听多个套接字的读(ae.h/AE_READABLE)和写事件(ae.h/AE_WRITEABLE),当套接字可读或有新的可应答的套接字出现,产生读事件;当套接字可写,产生写事件。如果同时可读可写,则会先读再写。如果没有任何事件,返回的是ae.h/AE_NONE。

3、I/O多路复用程序

redis的I/O多路复用程序是通过包装操作系统原生的如select、epoll、evport、kqueue等I/O多路复用函数库,来实现I/O多路复用。由于redis底层对每种I/O多路复用都实现了相同的api接口,因此可以根据实际情况互换。每种复用方式,在redis里面是分别保存在一个.c的文件内。

1)select

select是较早的unix多路复用方式,其提供三种流——读、写、异常,调用时需要传入感兴趣的流,select将其拷贝到内核。select会使程序阻塞,让后其轮询每个流,当某个监听的流有操作时,其调用相关函数,返回结果。

由于select会将传入的流修改,并且需要全量传入、全量返回,对于大量的请求下,效率较低。

2)epoll与kqueue

epoll是linux内核的,kqueue是BSD内核的,其原理基本一致。其是通过创建一个句柄,并注册事件函数。即其是提前将有可能的事件都先注册好,当具体事件发生时去调用,而不是select的每次发生时在注册。

4、文件事件处理器

redis针对不同的文件事件,编写了多个文件事件处理器,包括处理各个客户端连接的应答处理器、接收客户端请求的命令请求处理器、向客户端返回命令结果的命令回复处理器、主从复制情况下的复制处理器。

1)应答处理器

名称是networking.c/acceptTcpHandler,用于对连接服务器监听套接字的客户端进行应答。redis初始化的时候,会将此应答处理器和套接字的读事件联系起来。当客户端发送连接请求,就会产生读事件(AE_READABLE)。

2)命令请求处理器

名称是networking.c/readQueryFromClient,用于处理读入客户端发送过来的套接字,当应答处理器连接到套接字的时候,命令请求处理器就会将读事件与其关联起来。当客户端发送请求时,就会产生读事件,命令请求处理器读入套接字中客户端发送的命令事件。

3)命令回复处理器

名称是networking.c/sendReplyToClient,用于将服务器执行命令后得到的回复返回给客户端。当有命令要返回给客户端,redis会将写事件与命令回复处理器关联起来,当客户端准备好接受服务器的回复,就会产生写事件,引发命令处理器将相关要返回给客户端的实际写入套接字。命令发送完毕后,会解除写事件和该客户端的关联。

4)示例

下面讲述一次完整的客户端与服务器连接事件。

当redis服务器正常运作时,监听套接字的事件AE_READABLE处于监听状态,且相应处理该事件的是应答处理器。

当有客户端向redis服务器发送连接请求,会产生AE_READABLE,触发应答处理器执行。处理器会进行连接并回复客户端,并创建客户端套接字,将套接字的AE_READABLE与命令请求处理器关联。

当客户端向redis服务器发送命令,会产生AE_READABLE事件,命令请求处理器会读入套接字中的命令,并传给相关执行程序去执行。

redis服务器执行完毕命令后,将产生相应的回复,服务器会将套接字的AE_WRITEABLE与命令回复处理器关联,当客户端尝试读取回复,客户端套接字将产生AE_WRITEABLE,命令回复处理器将执行,把要返回的内容写入套接字。

整个过程如下图:

——written by linhxx 2017.09.06

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-09-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

Linux系统进程的知识总结,进程与线程之间的纠葛...

当一个程序开始执行后,在开始执行到执行完毕退出这段时间内,它在内存中的部分就叫称作一个进程。

560
来自专栏用户画像

2.1.5 数据报与虚电路

分组交换根据其通信子网向端点系统提供的服务,还可以进一步分为面向连接的虚电路方式和无连接的数据报方式。这两种服务方式都由网络层提供。

752
来自专栏CSDN技术头条

深入理解 Java 多线程核心知识:跳槽面试必备

多线程相对于其他 Java 知识点来讲,有一定的学习门槛,并且了解起来比较费劲。在平时工作中如若使用不当会出现数据错乱、执行效率低(还不如单线程去运行)或者死锁...

843
来自专栏存储

spring boot redis分布式锁

随着现在分布式架构越来越盛行,在很多场景下需要使用到分布式锁。分布式锁的实现有很多种,比如基于数据库、zookeeper等,本文主要介绍使用Redis做分布式锁...

3615
来自专栏知识分享

关于STM32的外部引脚中断的问题

今天想用自己以前的比较干净的工程模板做一个东西,,,,,,,在添加上引脚中断的时候,,突然想知道自己配置的中断优先级是否正确执行,,,,, 以前刚学习32的时候...

3246
来自专栏coder修行路

python爬虫番外篇(一)进程,线程的初步了解

整理这番外篇的原因是希望能够让爬虫的朋友更加理解这块内容,因为爬虫爬取数据可能很简单,但是如何高效持久的爬,利用进程,线程,以及异步IO,其实很多人和我一样,故...

1856
来自专栏Golang语言社区

高性能网络编程7--tcp连接的内存使用

当服务器的并发TCP连接数以十万计时,我们就会对一个TCP连接在操作系统内核上消耗的内存多少感兴趣。socket编程方法提供了SO_SNDBUF、SO_RCVB...

3106
来自专栏行者悟空

Hadoop之RPC机制

671
来自专栏C/C++基础

操作系统简介

操作系统(Operating System,OS)是计算机系统组成要素,是管理和控制计算机硬件与软件资源的基本软件。操作系统是用户和计算机交互的接口,也是计算机...

823
来自专栏用户画像

7.4.2 程序中断方式

程序中断是指在计算机执行现行程序的过场中,出现某些急需处理的异常情况或特殊请求,CPU暂停中断现行程序,而专区对这些异常情况或特殊情况进行处理,在处理完毕后CP...

441

扫描关注云+社区