这是小小国庆节更新的第一篇,小小本篇将会更新Redis原理应用,线程IO模型。

送书反馈

小小送的书到啦,一共三本书,晒图如下。
打卡学习 | Redis原理应用-线程IO模型插图
打卡学习 | Redis原理应用-线程IO模型插图(1)
打卡学习 | Redis原理应用-线程IO模型插图(2)

小小开始今天的文章,跟我学Redis系列之,Redis原理应用之,线程IO模型。

总说

Redis是个单线程程序,正是因为其单线程,才能确保Redis做到快,相当的快,相当相当的快。
既然Redis是单线程,如何处理高并发呢,那就是多路复用这个概念,通过select系列的事件轮询api,以及非阻塞IO实现Redis的单线程应用的高可用化。

非阻塞IO

打卡学习 | Redis原理应用-线程IO模型插图(3)
应用程序中进程在发起IO调用后到内核执行IO操作返回结果之前,若发起系统调用的线程不会等待而是立刻返回,则此次IO操作为非阻塞IO模型,非阻塞IO简称为NIO

调用过程

进程发起IO系统调用后,如果内核缓冲区没有数据,需要到IO设备中读取,进程会返回一个错误而不会被阻塞,进程发起IO系统调用后,如果内核缓冲区内有数据,内核就会把数据返回给进程。
在上面的阻塞IO模型来说,内核数据没有准备好需要进程阻塞的时候,就会返回一个错误,使得进程不被阻塞。

特点

  1. 进程重复调用,消耗CPU资源。
  2. 实现难度低,开发应用相对较难
  3. 适用并发量小,不需要及时响应网络应用开发。

IO多路复用模型

打卡学习 | Redis原理应用-线程IO模型插图(4)
select是内核提供的系统调用,支持一次查询多个系统调用的可用状态,当任意一个结果状态可用的时候就会返回,用户进程会再一次发起一次系统调用进行数据的读取,即,NIO中N次系统调用,借助select只需要发起一次系统调用就可以实现了。流程如上图所示。

原理

多个进程的IO可以注册到一个复用器上,然后用一个进程调用该select,select会监听所有注册进来的IO
如果select没有监听的IO在内核缓冲区都没有可读的数据的时候,select调用进程会被阻塞,而当任一IO在内核缓冲区中有可用数据的时候,select调用就会返回。
而后select调用进程可以自己或者通知另外的进程来再次发起读取IO,读取内核中准备好的数据。
可以看到,多个进程注册IO后,只有另一个select调用进程会被阻塞。

应用

select poll epoll nginx可以选择的三个方案,javaNIO

特点

专一进程解决多个进程IO的阻塞问题,性能好,Reactor模式
实现,开发难度大,适用高并发服务器应用开发。一个进程(线程)响应多个请求。

指令队列

Redis会将每个客户端套接字都关联一个指令队列,客户端的指令通过队列来进行顺序处理,先到先服务。

响应队列

和Redis指令队列类似,为客户端的套接字关联一个响应队列,Redis服务器通过响应队列,把指令的返回结果返回给客户端,如果队列为空,意味着连接处于空闲状态,不需要获取事件,如果队列有数据,可以再次调用select,触发相应的事件

定时任务

 服务器除了响应IO事件外,还要处理其他任务,比如定时任务。但是当线程处于一个事件循环中,处于阻塞状态,怎样准确调度定时任务呢?

  Redis会将定时任务记录在最小堆中,最近的一个定时任务将在堆的最上方。每个事件循环周期Redis线程都会执行当前的定时任务,在进入下一个事件循环时,将记录下一个最近的定时任务时间,并且将时间差设置为timeout时间。这样子Redis就知道,在timeout时间内没有其他定时任务要做,因此可以安心的阻塞在事件循环中。

  Nginx和Node.js的事件处理原理和Redis类似。