Redis之epoll和IO多用复用

  • Post author:
  • Post category:其他


一、redsi的IO多路复用

redis利用epoll来实现IO多路复用,将连接信息和事件放入队列中,一次放到文件事件分派器,事件分派器将事件分发给事件处理器。

IO多路复用,使用的是linux内核函数,它的使用有三种select、poll、epoll,redis使用的就是epoll进行实现。

在redis中,多个客户端同时进行连接,redis使用epoll,把各个客户端的事件放到队列中,然后又事件派发器找到对应的工作单元。

IO多路复用解决就是防止一个读写导致整个进程的阻塞

Redis服务采用Reactor的方式来实现文件事件处理器,它的组成有4个部分:

  • 多个套接字
  • IO多路复用程序
  • 文件事件分派器
  • 事件处理器


因为文件事件分派器队列的消费是单线程的,所以redis才叫单线程模型。


IO就网络IO,复用是多个连接、复用就一个或一组线程处理TCP连接,总结一句话就是一个服务进程可以同时处理多个套接字描述符(FD)。

二、同步\异步和阻塞\非阻塞

1、同步\异步

  • 同步:调用者需要等待结果,才能执行后续操作
  • 异步:是指被调用者返回应答结果,先让调用者回去,然后在处理结果,完成后在通知调用者

同步、异步的讨论对象是被调用者,重点在于获得调用结果的消息通知上。

2、阻塞\非阻塞

  • 阻塞:调用者一直等待切别的事情都不做,当前线程会被挂起,什么都不处理
  • 非阻塞:调用发出后,调用者放去忙其它事情,不会阻塞当前线程,而立即返回

阻塞、非阻塞讨论的对象时调用者,重点在于等待消息时候的行为,调用者是否能干其它的事情

3、四种模型

拿客户去海底捞吃饭举例:

  • 同步阻塞:服务员说快到了,需要等待,客户在等的时候什么都不干
  • 同步非阻塞:服务员说快到了,需要等待,客户玩手机等待
  • 异步阻塞:服务员说,需要等等可以去逛街,但是客户在等待什么都不干
  • 异步非阻塞:服务员说,需要等等可以去逛街,客户玩手机等待服务员通知

其实就是调用者和被调用者中间干什么的讨论。

三、Linux的五种IO模型

1、Blocking IO(BIO)

BIO的特点,就是在执行过程中的两个阶段,都被block了。也就是调用者(套接字)、被调用者(系统内核)都是阻塞的。

阻塞位置:

  • 服务端:accpet()函数
  • 服务端读取客户端:read()函数

缺点:

  • 使用多线程,会导致每次过来客户端都会启动一个线程
  • 线程的上下文切换消费性能

2、NoneBlocking IO(NIO)

NIO中一切都是非阻塞的。

accpet()是非阻塞的,没有客户端连接就返回error。

read()是非阻塞的,读取不到数据,就返回error,在处理读取到的数据时候是阻塞的。

在NIO模式下,线程只有一个:

当客户端和服务端连接,这个socket就会加入到数组中,隔一段时间遍历一次,看到这个socket的read()方法是否能读取到数据,这样就可以一个线程处理多个请求的连接和读取了。

当用户进程发起read操作的时候,如果内核中数据还没准备,它并不会blokcing用户进程,而是返回一个error,所以用户进程不需要等地,但是用户进程需要不断的主动向内核询问是否准备好数据了。

缺点:

  • 连接很多的时候,数组容量很大,如果存在100个,其中99个都是没有数据的,但是还要遍历
  • 每次遍历都存在用户态和内核态的切换,开销很大

3、IO multipexing(IO多路复用)

IO多路复用就是常说的select、poll、epoll,有些地方也称为事件驱动IO,就是通过一致机制,一个进程监听多个描述符,一旦某个描述符就绪(就绪状态),就能够通知用户程序进行读写操作(循环监听放在了内核中进行)。

IO多路复用,复用是指在单个线程通过记录跟踪每个scoket的状态来管理IO流,目的就是为了尽量多的提高服务器的吞吐能力。

Reactor模式,是指通过一个或多个输入同时传递给服务处理器的服务请求的时间驱动处理模式。并把她们分派给对应的应用处理器。即IO多了复用统一监听事件,收到事件后分发给处理程序。

Linux内核的三种实现:

  • select:

    • 流程:

      • select是一个阻塞函数
      • 当有数据的时候,会对应位置设置为1
      • select返回,不在监听
      • 遍历文件描述符fd,判断哪个位置被设置了
      • 返回数据
    • 优点:

      • 把遍历放入的内核中
      • 使用类似bitmap的方式记录哪个fd有可读数据
    • 缺点:

      • bitmap只有1024
      • rset每次重置为0
      • 依然存在用户拷贝内核态的卡小
      • 存在可读数据的时候,还是需要遍历fd,时间复杂度n(O)
  • poll:

    • 解决问题:

      • 解决了bitmap1024问题
      • 解决了rset不可复用的问题
    • 缺点:

      • 通select后两点的问题一样
  • epoll:

    • 三大函数:

      • epoll_create:创建一个句柄
      • epoll_ctl:增加要监听的文件描述符
      • epoll_wait:发起类似select方法的调用
    • 流程:把需要读写的fd放在就绪列表中,直接遍历直接需要处理的fd

4、信号驱动和异步IO

和redis关系不大,所以不在说明。

总结:



版权声明:本文为liming0025原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。