高并发IO底层理解

IO读写基础

应用层在进行read,write系统调用时,不是物理级别的读写,而是缓存的复制,进程缓冲区同内核缓冲区的缓存复制,底层数据交换是有由操作系统内核完成,控制内核缓冲与硬件(物理设备)之间数据交换.linux系统在系统内核只有一个内核缓冲区,用户进程都有独立的缓冲区,是进程缓冲区。外部设备的直接读写涉及操作系统的中断,底层操作会对内核缓冲区进行监控,等待缓冲区达到一定数量的时候,再进行IO设备的中断处理,集中执行物理设备的实际IO操作,这种机制提升了系统的性能,至于什么时候中断(读中断、写中断),由操作系统的内核来决定,用户程序则不需要关心.

四种主要的IO模型

1、同步阻塞IO:      在内核进行IO执行的两个阶段,用户线程都被阻塞,在阻塞期间,用户线程基本不会占用CPU资源,但在高并发场景下不可采用.

 2、同步非阻塞IO: 不断的进行IO系统调用,轮询数据状态,用户线程不会阻塞,会占用大量的CPU时间,在高并发场景下,也不采可.简称NIO.

3、 IO多路复用:

系统调用,一种是select/epoll(就绪查询),一种是IO操作,轮询查找出达到IO操作就绪的socket连,一个选择器查询线程可处理成千上万个连接,不必创建维护大量线程,减小系统开销,缺点>select/epoll系统调用是阻塞式的,属于同步IO.都需要在读写事件就绪后,由系统调用本身负责进行读写,也就是说这个读写过程是阻塞的。

4、异步IO:AIO

在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的。用户线程需要接收内核的IO操作完成的事件,或者用户线程需要注册一个IO操作完成的回调函数。异步IO有时也被称为信号驱动IO.缺点>应用程序仅需要进行事件的注册与接收,其余的工作都留给了操作系统,即需要底层内核提供支持。目前Windows系统下通过IOCP实现了真正的异步IO,在linux系统中还不太完善。

高并发连接数配置

在生产环境Linux系统中,基本上都需要解除文件句柄数的限制。文件句柄,也叫文件描述符。文件描述符(File Descriptor)是内核为了高效管理已被打开的文件所创建的索引,它是一个非负整数(通常是小整数),用于指代被打开的文件。所有的IO系统调用,包括socket的读写调用,都是通过文件描述符完成的。

用ulimit命令,查看单个进程能够打开的最大文件句柄数量

ulimit -n

一个高并发的应用,并发连接数可以达到数十万百万千万级别,文件句柄数不够,当单个进程打开的文件句柄数量,超过了系统配置的上限值时,会发出“Socket/File:Can't open so many files”的错误提示。

可以通过ulimit来设置这两个参数, 注意ulimit只能作为临时修改,系统重启后,句柄数量又会恢复为默认值

ulimit -n 1000000

永久修改配置,可以编辑 /etc/rc.local 开机启动文件,在文件中添加如下内容,选项-S表示软性极限值,-H表示硬性极限值

ulimit -SHn 1000000

终极解除Linux系统的最大文件打开数量的限制,编辑Linux的极限配置文件/etc/security/limits.conf来解决,加入如下内容

#软性极限
soft nofile 1000000
#硬性极限
hard nofile 1000000

软性极限是系统警告(Warning)的极限值,超过这个极限值,内核会发出警告。

小结:

学习理解了低层IO操作的2个阶段:等待数据和复制数据。加深了对四种主要IO模型的理解掌握,前3种都是同步IO,因为实际IO操作都会阻塞应用的线程。仅第四种是真正的异步IO,但是依赖于系统内核的支持。这些内容为学习Netty这个优秀框架打下良好的理论基础。

书籍阅读:《Netty、redis、zookeeper高并发实战 》  尼恩

额外理解参考: 

    http://byteliu.com/2017/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BAIO/

    https://juejin.im/post/5cd50e07f265da03ab2343d3

猜你喜欢

转载自www.cnblogs.com/wangrq/p/IO-opration.html