文档章节

Redis网络架构及单线程模型

Float_Luuu
 Float_Luuu
发布于 2016/05/20 22:51
字数 1740
阅读 1720
收藏 20
点赞 2
评论 0

最近略有闲暇时间,于是对Redis进行了一些学习,学习途径除了官方文档还有Redis源代码,我看的版本是2.8.13,Redis源码总行数不到5W行,不同组件拆分非常细致,阅读起来也很清晰。这篇博客主要介绍我对Redis网络层架构以及线程模型的一些了解,希望能对大家有所帮助。

 

Redis网络基础架构

网络编程离不开Socket,网络I/O模型最常用的无非是同步阻塞、同步非阻塞、异步阻塞、异步非阻塞,高性能网络服务器最常见的线程模型也就是基于EventLoop模式的单线程模型。我们看看Redis的网络架构是怎么样的:

Redis基础组建结构

这里解释下上图涉及的组件,Redis网络层基础组件主要包括四个部分:

  1. EventLoop事件轮训器,这部分实现在AE里面。
  2. 提供Socket句柄事件的多路复用器,这部分分别对于不同平台提供了不同的实现,比如epoll和select可以用于linux平台、kqueue可以用于苹果平台、evpoll可以用于Solaris平台,这里并没有看到iocp,也就是Redis对于Windows支持并不是很好。
  3. 包括网络事件处理器实现的networking,这部分主要包括两个重要的今天要讲的事件处理器:acceptTcpHandler和acceptCommonHandler。
  4. 处理网络比较底层的部分,比如网络句柄创建、网络的读写等。

 

Redis单线程模型

要理解Redis的单线程模型,我们先抛出一些问题,当我们有多个客户端同时去跟Redis Server建立连接,之后又同时对某个key进行操作,这个过程中发生了什么呢?会不会有并发问题?

网络初始化

好了,这些问题先丢在这了,我们看看Redis启动初始化的过程中会做什么事情,这里尽量省略了与本文无关的部分:

  1. 初始化Redis Server参数,这部分代码通过initServerConfig实现。
  2. 初始化Redis Server,这部分代码在initServer里面。
  3. 启动事件轮训器。

对,这里我们就把Redis的启动部分简化为三步,跟网络操作有关的主要在第二步和第三步里面,来看看initServer里面发生了什么:

initServer流程

initServer里面首先创建了一个EventLoop,然后监听Server的IP对应的端口号,假设我们监听的是127.0.0.1:3333这个IP:端口对,我们得到的一个Server Socket句柄,最后通过createFileEvent将我们得到的Server Socket句柄和我们关心的网络事件mask注册到EventLoop上面。EventLoop是什么呢,我们看看它的定义:

typedef struct aeEventLoop {
    int maxfd;   /* highest file descriptor currently registered */
    int setsize; /* max number of file descriptors tracked */
    long long timeEventNextId;
    time_t lastTime;     /* Used to detect system clock skew */
    aeFileEvent *events; /* Registered events */
    aeFiredEvent *fired; /* Fired events */
    aeTimeEvent *timeEventHead;
    int stop;
    void *apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc *beforesleep;
} aeEventLoop;

上面我们关注的主要是两个东西:events和fired。他们分别是两个数组,events用于存放被注册的事件以及相应的句柄,fired用于存放当EventLoop线程从多路复用器轮训到有事件的句柄的时候,EventLoop线程会把它放入fired数组里面,然后处理。

事件注册示意图

我用上面的示意图描述createFileEvent做的事情,就是将Server Socket句柄和关心的事件mask以及当事件产生的时候的事件处理器accptHandler生成一个aeFileEvent注册到EventLoop的events的数组里面,当然在这之前会首先将事件注册到多路复用器上,也就是epoll、kqueue等这些组件上。事件注册完之后需要对多路复用器进行轮训,来分离我们关心切发生的事件,那就是最后一步,启动事件轮询器。

接收网络连接

上面的步骤完成了服务端的网络初始化,而且事件轮询器已经开始工作了,事件轮询器做什么事情呢,就是不断轮训多路复用器,看看之前注册的事件有没有发生,如果有发生,则将会将事件分离出来,放入EventLoop的fired数组中,然后处理这些事件。

很显然,上面注册的事件是客户端建立连接这个事件,因此当有两个客户端同时连接Redis服务器的时候,事件轮询器会从多路复用器上面分离出这个事件,同时调用acceptHandler来处理。acceptHandler做的事情主要是accept客户端的连接,创建socket句柄,然后将socket句柄和读事件注册到EventLoop的events数组里面,不一样的是对于客户端的事件处理器是readQueryClient。

accept客户端连接以及注册客户端连接句柄示意图

上面示意图表示了acceptHandler处理客户端连接,得到句柄之后再将这个句柄注册到多路复用器以及EventLoop上的示意图。之后再同样再处理下一个客户端的连接,这些都是串行的。

事件轮训

上面接收客户端这部分其实都发生在事件轮训的主循环里面:

void aeMain(aeEventLoop *eventLoop) {
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
    }
}

Redis会不断的轮训多路复用器,将网络事件分离出来,如果是accept事件,则新接收客户端连接并将其注册到多路复用器以及EventLoop中,如果是查询事件,则通过读取客户端的命令进行相应的处理,这一切都是单线程,顺序的执行的,因此不会发生并发问题。

应用分析

Redis官网对Redis的读写性能测试结果达到10左右,这是非常吸引人的。Redis的单线程的行为主要是对内存的读写,这些操作其实用不了多少时间,因此瓶颈在网络I/O上面,我们一般提供较好的网络环境就可以提升Redis的吞吐量,比如提高网络带宽,除此之外还可以通过合并命令提交批处理请求来代替单条命令一次次请求从而减少网络开销,提高吞吐量。

 

