1:io多路复用epoll 
io多路复用简单来说就是一个线程处理多个网络请求
我们知道epoll in 的事件触发是可读了,这个比较好理解,比如一个连接过来,或者一个数据发送过来了,那么in事件就触发了,那么out事件是如何触发的呢?缓冲区可写(有空的区域),就可以触发,epoll有两种模式LT(水平触发)和ET(边缘触发),LT模式下,主要缓冲区数据一次没有处理完,那么下次epoll_wait返回时,还会返回这个句柄;而ET模式下,缓冲区数据处理一次就结束,下次是不会再通知了,只在第一次返回.所以在ET模式下,一般是通过while循环,一次性读完全部数据.epoll默认使用的是LT.
socket的缓冲区已经满了,此时无法继续send。此时异步程序的正确处理流程是调用epoll_wait,当socket缓冲区中的数据被对方接收之后,缓冲区就会有空闲空间可以继续往里面写数据,此时epoll_wait就会返回这个socket的EPOLLOUT事件,获得这个事件时,你就可以继续往socket中写出数据。
redis的epoll使用的是默认的LT模式,只要写缓冲区可写时,就会不断的触发可写事件,为了避免一直触发可写事件,redis是在有数据可写的时候注册写事件,写完之后就取消写事件的注册
epoll内部数据结构为红黑树和链表,红黑树保存了所有socket和监听的事件信息,链表保存的是就绪的socket信息,就是那些就绪socket已经帮你整理好了
那么,这个准备就绪list链表是怎么维护的呢?当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。所以,当一个socket上有数据到了,内核在把网卡上的数据copy到内核中后就来把socket插入到准备就绪链表里了。
如此,一颗红黑树,一张准备就绪句柄链表,少量的内核cache,就帮我们解决了大并发下的socket处理问题。执行epoll_create时,创建了红黑树和就绪链表,执行epoll_ctl时,如果增加socket句柄,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断事件来临时向准备就绪链表中插入数据。执行epoll_wait时立刻返回准备就绪链表里的数据即可。
 
 
2:redis单线程是怎么做到高性能的呢?
以前我一直在想一个问题:如果一个redis命令很长,redis接收处理这个命令就要100毫秒,那么别的命令会不会延迟100毫秒呢?后续命令处理会不会像消息队列一样积压呢?
答案:不会
上面我们已经说了epoll的原理,它不是让我们一次处理完一个命令后,再去处理另一个命令,epoll是帮我们一次接收多个命令的部分数据(如果命令很短则是完整的数据),每个socket都有一个缓冲区,写满了就不能写了,需要读出来后才能继续往里面写,redis为每个client分配了一个变长缓冲区,从socket中读出后存在缓冲区中,当接收到一个完整的命令,就解析并执行这个命令,然后把缓冲区后面的数据往前移动,反复利用这块内存,当这块内存超过一定值后就会释放,在需要的时候重新分配一块内存
也就是说epoll的水平触发模式将一个较长的命令请求分成了多次接收,一次能接收多个命令的请求,天生就只支持高并发的,加上redis会将耗时的命令会分多次处理,保证了我们的读写操作都很快。
综述单线程高性能的原因:
1:纯内存操作本来就很快
2:redis使用epoll支持io多路复用,天生支持高并发请求
3:redis将耗时的操作分多次处理,保证每次处理的时间都很短,保证了读写性能,如果数据很长的话处理时间就会变长,所以redis不建议保存太长的数据
还有redis6.0实现了多线程的功能,性能至少翻倍,那你还要问题单线程为什么性能高吗?而且还是在数据的接收解析和数据的发送使用多线程的情况下,性能就至少翻倍了。可能是为了保证代码的简洁性,作者不愿意使用多线程,为了提升性能用了多线程,也是部分功能使用多线程,操作redis数据库的逻辑还是单线程,如果数据是写少读多的情况下,采用多线程读写锁性能会不会提升很多呢?
所以redis一开始采用单线程的原因:
1:代码简洁又简单 
2:性能已经很好了
3:性能不够我再搞多线程吗
 
3:redis单线程是怎么同时处理文件事件和时间事件
文件事件主要是网络I/O的读写,请求的接收和回复
时间事件就是单次/多次执行的定时器,如主从复制、定时删除过期数据、字典rehash等
redis所有核心功能都是跑在主线程中的,像aof文件落盘操作是在子线程中执行的,那么在高并发情况下它是怎么做到高性能的呢?
由于这两种事件在同一个线程中执行,就会出现互相影响的问题,如时间事件到了还在等待/执行文件事件,或者文件事件已经就绪却在执行时间事件,这就是单线程的缺点,所以在实现上要将这些影响降到最低。那么redis是怎么实现的呢?
 
