美文网首页
4.1 网络IO模型以及Redis的实现

4.1 网络IO模型以及Redis的实现

作者: MelodyOf流沙 | 来源:发表于2021-03-29 18:56 被阅读0次

网络IO模型通过内核的不断升级,现在已经有5种模式,这5种模式各有利弊。

五种IO模型

阻塞IO

监听一个fd,传递给内核,然后阻塞等待,内核发现此fd有事件产生时返回fd以及事件

非阻塞IO

监听一个fd,传递给内核,然后不管fd是否有事件发生,直接返回处理其他事件,但会一直轮询问内核是否fd有事件发生.这样用户空间一直对系统调用,造成cpu资源浪费,减低效率

异步IO

当前只有windows的iocp属于异步io。异步io必须满足2个条件:

  1. 内核到用户空间是无阻塞的。
  2. 硬件到内核是无阻塞的
    而其他IO模型内核空间拷贝数据到用户态是阻塞的,只有iocp是系统内核执行完成后才告知用户。
信号驱动IO

监听一个fd,传递给内核,非阻塞,后续内核收到此fd事件变化,发送一个信号给用户。

多路复用IO

前面的这些IO模型都是监听一个fd,如果系统有100万个连接,那么则需要去实现100万个线程去监听这些IO,这样对系统来说肯定是并发很低的。我们为了解决这个问题,产生了多路复用IO,也就是说,一次性监听多个fd,然后内核发现fd这些fd的某些有事件触发,则返回。对于这种模型linux有3种实现方式

  • select
// readfds:关心读的fd集合;writefds:关心写的fd集合;excepttfds:异常的fd集合  
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);  

传递3个不同事件监听类型fd数组下去,然后内核对这些数据进行for循环。如果对应数组有对应事件产生,则返回通知,如果timeout内没有任何事件,会告诉超时。时间复杂度比较高,是O(n)。
select基本所有平台都支持,但是select缺点除了时间复杂度以外,还有只支持最大连接数1024,如果要修改这个连接数,需要修改常量后重新编译内核。

  • poll
int poll (struct pollfd *fds, unsigned int nfds, int timeout);  
  
struct pollfd {  
    int fd; /* file descriptor */  
    short events; /* requested events to watch */  
    short revents; /* returned events witnessed */  
};  

poll传递的参数是一个fd以及events在一起的结构体数组。在内核也是对这个数据进行for循环,遍历查看是否有对应事件产生。但是这个是没有最大连接数的限制的。

从上面看,select 和 poll 都需要在返回后,通过遍历文件描述符来获取已经就绪的 socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。比如我有100万的连接数,但当前活跃的可能只有1000个,但是select和poll都需要遍历100万次,对效率大打折扣

  • epoll
//创建epollFd,底层是在内核态分配一段区域,底层数据结构红黑树+双向链表  
int epoll_create(int size);//创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大  
  
//往红黑树中增加、删除、更新管理的socket fd  
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);  
  
//这个api是用来在第一阶段阻塞,等待就绪的fd。  
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);  

epoll对fd的监听模式有2种可以选择,LT以及ET

  • LT 水平触发
    无论fd是否发生变化,每次都会告知用户态当前fd的状态如何
  • ET 边缘触发
    只有fd发生变化,才会告知用户态,告知之后,下一次不会再告诉当前fd的状态信息

Reactor模型介绍

Reactor模型指在使用多路复用IO时,对于用户态fd的事件管理模型

Reactor单线程模型

业务逻辑处理和fd的读写IO都在同一个线程实现

Reactor多线程模型

业务逻辑处理和fd的读写IO不在同一个线程实现

multi-reactor 多线程模型

业务处理多线程以及读写IO的事件分发机制也采用多线程处理

Redis的网络IO模型

Redis采用单线程为何支持高并发
  • Redis使用的内存IO,不是磁盘IO,大大降低了IO时间
  • Redis单线程,无需去考虑多线程造成的死锁问题
  • Redis单线程,底层网络IO模型使用多路复用epoll方式(如果内核不支持epoll,可自动切换到select或者poll,看配置信息可进行修改)
Redis6实现了多线程,作用是什么

Redis6实现的多线程,只是对网络IO读写处理做多线程处理,但是对命令行的操作仍然是单线程的。这样即加快了IO处理效率,又保证了原子性。

相关文章

  • 4.1 网络IO模型以及Redis的实现

    网络IO模型通过内核的不断升级,现在已经有5种模式,这5种模式各有利弊。 五种IO模型 阻塞IO 监听一个fd,传...

  • Redis深度历险-IO模型

    Redis深度历险-IO模型 Redis是单进程单线程实现的服务器,网络并发还是值得学习一下的,本文在Redis6...

  • 【问答】Redis

    Memcache和Redis的区别?Redis和memcached 的内存管理的区别? 网络IO模型:Memcac...

  • Redis 小记

    网络 IO 模型 redis 采用 io 多路复用,默认采用 epoll 方式,也提供了 kqueue、selec...

  • Redis VS Memcache 区别

    网络IO模型 性能对比:(占用的核数,线程数,网络模型) 性能对比:由于Redis只使用单核,而Memcached...

  • Redis学习之旅~原理篇

    内容依旧来自 核心原理 线程IO模型 单线程非阻塞IO redis是单线程模型。redis的...

  • redis为什么性能高?

    存内存访问,速度高 非阻塞IO,Redis使用epoll作为I/O多路复用技术的实现。redis自身的事件处理模型...

  • 要记得

    redis 1,redis是一个单线程的高性能缓存数据库,redis底层采用网络io的多路复用(事件驱动模型)来监...

  • 1.Nette入门第一章——IO演进

    1. IO 基础 1.1. linux网络IO模型 阻塞IO模型 非阻塞IO模型 IO多路复用模型(NIO) 信...

  • 网络IO模型

    网络IO的模型大致包括下面几种 同步模型(synchronous IO)阻塞IO(bloking IO)非阻塞IO...

网友评论

      本文标题:4.1 网络IO模型以及Redis的实现

      本文链接:https://www.haomeiwen.com/subject/aehrhltx.html