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. 嵌入式linux系统应用开发

    关于嵌入式系统   平时大家说的嵌入式其实范围比较广的,是一种软硬件可裁剪,以应用为中心开发的专用系统,硬件平台可以是单片机,或者以ARM系列的处理器.单片机一般直接裸奔程序,不过现在有了好多基于单片 ...

  2. 【JVM】JVM优化过程全记录

    请大神移步:https://segmentfault.com/a/1190000010510968?utm_source=tuicool&utm_medium=referral 今天看JVM群 ...

  3. Linux Centos 下安装npm 实测可用

    转载地址 https://blog.csdn.net/u012129607/article/details/60966045 1.root 登录linux 2.没有目录就自己创建一个 cd /usr/ ...

  4. golang 复数

    目录 1.声明/赋值/初始化 2.类型 3.取虚实部数值 4.运算 5.注意 跳转 1.声明/赋值/初始化 var name complex128 =complex(x,v) name := comp ...

  5. HTML实例-02-京东顶部导航条

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. Java基于SSM的个人博客系统(源码 包含前后台)

    @ 目录 系统简介 系统运行截图 核心代码 写在最后 系统简介 技术点:Java.JSP.SSM框架,实现了个人博客系统 用户角色分为:普通用户.管理员.系统管理员 功能:发博客.博客分类.博客删除. ...

  7. Redis设计与实现——多机数据库的实现

    复制 旧版Redis的复制功能分为同步(sync)和命令传播两个操作. sync:是一个非常耗费资源的操作                                           命令传播 ...

  8. Ng-Matero V10 正式发布!

    Angular v10 在六月下旬就悄无声息的发布了,虽然 v9 的发布延期了两个月,但是 v10 并没有受影响,仍然如期而至. 相比 v9 的重量级发布,v10 并没有颠覆性的变化,主要还是 bug ...

  9. Fiddler+模拟器+APP抓包HTTPS 为什么有时候抓不到?

    抓包的原理是什么? 代理 客户端请求 -> 经过代理 -> 到达服务端 服务端返回 -> 经过代理 -> 到达客户端 任何Https的App都能抓到包么? Android7.0 ...

  10. python 11 类与对象

    给大家介绍对象hhhh 封装 举个例子,把乱七八糟的数据仍到列表,数据层面的封装 把常用的代码打包成一个函数,封装 外观特征(静态) 能做什么(动态) 对象=属性(静态) + 方法(动态) 1.方法多 ...