定时执行的时间事件保存在一个链表中,由于链表中任务没有按照执行时间排序,所以每次需要扫描单链表,找到最近需要执行的任务,时间复杂度是O(N),redis敢这么实现就是因为这个链表很短,大部分定时任务都是在serverCron方法中被调用。从现在开始到最近需要执行的任务的开始时间,时长定位T,这段时间就是属于文件事件的处理时间,以epoll为例,执行epoll_wait最多等待的时长为T,如果有就绪任务epoll会返回所有就绪的网络任务,存在一个数组中,这时我们知道了所有就绪的socket和对应的事件(读、写、错误、挂断),然后就可以接收数据,解析,执行对应的命令函数。
如果最近要执行的定时任务时间已经过了,那么epoll就不会阻塞,直接返回已经就绪的网络事件,即不等待。
总之单线程,定时事件和网络事件还是会互相影响的,正在处理定时事件网络任务来了,正在处理网络事件定时任务的时间到了。所以redis必须保证每个任务的处理时间不能太长。 

聊聊redis单线程为什么能做到高性能和io多路复用到底是个什么鬼的更多相关文章

  1. 为什么 redis 单线程却能支撑高并发

    redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发? 这个是问 redis 的时候,最基本的问题吧,redis 最基本的一个内部原理 ...

  2. 2.redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?

    作者:中华石杉 面试题 redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发? 面试官心理分析 这个是问 redis 的时候,最基本的 ...

  3. redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?

    redis 和 memcached 有啥区别? redis 支持复杂的数据结构 redis 相比 memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作.如果需要缓存能够支持更复杂的结构 ...

  4. 爬虫基础--IO多路复用单线程异步非阻塞

    最近一直的学习爬虫  ,进行基础的学习 性能相关 参考 https://www.cnblogs.com/wupeiqi/p/6229292.html # 目标:单线程实现并发HTTP请求 # # so ...

  5. redis 单线程的理解

    单线程模型 Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程.其中执行命令阶段,由于Redis是单线程来处理命令的,所有每一条到达服务端的命令不会立刻执行,所有的命令都会 ...

  6. 【Redis破障之路】三:Redis单线程架构

    众所周知,Redis是一个单线程架构的NoSQL数据库,但是是单线程模型的Redis为什么性能如此之高?这就是我们接下来要探究学习的内容. 1.Redis的单线程架构 1.1.Redis单线程简介 首 ...

  7. Redis系列:深刻理解高性能Redis的本质

    1 背景 分布式系统绕不开的核心之一的就是数据缓存,有了缓存的支撑,系统的整体吞吐量会有很大的提升.通过使用缓存,我们把频繁查询的数据由磁盘调度到缓存中,保证数据的高效率读写. 当然,除了在内存内运行 ...

  8. 硬核剖析Redis单线程为什么那么快?

    (本文首发于"数据库架构师"公号,订阅"数据库架构师"公号,一起学习数据库技术,助力职业发展) Redis目前是使用率最高的内存库数据库,是企业应用开发的必备, ...

  9. Redis单线程原理

    redis是以socket方式通信,socket服务端可同时接受多个客户端请求连接,也就是说,redis服务同时面对多个redis客户端连接请求,而redis服务本身是单线程运行. 假设,现在有A,B ...

随机推荐

  1. 618购物节要到了,Python帮你实现商品有货的微信提醒

    时间过的真快,不知不觉一年已过了一半,又快到618购物狂欢节了,剁手党们都希望无论是618购物节还是双11购物节,都能够买到便宜又实惠的商品,但是真心实惠的东西往往是紧俏的,经常会出现无货的情况,我们 ...

  2. 解决Xshell 工具连接不上VirtualBox虚拟机

    初次尝试用VirtualBox安装Linux虚拟机,却遇到了一些问题,特地记录于此,方便后面查阅! 首先简易记录下安装Linux虚拟机过程: 大致经过如下步骤:新建虚拟电脑,加载Linux版本镜像安装 ...

  3. git使用-克隆仓库

    1.git clone 克隆地址 克隆地址: 2.克隆命令

  4. 2020-04-18:synchronized和reentrantLock的异同

    福哥答案2020-04-19:采纳群员答案: 1 synchronized是关键字,reentrantlock是类,API层面的2 前者是通过monitor来实现锁机制,后者是基于AQS实现的,通过内 ...

  5. jquary常见问题总结

    如何调用本地json 1. 调用 <script src="solution.json?cb=readData"></script> 2. json 修改 ...

  6. 02树莓派4B—C语言编程——PWM

    01树莓派直接输出PWM波 —— 硬件PWM程序  (推荐使用) #include <stdio.h> #include <wiringPi.h> #include <s ...

  7. P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表

    P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表 题目背景 \(JYY\) 和 \(CX\) 的结婚纪念日即将到来,\(JYY\) 来到萌萌开的礼品店选购纪念礼物. 萌萌的礼品店 ...

  8. 洛谷P1149.火柴棒等式(暴力搜索)

    题目描述 给你n根火柴棍,你可以拼出多少个形如"A+B=C"的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: 注 ...

  9. 对于python装饰器结合递归的进一步理解

    对于python装饰器结合递归的进一步理解 代码如下: import functools def memoize(fn): print('start memoize') known = dict() ...

  10. name 'xrange' is not defined

    出现这个错误是因为examples使用的是Python2 在Python3中,移除了在Python2中的range, 并将 xrange 命名为 range 将代码中的xrange改为range就可以 ...