一、BIO、NIO、AIO特点
1、BIO的特点就是每次一个客户端接入,都要在服务端创建一个线程来服务于这个客户端,所以如果有很多个客户端,就会对应成千上万个服务端线程,这会导致服务端负载过高,甚至卡死。
2、NIO是同步非阻塞io,客户端和服务器端通过channel(通道)通讯,实现了多路复用
- 1.一个客户端会对应一个channel,然后多路复用器selector会轮询channel
- 2. 然后当有请求过来的时候,selector才会去创建工作线程与buffer,
- 3. 工作线程会通过buffer从channel中读取请求并进行处理
- 4. 然后处理完成后再通过buffer将数据返回给channel,当请求读写完成后会释放这个线程
3、AIO是NIO的升级,实现了异步非阻塞,异步IO的操作基于事件和回调机制
二、buffer、channel、selector相关概念
buffer实际上是一个容器,内部通过一个连续的字节数组存储I/O上的数据,在nio中,channel在文件、网络上对数据的读取或是写入都必须通过buffer
selector用于检测在多个注册的channel上是否有I/O事件发生,并对检查到的I/O事件进行相应的相应和处理,因此通过一个selector线程可以实现对多个channel的管理,而不必 每个线程都创建一个线程,避免线程资源的浪费和多线程之间的上下文切换导致的开销。seletor只在channel上有读写事件发生时候,才会调用I/O的函数进行读写操作,可极大的减少系统开销,提高系统的并发量
三、select、poll、epoll
- fd是什么? fd既file descriptor-文件描述符。Java中用对象代表输入输出流等...在Linux系统中不是面向对象的,是一切皆文件的,拿文件来代表输入输出流
- select:它的模式是这样的:程序端每次把文件描述符集合交给select的系统调用,select遍历每个文件描述符后返回那些可以操作的文件描述符,然后程序再次遍历可以操作的文件描述符进行读写。
- poll:以链表来存储文件描述符集合
- epoll:内核通过mmap实现共享空间,用户态和内核态有一个空间是共享的,文件描述符fd存在共享空间实现用户态和内核态共享。epoll里面有三个调用,用户空间先epoll_create准备一个共享空间mmap,里面维护一个红黑树,内核态将连接注册进红黑树,epoll_ctl写入。当有数据准备好了,调用epoll_wait中断阻塞,取链表fd,再单独调用read。mmap应用:kafka实现数据通过socket存到服务器文件上的过程也是mmap。
四、缓存I/O、内存映射文件和零拷贝
- 用户态:用户程序运行在用户态,用户态下有许多限制。比如无法直接操作硬件、创建和切换线程、开辟内存等操作(安全),这些操作都需要通过内核态完成
- 内核态:可直接操作系统硬件资源等,用户态可通过系统调用转换为用户态。比如用户态的io操作、切换线程都是通过系统调用进入内核态通过kernel(内核)完成的
- 对于缓存I/O,一个读操作会有3次数据拷贝,磁盘》内核缓存区》用户缓存区》应用程序内存
- 对于缓存I/O,一个写操作会有3次数据拷贝,应用程序内存》用户缓存区》内核缓存区》磁盘
内存映射文件:当用户不再有物理内存,直接拿应用程序的逻辑内存地址映射到Linux操作系统的内核缓冲区,应用程序虽然读写的是自己的内存,但是这个内存只是一个逻辑地址,实际读写的是内核缓冲区
读:磁盘》内核缓冲区
写: 内核缓冲区》磁盘