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. 100例Python代码带你从入门到进阶!

    以下所有代码全都至少运行一遍,确保可复现.易于理解.逐步完成入门到进阶的学习. 此教程经过我 反复打磨多遍 ,经常为此熬夜,真心不易,文章比较长,看完有用,帮我点个在看或分享支持. 教程包括 62 个 ...

  2. javascript 字符串对象

    数组转换字符串     tostring() 将数组转换成字符串     join(分隔符)将数组转换成字符串     基本包装类型     基本包装类型 就是把简单数据类型 包装成繁杂数据类型    ...

  3. Navicat Premium 安装破解

    软件官网 : https://www.navicat.com.cn/ Navicat Premium 12 下载地址:https://www.lanzous.com/i9j0syf 密码:7pup N ...

  4. 程序员必须了解!IntelliJ IDEA 2020.2的新增功能

    IDEA 因为之前破解过,所以家里的电脑都是19版本的,用的也比较顺手,也就一直懒得去动他,但是,程序猿的好奇心可能真的挺重,猎奇心里,在网上也看到了很多关于2020版本的idea的各种好处,于是,闲 ...

  5. 2020-07-06:一个6亿的表a,一个3亿的表b,通过外间tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录

    福哥答案2020-07-06:表a和表b的字段都是id和tid,数据类型都是int.查询结果顺序上以 表a 为准.1.JOIN.SELECT * FROM a JOIN b ON a.tid = b. ...

  6. 免费深度学习GPU,Google Yes!

    深度学习越加火热,但是,很多实验室并没有配套的硬件设备,让贫穷的学生党头大 经过网上大量的搜罗,我整理了适合学生党的深度学习解决方案.利用Colab + Kaggle两大免费的GPU环境,让深度学习变 ...

  7. LeetCode 647. Palindromic Substrings的三种解法

    转载地址 https://www.cnblogs.com/AlvinZH/p/8527668.html#_label5 题目详情 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串. 具有不同 ...

  8. 为 Eureka 添加 Http Basic 认证

    简介 在网络世界中,任何网络中的服务都是不安全的,为了使我们的 Eureka 服务更加安全,我们可以添加各种各样的认证方式,以使客户端在提供相应的证明之后才能够注册到 Eureka 中.而这次我们就添 ...

  9. IDEA创建聚合项目

    1.新建一个空工程 2.新建Modul New-->Modul 3.选择maven(不选模板,放在工程下) 4.选择依赖 <project xmlns="http://maven ...

  10. 不安装证书如何通过模拟器+Fiddler抓包APP的HTTPS请求?

    模拟器抓取https方法 说明:为了解决安卓手线上不能抓取https请求,以下整理通过模拟器抓取https请求方法如下:前置条件:安卓模拟器:夜神抓包工具:Fiddler汉化中文升级版1无需FIDDL ...