网络IO
2024-01-10 15:37:05 7 举报
AI智能生成
网络IO,即输入/输出操作,是计算机系统中用于处理数据流的关键过程。它涉及将数据从一个地方传输到另一个地方,例如从硬盘读取文件或将数据发送到互联网。网络IO的速度和效率对系统性能至关重要,因为它直接影响到应用程序的响应时间和用户体验。为了提高网络IO性能,可以采取多种策略,如优化硬件设备、调整操作系统设置和使用高性能的网络协议。总之,网络IO是现代计算机系统中不可或缺的一部分,对于确保数据的快速传输和处理具有重要意义。
作者其他创作
大纲/内容
这是一种最传统的一种IO模型,即在读写数据过程中会发生阻塞现象也是最简单的IO模型,一般表现为进程或县城等待某个条件,如果条件不满足,则一直等待下去,如果条件满足,则进行下一步操作应用进程通过系统调用recvfrom接收数据,但由于内核还没准备好数据,应用进程就会阻塞,知道内核准备好数据,recvfrom完成数据报的复制工作,应用进程才能结束阻塞状态
模型图
1.阻塞IO模型
2.非阻塞IO模型
应用进程预先向内核注册一个信号处理函数然后用户进程不阻塞直接返回,当内核数据准备就绪时会发送一个信号给进程,用户进程在信号处理函数中把数据复制到用户空间,实现比较复杂
3.信号驱动IO模型
多个进程的IO可以注册到同一个管道上,这个管道会统一和内核进行交互当管道中的某一个请求需要的数据准备好之后,进程再把对应的数据复制到用户空间IO多路转接是多了一个select函数,多个进程的IO可以注册到同一个select上,当用户进程调用该select时select会监听所有注册好的IO,如果所有被监听的IO需要的数据都没有准备好,那么select调用进程会阻塞当任意一个IO所需要的数据准备好之后,select调用就会返回,然后进程通过recvfrom实现数据复制这里并没有向内核注册信号处理函数,所以IO复用模型并不是非阻塞的,进程在发出select后要等select监听的所有IO操作中至少一个需要的数据准备好,才会由返回值,并且需要再次发送请求去执行文件的复制阻塞IO模型,非阻塞IO模型,IO复用模型和信号驱动IO模型都是同步的IO模型,因为无论哪种模型真正的数据复制过程都是同步进行的
核心源码
1.支持性比较好.几乎所有的操作系统都能支持
2.模型比较简单
优点
3.如果并发数量比较少,可以使用原生阻塞式的连接方式,相比原生的recvfrom的方式,select多了一次系统调用,多一次用户态和内核态的切换
缺点
select
1.数组结构改为链表形式,突破了select函数中的宏定义的1024数量限制,
1.和select一样,需要遍历轮询,因为无法准确地知道哪个socket当中有数据
poll
只要文件描述符关联的读内核缓冲区非空,有数据可以读取,就一直发出可读信号进行通知,当文件描述符关联的内核写缓冲区不满,有空间可以写入,就一直发出可写信号进行通知,epoll默认模式是水平触发
水平触发
当文件描述符关联的读内核缓冲区非空时,则发出可读信号进行通知,写缓冲区不满时,则发出可写信号进行通知,边缘触发只会通知一次
两者区别:当有数据可读时,水平触发会一直通知epoll对象告诉我们有数据可以读,触发epoll_wait系统调用,如果我们上一次的socket还没处理完毕,则会造成该系统调用的阻塞,消耗CPU,但是如果我们先让数据留存在缓冲区,等这次epoll_wait处理完毕之后,再去读,此时也有可能不止一个socket中有数据,我们可以一次性读取多个socket,效率比较高
边缘触发
向内核注册一定数量的fd,该数量只是一个建议
epoll_create
epoll_ctl
epoll_wait
监听所有的socket连接,需要快速插入和删除,还要搜索socket以避免重复添加再加上数量比较多,所以采用了红黑树结构,搜索和插入删除的事件复杂度都是O(logN)
rbr维护需要监听的socket,保存需要监视的socket,需要快速地添加删除,底层是红黑树
eventpoll对象
伪代码
epoll
4.IO多路复用模型
应用进程把IO请求传给内核后,完全由内核去完成文件的复制。内核完成相关操作后,会发送信号告诉应用进程本次IO操作已经完成用户进程发起aio_read操作之后,给内核传递描述符、缓冲区指针、缓冲区大小等告诉内核当整个操作完成时,如何通知进程,然后就立刻去做其他事情了,当内核收到aio_read后会立刻返回,然后开始等待数据准备,数据准备好之后,直接把数据复制到用户空间,然后通知本次IO操作已经完成
暂时还没有完全支持,还是借用了IO多路复用的方式实现的
Linux
利用IOCP模型去实现
Windows
5.异步IO模型
Linux下五种IO模型
当网卡上收到数据以后,Linux中第一个工作的模块是网络驱动,网络驱动会以DMA的方式把网卡上收到的帧写到内存里。再向CPU发起一个中断,以通知CPU有数据到达第二,当CPU收到中断请求后,回去调用网络驱动注册的中断处理函数。网卡的中断处理函数并不做过多工作,发出软中断请求,然后尽快释放CPU.ksoftirqd检测到有软中断请求到达,调用poll开始轮询收包,收到后交由各级协议栈处理,最后会被放到用户socket的接收队列中
中断、上半部、下半部
CPU是如何知道网卡中有数据需要接收内核是怎样接收数据的
了解epoll本质,要从操作系统进程调度的角度来看数据接收阻塞是进程调度的关键一环,指的是进程在等待某事件(如接收到网络数据)发生之前的等待状态,recv、select和epoll都是阻塞方法。了解\"进程阻塞为什么不占用CPU资源\
操作系统添加等待队列只是添加了对这个\"等待中\"进程的引用,以便在接收到数据时获取进程对象、将其唤醒,而非直接将进程管理纳入自己之下,直接将进程挂到等待队列之下当socket接收到数据后,操作系统将该socket等待队列上的进程重新放回到工作队列该进程变成运行状态,继续执行代码,也由于socket的接收缓冲区已经有了数据,recv可以返回接收到的数据
进程阻塞
操作系统的IO
该技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽1.零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之前不必要的中间拷贝次数,从而有效地提高数据传输效率2.零拷贝技术减少了用户进程地址空间和内核地址空间之间因为上下文切换而带来的开销可以看出没有说不需要拷贝,指示说减少冗余[不必要]的拷贝Kafka、Netty、RocketMQ、Nginx均使用了零拷贝技术目的:减少IO流程中不必要的拷贝,当然零拷贝需要OS支持,也就是需要kernel暴露API
什么是零拷贝Zero-copy
在早期计算机中,用户进程需要读取磁盘数据,需要CPU终端和CPU参与,因此效率比较低发起IO请求,每次的IO中断,都带来CPU的上下文切换。因此出现了DMADMA(Direct Memory Access,直接内存读取)是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖CPU的大量中断负载.DMA控制器,接管了数据读写请求,减少CPU的负担,这样一来,CPU能高效工作了,现在硬盘都支持DMA实际IO读取,涉及两个过程:1.DMA等待数据准备好,把磁盘数据读取到操作系统内核缓冲区2.用户进程,将内核缓冲区的数据COPY到用户空间
DMA(Direct Memory Access)
子主题
传统数据传送机制
硬盘上文件的位置和应用缓冲区(application buffer)进行映射(建立一种一一对应关系)由于mmap()将文件直接映射到用户空间,所以实际文件读取时根据这个映射关系,直接将文件从硬盘拷贝到用户空间,只进行了一次数据拷贝,不再有文件内容从硬盘拷贝到内核空间的一个缓冲区mmap内存映射将会经历:3次拷贝:1次CPU copy 两次 DMA copy以及4次上下文切换,调用mmap函数两次,write函数两次
MMAP内存映射
sendfile
splice
NIO提工的内存映射MappedByteBuffer
Kafka中的零拷贝
Java生态圈中的零拷贝
零拷贝
区别:在于是否要请求发起方主动获取结果
1.结果占位符Future
2.接口回调Callback
异步结果通知方式
同步与异步
区别:在于是否要请求发起方等待
阻塞与非阻塞
同步阻塞
同步非阻塞
异步阻塞
异步非阻塞
组合
同步与异步、阻塞与非阻塞
AIO
面向流与面向缓冲区
Java BIO的各种流是阻塞的,这意味着,当一个线程调用read()或者write()时,该线程被阻塞,知道有一些数据被读取,或者数据完全写入,该线程在此期间不能再干任何事情了JavaNIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞所以直至数据变得可以读取之前,该线程可以继续做其他的事情。非阻塞写也是如此一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同事可以去做别的事情,线程通常将非阻塞IO的空闲事件用于在其他通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(Channel)
阻塞与非阻塞IO
和BIO的区别
客户端和服务端均可向Selector注册感兴趣的感兴趣的事件客户端:感兴趣的事件有OP_READ读事件、OP_CONNECT 连接事件服务端:感兴趣的事件有OP_READ读事件、OP_ACCEPT 接受请求事件
当接收缓存区有数据可读时,触发
OP_READ
当发送缓冲区有空间可写时,触发
OP_WRITE
当服务端可以跟客户端建立连接时,触发,只给客户端使用
OP_CONNECT
OP_ACCEPT
SelectionKey
Selector
Channel
InputStream是Java socket中提供的默认读写网络流的接口类,其内部由SocketInputStream实现;在调用read方法时如果流还没有准备完成则会阻塞整个调用线程直到流准备完成
Buffer
核心三大组件
NIO架构图
NIO
单线程
一个连接一个线程
线程池模型处理
阻塞式IO当客户端向服务端发起连接时,如果客户端没有发送数据,服务端将会一直阻塞直到客户端发出数据,其他的客户端必须要等待服务端处理完毕可以延伸出两种策略:缺点:受限于服务器的CPU核心数,无法支撑起高并发
BIO
一个基于事件驱动的主从React模型开发的网络IO框架,对IO模型做了一些封装
一系列的ChannelHandler组成的出站/入站事件(ChannelInboundHandler/ChannelOutboundHandler)链表进行处理,也是Netty开发中经常写的业务
ChannelPipeline
1.一个容器中增加了读指针和写指针,相比于原生的NIO中的ByteBuffer的一个指针方便了很多
2.可以分配堆外内存,使用了零拷贝的技术
3.Netty在一开始就向OS申请了一大块儿内存用来为ByteBuf分配空间
ByteBuf
类似于线程池,由EventLoop组成
EventLoopGroup
可以调整连接中的TCP参数来优化性能,如发送/接收缓冲区大小
ChannelOption
核心组件
TCP
UDP
1.应用程序写入数据的字节大小大于套接字发送缓冲区的大小
2.进行MSS大小的TCP分段。MSS是最大报文段长度的缩写.MSS是TCP报文段中的数据字段的最大长度.数据字段加上TCP首部才等于整个的TCP报文段.所以MSS并不是TCP报文段的最大长度.而是:MSS=TCP报文段长度 - TCP首部长度
MTU(Maximm Transmission Unit),用来通知对方所能接受数据服务单元的最大尺寸,说明发送方能够接受的有效载荷大小在以太网中是1500个字节TCP报头占20个字节IP报头占20个字节
具体原因
现象描述
1.分隔符。分割每个报文
2.固定长度。截取每个报文
3.消息头+消息体。把每个报文长度写在消息头当中
解决方式
粘包/半包
1.主从Reactor线程模型
2.NIO多路复用非阻塞
3.无锁串行化
4.支持高性能序列化协议
5.零拷贝(直接内存的使用)
6.ByteBuf的内存池设计
7.灵活的TCP参数配置能力
8.并发优化
Netty高并发高性能架构设计精髓
Netty
Java中的IO
为什么是3次而不是两次或者4次
大量的请求向服务端发起建立连接的请求,这些客户端却无法响应服务端的第二次握手请求,服务端为了保存客户端第一次握手的状态,当这个数量特别大时,超过了服务端维持TCP第一次握手的队列时,服务端将无法接收后续客户端请求,从而造成瘫痪这个参数是cat /proc/sys/net/ipv4/tcp_max_syn_backlog
DDos攻击
三次握手
为什么客户端要等待2*MSL
四次挥手
面向连接的、可靠的传输协议
面向报文的传输协议
IP占4个字节
端口号2个字节
一个Socket组成也指一条连接
TCP/UDP
短连接
HTTP 1.1通过增加更多的请求头和响应头来改进和扩充HTTP 1.0的功能。如,HTTP 1.0不支持Host请求头字段,浏览器无法使用主机头名来明确表示要访问服务器上的哪个WEB站点,这样就无法使用WEB服务器在同一个IP地址和端口号上配置多个虚拟WEB站点。在HTTP 1.1中增加Host请求头字段后,WEB浏览器可以使用主机头名来明确表示要访问服务器上的哪个WEB站点,这才实现了在一台WEB服务器上可以在同一个IP地址和端口号上使用不同的主机名来创建多个虚拟WEB站点
无host头域
不能只传输对象的一部分,要求传输整个对象
不允许断点续传
HTTP1.0
HTTP1.1中默认开启Connection: keep-alive,能够更好的利用TCP的慢启动机制
长连接
HTTP1.0中主要使用 Last-Modified,Expires 来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略:ETag,Cache-Control
增加缓存处理
Host 是 HTTP 1.1 协议中新增的一个请求头,主要用来实现虚拟主机技术。虚拟主机(virtual hosting)即共享主机(shared web hosting),可以利用虚拟技术把一台完整的服务器分成若干个主机,因此可以在单一主机上运行多个网站或服务。举个栗子,有一台 ip 地址为 61.135.169.125 的服务器,在这台服务器上部署着谷歌、百度、淘宝的网站。为什么我们访问 https://www.google.com 时,看到的是 Google 的首页而不是百度或者淘宝的首页?原因就是 Host 请求头决定着访问哪个虚拟主机
增加Host字段
长连接会给服务器造成压力
支持断点续传
HTTP1.1
HTTP1.x的解析是基于文本,基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合,基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮
新的二进制格式
HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小
header压缩
例如我的网页有一个sytle.css的请求,在客户端收到sytle.css数据的同时,服务端会将sytle.js的文件推送给客户端,当客户端再次尝试获取sytle.js时就可以直接从缓存中获取到,不用再发请求了
服务端推送
HTTP/1.0 每次请求响应,建立一个TCP连接,用完关闭 - HTTP/1.1 「长连接」 若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞; - HTTP/2.0 「多路复用」多个请求可同时在一个连接上并行执行,某个请求任务耗时严重,不会影响到其它连接的正常执行
多路复用
HTTP2.0
基于google的QUIC协议,而quic协议是使用udp实现的;
减少了tcp三次握手时间,以及tls握手时间;
解决了http 2.0中前一个stream丢包导致后一个stream被阻塞的问题;
优化了重传策略,重传包和原包的编号不同,降低后续重传计算的消耗;
连接迁移,不再用tcp四元组确定一个连接,而是用一个64位随机数来确定这个连接;
更合适的流量控制。
HTTP3.0
1.DNS解析域名获取其IP地址
2.建立TCP连接
3.发送HTTP/HTTPS请求(建立TLS连接)
4.服务器响应请求
5.浏览器解析渲染页面 reflow 回流 确定大小尺寸位置 repain 绘制颜色
6.浏览器断开连接
浏览器中输入url发生了什么
HTTP
网络IO
0 条评论
回复 删除
下一页