高并发编程必备知识IO多路复用技术select,poll讲解

简介: 高并发编程必备知识IO多路复用技术select,poll讲解

百万级连接和千万级连接的请求就是通过这些模型来做的

epoll:是nginx底层的机制了,运用事件驱动的方式支持千万级连接,像一些大厂使用的代理服务器就用nginx来做

一、select.poll的原理和优缺点:

上篇文章讲解了unix的五种网络编程模型

1、什么是IO多路复用:

   I/O多路复用,I/O指的是网络I/O,就是客户端请求,到服务端响应,多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程。

   简单来说:就是使用一个或者几个线程处理多个TCP连接,服务器创建线程和时间片的切换是很耗性能的。

   最大优势是减少系统开销小,不必创建过多的进程/线程,也不必维护这些进程/线程。

上面的图中,每一个actor代表一个客户端,每一条线代表10万条请求连接,Linux内核相当于服务器。

然后Linux内核有多个进程/线程去处理连接数,轮询的去处理这些的连接数。IO的多路复用就是这种的意思。

Select:是多路复用的其中一种

基本原理:

   监听文件3类描述符:writefds,readfds和exceptfds,所以在IO多路复用里面有写事件,读事件,异常事件。

在linux里面所有的文件的操作,socket连接都是一个文件描述符,在java编程里面,所有的东西都是对象,在Linux里面一切的东西都是fd,不是百分百,大部分都是这样的。

select的时候会调用一个函数,这个函数会监听用户的30万个连接,监听是否有读和写还有异常事件,调用后select函数会阻塞住,等有数据,可读,可写,或者出现异常,或者超时就会返回。select函数正常返回后,通过遍历30万个连接的请求的数组才能发现哪些句柄发生了事件(来判断哪些是可读或者可写的),来找到就绪的描述符fd,然后进行对应的IO操作。几乎在所有的平台上支持,跨平台支持性好。

这是最原始的多路复用技术。

缺点:

     1):select采用轮询的方式扫描文件描述符,全盘扫描,随着文件描述符FD数量增多而性能下降。因为30万个请求的链接会在用户空间和linux内核空间拷来拷去,是很耗性能的。

     2):每次调用 select(),需要把fd集合从用户态拷贝到内核态,并进行遍历(消息传递都是从内核到用户空间)

     3):最大的缺陷就是单个进程打开的FD有限制,默认是1024(可修改宏定义,但是效率仍然慢)   宏定义:就是java定义的常量      static  final  int MAX_FD=1024000,

所以在select模型支持太多的并发是不可能的,最多有几千个,上万的话性能就会急剧的下降。

poll:

   基本流程:

          select()和poll()系统调用的大体一样,处理多个描述符也是使用轮询的方式,根据描述符的状态进行处理,一样需要把fd集合从用户态拷贝到内核态,并进行遍历

最大的区别是:poll没有最大文件描述符限制(使用链表的方式存储fd,因为链表可以无限的去扩展,单/双向链表都可以无限扩展)

高并发编程必备知识IO多路复用技术-epoll讲解

epoll模型是nginx的模型,nginx底层就可以用这个,可以支持千万级的连接并发

基本原理:在2.6内核中提出的,对比select和poll,epoll更加灵活,没有描述符限制,用户态拷贝到内核只需要一次使用,采用事件通知的方式而不是轮询,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用callback的回调机制来激活对应的fd,然后进行io事件的处理。

优点:

   1):没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,这个最大句柄数是可以查看的,一般是65535,不用去在意它,一般是可以修改的,1G内存大概支持10万个句柄,虽然是65535,但是可以去调整它,一把把它调整成几十万,要支持单机百万连接的话,10G的话16G内存就可以解决了,所以单机解决百万的连接是不难的,只要模型用的对,Linux内核配的对就没问题。但是你要说网路IO阻塞了那是没有办法。

    2):效率提高,使用回调通知而不是轮询的方式,不会随着增加FD的数目的增加而效率下降,前面的两种模型是随着FD的数目增加而下降 。采用回调机制callback

   3):通过callback机制通知,内核和用户空间mmap同一块内存实现,不用拷贝来拷贝去,性能非常高。

