Redis之IO线程、IO多路复用,BIO、NIO和AIO区别

参考文章https://blog.csdn.net/Happy_wu/article/details/80052617

redis的线程

redis是单线程操作的,但是却可以处理高并发。原因是基于多路复用的非阻塞IO,基于NIO(non_blocking_io);

redis为什么这么快?

  • 完全基于内存,绝大部分请求是纯粹的内存操作;
  • 数据结构简单,对数据操作也简单,redis中的数据结构是专门进行设计的;
  • 采用单线程,避免了不必要的上下文切换和竞争条件,不用考虑加锁释放锁和死锁的问题;
  • 使用多路复用模型,非阻塞IO;

对多路复用的理解
多路Io复用是利用select、poll、epoll可以同时监察多个流的IO事件的能力,在空闲的时候会把当前线程阻塞,当有一个或多个流由IO事件发生时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll只是轮询那些真正发出了时间的流),并且一次顺序的处理就绪的流。

  • select:服务端一直在轮询、监听如果有客户端链接上来就创建一个连接放到数组A中,继续轮询这个数组,如果在轮询的过程中有客户端发生IO事件就去处理;select只能监视1024个连接(一个进程只能创建1024个文件);而且存在线程安全问题;

深入理解:redis网络编程——Selector模型

  • poll:在select做了许多修复,比如不限制监测的连接数;但是也有线程安全问题;
  • epoll:也是监测IO事件,但是如果发生Io事件,它会告诉你是哪个连接发生了事件,就不用再轮询访问。而且它是线程安全的,但是只有linux平台支持;

IO多路复用(Reactor)

实际上虽然上述方式允许单线程内处理多个IO请求,但是每个IO请求的过程还是阻塞的,平均时间甚至比同步阻塞IO模型还要长,而IO多路复用模型使用了Reactor设计模式实现线程不必阻塞,可以干别的事情,当IO事件触发时,再进行处理。

Reactor设计模式

在这里插入图片描述
EventHandler表示IO事件处理器,它拥有IO文件句柄Handle以及对Handle的操作handle_event。Reactor用于管理EventHandler进行注册删除,并使用handle_events实现事件循环,不断调用同步时间多路分离器的多路分离函数select,只要某个文件句柄被激活,select就返回(阻塞),handle_events就会与文件句柄关联的事件处理器的handle_event进行相关操作。

在这里插入图片描述
将用户线程轮询的IO操作状态的工作统一交给handle_events事件循环进行处理,用户线程注册事件处理器之后可以继续执行其他工作,而Reactor线程负责返回select函数检查socket状态,当有socket被激活石,则通知相应用户线程执行handle_event进行数据读取处理工作。

如何结合事件模型使用NIO同步非阻塞特性

在NIO中如果一个连接不能读写,我们可以把这件事记下来,记录方式是在Selector上注册标记位,然后切换到其他就绪的连接继续进行读写。

NIO中的主要事件: 读就绪、写就绪、有新的连接到来;
我们首先需要注册当这几个时间到来的时候所对应的处理器,然后在合适的时机告诉事件选择器:我们对这个事件感兴趣。
对于写操作,就是写不出去的时候对写事件感兴趣;
对于读操作,就是完成连接和系统没有办法承载新读入的数据时;
对于accept,一般是服务器刚启动时;
对于connect,一般是connect失败需要重新连接或者直接异步调用时;

对BIO、NIO和AIO的概念解析

所有的系统IO都分为两个阶段:等待就绪和操作。例如:读函数分为等待系统可读和真正的读;同理,写函数分为等待网卡可写和真正的写。

可以将这三种IO的特点概括为:

  • BIO里用户最关心"我要读";我要一直等在这处理处理时间;
  • NIO里用户最关心"我可以读了";我不在这等了,如果有事件发生,你就通知我,我再来处理;
  • AIO里用户最关心"读完了";你帮我处理吧,处理完了通知我。