参考文献

《Redis源码》

 

 

© 著作权归作者所有

共有 人打赏支持
Float_Luuu
粉丝 199
博文 46
码字总数 102357
作品 0
长宁
高级程序员
Redis 专栏(使用介绍、源码分析、常见问题...)

来源http://blog.csdn.net/yangbodong22011/article/details/78529448 https://github.com/hurley25 https://github.com/hurley25/ANet ANet 基于Redis网络模型的简易网络库,网络模块代码取......

libaineu2004
2017/12/16
0
0
Redis网络库源码浅解

Redis网络模型是一个使用IO多路复用、单线程、非阻塞的模型。这个模型的优点在于单线程不用考虑加锁,如果在单核环境上可以将效率发挥到最大。它没有那么庞大,代码一共2000多行,因此比较容...

Tanswer_
2017/08/12
0
0
Redis单线程优势

简介 Redis采用的是基于内存的采用的是单进程单线程模型的KV数据库,由C语言编写。官方提供的数据是可以达到100000+的qps。这个数据不比采用单进程多线程的同样基于内存的KV数据库Memcached...

沈渊
2017/11/12
0
0
Redis是单线程的以及Redis为什么这么快

一、前言 近乎所有与Java相关的面试都会问到缓存的问题,基础一点的会问到什么是“二八定律”、什么是“热数据和冷数据”,复杂一点的会问到缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降...

码上青天
05/03
0
0
为什么使用 Redis及其产品定位

传统MySQL+ Memcached架构遇到的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和...

今幕明
2014/08/23
0
0
为什么使用 Redis及其产品定位

传统MySQL+ Memcached架构遇到的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和...

stefanzhlg
2014/12/18
0
0
NoSQL数据库:Redis适用场景及产品定位

传统MySQL+ Memcached架构遇到的问题   实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加...

小虫子de
2013/06/17
0
3
UtilBox(ub)基础组件 -- epoll_server网络事件模型

今天事情比较少,突然在在网上看到了一篇关于网络同步异步IO的帖子,正好想起了前几天分析过的Redis的代码。Redis的代码很精练也很轻巧,基本没有第三方以来的库(最新版本中加入了jemalloc,...

长平狐
2013/01/05
176
0
360开源的网络编程库--Pink

Pink是360开源的网络编程库,支持 pb、Redis 等协议。对网络编程的封装,用户实现一个高性能的 server 只需要实现对应的 DealMessage 函数即可。 支持单线程模型、多线程 worker 模型。...

匿名
2016/08/11
919
1
Redis与Memcached的区别

传统MySQL+ Memcached架构遇到的问题   实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加...

蓝狐乐队
2014/05/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

tomcat虚拟路径的几种配置方法

tomcat虚拟路径的几种配置方法 一般我们都是直接引用webapps下面的web项目,如果我们要部署一个在其它地方的WEB项目,这就要在TOMCAT中设置虚拟路径了,Tomcat的加载web顺序是先加载 $Tomcat_ho...

Helios51
8分钟前
1
0
Mac 安装jupyter notebook的过程

MAC台式机 python:mac下自带Python 2.7.10 1.先升级了pip安装工具:sudo python -m pip install --upgrade --force pip 2.安装setuptools 工具:sudo pip install setuptools==33.1.1 3.安装......

火力全開
14分钟前
0
0
导航守卫解释与例子

“导航”表示路由正在发生改变。 正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。 记住...

tianyawhl
14分钟前
0
0
Java日志框架-logback配置文件多环境日志配置(开发、测试、生产)(原始解决方法)

说明:这种方式应该算是最通用的,原理是通过判断标签实现。 <!-- if-then form --> <if condition="some conditional expression"> <then> ... </then> </if> ......

浮躁的码农
28分钟前
1
0
FTP传输时的两种登录方式和区别

登录方式 匿名登录 用户名为: anonymous。 密码为:任何合法 email 地址。 授权登录 用户名为:用户在远程系统中的用户帐号。 密码为:用户在远程系统中的用户密码。 区别 匿名登录 只能访问...

寰宇01
29分钟前
0
0
plsql developer 配置监听(不安装oracle客户端)

plsql developer 配置监听(不安装oracle客户端)

微小宝
36分钟前
1
0
数据库(分库分表)中间件对比

本人的宗旨就是,能copy的,绝对不手写。 分区:对业务透明,分区只不过把存放数据的文件分成了许多小块,例如mysql中的一张表对应三个文件.MYD,MYI,frm。 根据一定的规则把数据文件(MYD)和索...

奔跑吧代码
40分钟前
2
0
Netty与Reactor模式详解

在学习Reactor模式之前,我们需要对“I/O的四种模型”以及“什么是I/O多路复用”进行简单的介绍,因为Reactor是一个使用了同步非阻塞的I/O多路复用机制的模式。 I/O的四种模型 I/0 操作 主要...

hutaishi
47分钟前
1
0
【2018.07.16学习笔记】【linux高级知识 20.16-20.19】

20.16/20.17 shell中的函数 20.18 shell中的数组 20.19 告警系统需求分析

lgsxp
52分钟前
0
0
用 D3.js 画一个手机专利关系图, 看看苹果,三星,微软间的专利纠葛

用 D3.js 画一个手机专利关系图, 看看苹果,三星,微软间的专利纠葛 前言 本文灵感来源于Mike Bostock 的一个 demo 页面 原 demo 基于 D3.js v3 开发, 笔者将其使用 D3.js v5 进行重写, 并改为...

ssthouse_hust
56分钟前
23
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部