当启动linux内核的时候:会涉及到下面三个函数

Linux内核核心函数:是c里面的,poll和select采用的是分别一个函数

         1)epoll_create():在系统启动的时候,在linux内核里面申请一个文件系统:B+树,查找效率非常快,返回epoll对象,也是一个fd

          2)  epoll_ctl():操作epoll对象,在这个对象里面修改添加删除对应的链接fd,在epoll对象里面有100万个链接的话,假如有1万个链接是活跃的,1万个fd会就绪放到一个集合里面去,那么这1万个fd就会有对应的回调函数

          3) epoll_wait():在ctl操作epoll对象的时候,wait就会做对应的处理了。判断并完成对应的io操作,判断这个集合callback是否为空,不为空的话,对集合中的fd都做一个io的操作。

三个函数组成函数组成epoll的高性能,这三个是互相搭配的

缺点:

  编程模型比select/poll复杂

举个例子:100百万个链接,里面有1万个链接是活跃的,在select,poll,epoll三个模型中表现是怎么样的?

在select模型里面:想要支持百万个链接的话,单个进程的话支持1024,在不修改宏定义的情况下该怎么做呢?则需要1000个进程才可以支持100万个连接,1000个进程在一台机器上创建的话给8核16G的话,这时机器会挂掉的,1000个进程每个进程处理1000个连接,cpu是轮询不过来的。性能会特别的差

poll:100万个链接的话,遍历都响应不过来了,还有空间的拷贝消耗大量的资源

epoll:不会遍历整个fd,通过上面的三个函数,第一个函数进行注册,注册好之后,100万个链接进来的时候,有1万个链接活跃,就会操作epoll对象,并绑定一个callback函数,当每一个fd就绪的时候就会触发callback函数,从而调用wait函数进行处理从而完成io的操作。省了两点:不用遍历fd,不用进行内核空间和用户空间之间的拷贝。

相关文章
|
1月前
|
网络协议 安全 Linux
Linux C/C++之IO多路复用(select)
这篇文章主要介绍了TCP的三次握手和四次挥手过程,TCP与UDP的区别,以及如何使用select函数实现IO多路复用,包括服务器监听多个客户端连接和简单聊天室场景的应用示例。
89 0
|
1月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
73 1
Linux C/C++之IO多路复用(aio)
|
1月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
23 0
Linux C/C++之IO多路复用(poll,epoll)
|
1月前
|
Java Linux
【网络】高并发场景处理:线程池和IO多路复用
【网络】高并发场景处理:线程池和IO多路复用
44 2
|
1月前
|
监控 网络协议 Java
IO 多路复用? 什么是 IO 多路复用? 简单示例(日常生活)来解释 IO 多路复用 一看就懂! 大白话,可爱式(傻瓜式)教学! 保你懂!
本文通过日常生活中的简单示例解释了IO多路复用的概念,即一个线程通过监控多个socket来处理多个客户端请求,提高了效率,同时介绍了Linux系统中的select、poll和epoll三种IO多路复用的API。
108 2
|
1月前
|
并行计算 算法 搜索推荐
探索Go语言的高并发编程与性能优化
【10月更文挑战第10天】探索Go语言的高并发编程与性能优化
|
2月前
|
消息中间件 NoSQL Java
面试官:谈谈你对IO多路复用的理解?
面试官:谈谈你对IO多路复用的理解?
46 0
面试官:谈谈你对IO多路复用的理解?
|
1月前
|
Java Linux 应用服务中间件
【编程进阶知识】高并发场景下Bio与Nio的比较及原理示意图
本文介绍了在Linux系统上使用Tomcat部署Java应用程序时,BIO(阻塞I/O)和NIO(非阻塞I/O)在网络编程中的实现和性能差异。BIO采用传统的线程模型,每个连接请求都会创建一个新线程进行处理,导致在高并发场景下存在严重的性能瓶颈,如阻塞等待和线程创建开销大等问题。而NIO则通过事件驱动机制,利用事件注册、事件轮询器和事件通知,实现了更高效的连接管理和数据传输,避免了阻塞和多级数据复制,显著提升了系统的并发处理能力。
56 0
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
4月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用