BIO
Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
每一个线程守着一个IO通道,当没有IO时这个线程就阻塞着,一旦有IO事件发生,这个线程就开始工作

缺点
严重依赖线程:

  • 线程的创建和销毁成本很高;
  • 线程本身占用较大内存;
  • 线程切换成本很高;
  • 容易造成锯齿状的系统负载;

Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。socket主要的读、写、注册和接受函数,在等待就绪阶段都是非阻塞的,真正的IO操作是同步阻塞的。
将每个连接(IO通道)都注册到Selector多路复用器上,告诉复用器我已经连接了,如果有IO事件发生,你就通知我。Selector就不断地调用select函数,去访问每一个通道看那个通道有IO事件发生,如果发生了就通知,内核开启一个对应事件的线程去工作

Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。

Reactor和Proactor

Reactor模式是基于同步IO的,而Proactor模式是基于异步IO相关的

Reactor

  1. 某个事件处理者宣称它对某个socket上的读事件很感兴趣;
  2. 事件分离者等待这个时间的发生;
  3. 当事件发生了,事件分离者被唤醒,负责通知先前那个事件处理者;
  4. 事件处理着收到消息,于是去那个socket上读数据了;
  5. 如果需要,它将再次宣称对这个socket上的读事件感兴趣,一直重复上面的步骤。

Proactor

  1. 事件处理者直接投递发一个写操作;
  2. 这个时候,事件处理者根本不关心写事件,它只管发这么个请求,它魂牵梦萦的是这个鞋操作的完成事件;
  3. 它发个命令不管具体的事情了。只等着比人帮他搞定的时候给他回个话;
  4. 事件分离者等着这个写事件的完成;
  5. 当事件分离者默默的等待完成事件到来的同时,操作系统已经开始干活了,它从目标读取数据,放入用户提供的缓冲区,最后通知事件分离者,这个事情我干完了;
  6. 事件分离者通知之前的事件处理者,你吩咐的事情搞定了;
  7. 事件处理者这时会发现想要读的书已经放在它提供的缓冲区了,想怎么处理都行;
  8. 如果有需要,事件处理者还像之前一样发起另一个写操作,重复上面的步骤。

NIO存在的问题

  • 连接数较小的时候,优势不明显;
  • 没有完全屏蔽平台差异,仍然是基于各操作系统的IO系统实现的。建议使用成熟的NIO框架,Netty、MINA等。

对阻塞、非阻塞、同步、异步的理解

参考文章:https://blog.csdn.net/ty497122758/article/details/78979302
以银行取款为例:

  • 同步:自己亲自(用户线程)持银行卡取钱;
  • 异步:委托朋友(OS)拿着你的银行卡和密码(数据缓冲区地址和大小)去取钱;
  • 阻塞:ATM排队取款,只能等待;
  • 非阻塞: 柜台取款,取个号,然后坐在椅子上做其它事,等号广播会通知你办理,没到号你就不能去,你可以不断问大堂经理排到了没有,大堂经理如果说还没到你就不能去(使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器会通知可读写时再继续进行读写,不断循环直到读写完成)。

一个IO操作实际上是被分为两步的,就拿处理网络数据来说。第一步:发起IO请求,第二部实际的IO操作。
阻塞IO和非阻塞IO的区别在于第一步;发起IO请求线程是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO;否则就是非阻塞IO;
同步IO和非同步IO的区别在于第二步;如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO复用都是同步IO;如果不阻塞,而是由操作系统帮你做完再将结果返回给你,那么就是异步IO

当有一个read操作发生时,会经过以下流程

第一步:

  1. 通过read系统调用想内核发起读请求
  2. 内核想硬件发送读指令,并等待读就绪

第二步:
3. 内核把将要读取的数据复制到描述符所指向的内核缓冲区中
4. 将数据从内核缓冲区拷贝到用户进程空间中

  • 8
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值