System_IO_NIO
2024-12-04 10:09:58 0 举报
系统级NIO原理
作者其他创作
大纲/内容
FD1FD2
stack
1
三次握手
系统IO原理:linuxVFS FDpagecache【java】1。文件系统的io2。内存和io关系3。网络io
为啥ulimit -n 1024但是连接数超过了1024呢?root用户没有限制。非root用户才限制
APP Server服务端1. 建立socket连接(socket -> fd4bindlisten fd4)2. epoll_create 开辟空间fd6(epfd) 3. epoll_ctl 在epfd中操作相应的fd 4. epoll_wait ->fdsacceptrecv
IO
C
pc4k
CPUint
你不能控制的
性能稍高一些
cap
Netty原理架构解析https://blog.csdn.net/YHC2113/article/details/90481619
thread
多条 路(每一个IO) 通过一次系统调用,获得复用器中的各个IO的状态然后,由程序对有状态的IO 进行R/W
font color=\"#f44336\
limit
fd9
超过pc阈值/LRU是否是dirty如果不是dirty直接淘汰
FIN
WRITEHANDLER
即便不调用内核,内核也会随着中断完成所有FD的状态设置
txtcode10*4KB1
syn
ifconfig
app1-x
pos
C300_123P+S200_80P
3不传递fds不触发内核遍历
app
多路复用器:select poll的弊端1,每次都要重新,重复传递fds (解决办法:内核开辟空间)2,每次,内核被调了之后,针对这次调用,触发一个遍历fds全量的复杂度
epoll_wait
out
appX
多 路 复用器
ooxx
ACK
win大小
因为accept阻塞,所以要创建(clone)新的线程处理接收的内容,不然就会一直阻塞无法接收数据
on heap
网络的拥塞如果发出的包超过win的限制,会丢包
TCP 如果双方建立了连接很久都不说话?对方还活着吗?
off heap
FD1 READ重复调起
ooxxdirty
allocateDirect堆外
CAIPCPORT:123随机生成端口号
网卡
int 0x80中断call back指令
clonerecv(fd5--> /blocking
page4kB不会全量分配缺页内存优化
key.canel
//最多有几个备胎,也就是在socket建立后,没有accept分配fd建立连接,最多的socket的数量 private static final int BACK_LOG = 2;
Thread
cpummu
data
FD1.register selector OP_WRITE
kernel
client
同一套代码: java NIO selector:pollepoll的不同底层实现
文件
int : cpu的指令
kernel《深入理解linux内核》《深入理解计算机系统》epoll < 怎么知道数据到达中断
get
程序的角度什么时候调用select内核什么时候遍历fds修正状态
app1保护现场可运行
FD6
BUFFER
内核级的
cpu
S
这个模型:考虑资源利用,充分利用cpu核数考虑有一个fd执行耗时,在一个线性里会阻塞后续FD的处理当有N个fd有R/W处理的时候:将N个FD 分组,每一组一个selector,将一个selector压到一个线程上最好的线程数量是:cpu cpu*2单看一个线程:里面有一个selector,有一部分FD,且他们是线性的多个线程,他们在自己的cpu上执行,代表会有多个selector在并行,且线程内是线性的,最终是并行的fd被处理但是,还是一个selector中的fd要放到不同的线程并行,从而造成cancel调用嘛? 不需要了!!!其实就是分治,我的程序如果有100W个连接,如果有4个线程(selector),每个线程处理 25w那么,可不可以拿出一个线程的selector就只关注accpet ,然后把接受的客户端的FD,分配给其他线程的selector
缺页处理:pagecache 会被LRU机制淘汰,程序在许久没有访问一个pagecache,该pagecache没有被修改过不是dirty状态,内存不够的时候会被淘汰掉,后面的pagecache会往前移动,新的pagecache会在队列后面加入。这时程序突然要访问之前的pagecache,发现没有了,造成了缺页,内核会先去磁盘把之前已经持久化的pagecache内容缓存到内存中形成新的pagecache,然后程序才访问该pagecache。
app1指针 seek 20
ack
中断
网络IO 变化 模型
heap
FileChannel
TCP
ByteBuffer
BIO的弊端阻塞 BLOCKING
计组:中断处理延伸:
数据包多大MTU(整体大小)MSS(数据内容大小)
著名的C10K 问题早期的网络如何突破1w个并发连接
app1-z
服务端没有发分手请求客户端处在 FIN_WAIT2
Object
即便你不调用accept
计组:通过中断放入链表
包
JDK new io
read(fd8)
READ HADNLER
资源
3 修改变为dirty状态
2
-:普通文件(可执行,图片,文本)REGd: 目录l:连接b:块设备c:字符设备 CHRs:socketp: pipeline[eventpoll]:。。。
EPOLL V.S SELECT/POLL
3次握手
JAVA
内核只调度可运行的进程
文件类型
map
最终:中断->回调 callbackevent 事件 ->回调处理事件大小,复杂度在EPOLL之前的cb:只是完成了将网卡发来的数据,走内核网络协议栈span style=\"font-size: inherit;\
select()
消耗不消耗资源消耗SOCKET四元组规则
有可能最后的ack没有到达对方,自己多留一会资源
PUT()不会产生系统调用
page cache优化IO性能弊端:丢失数据
在主线程里不能阻塞执行,不能是线性的所以事件会被重复触发解决方案key.cancel
读写交替buffer.flip();说明想要读取
只要程序自己读写,那么,你的IO模型就是同步的
channel.readchannel.write系统调用
程序访问磁盘,中间会先访问kernel,kernel操作内存, (系统无法直接访问app,都是通过Kernel来访问)磁盘的内容会先加载到内存中的VFS(虚拟文件系统),相同的程序会访问同一个内存内容,因为相同的磁盘内容加载到内存中inode相同,不会多次创建,使用stat xxx命令可以查看inode程序通过kernel访问内存文件,使用FD(文件描述符)并记录自己的seek(偏移量)找到自己要读取的虚拟文件位置。内存中的pagecache 大小为4kb的整数倍,如果内存中的文件被修改会被标记为dirty脏,dirty的数据在LRU(最近最少使用)淘汰前被内核写入磁盘或者手动调用flush写到磁盘上,同时去掉dirty状态。
ByteBuffer申请堆内空间:allocate 在jvm里申请堆外空间:allocateDirect 在jvm外java进程上
表:中断向量表25580 cb回调函数
Client100,123
硬盘file:appW 10*4kB
90
加载到内存中的PageCache
Socket可以先建立
txt程序代码
BIO
EPOLL为了规避遍历
创建//堆上// ByteBuffer buffer = ByteBuffer.allocate(1024); //堆外 ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
select(fds)poll(fds)
内存中的文件
fdseek
java Clinux pro进程
硬盘
网络IO: TCP 参数
OS:EPOLL //对应的java代码 font color=\"#ff0000\
ThreadFD1.READ()
TIME_WAIT2MSL(2倍的报文活动时间)可能是30s 、1m、2m
物理内存
AIP_CPORT+XIP_XPORT : FD3AIP_BPORT+XIP_XPORT : FD4AIP_APORT+XIP_XPORT : FD5AIP_CPORT+XIP_YPORT : FD3AIP_BPORT+XIP_YPORT : FD4AIP_APORT+XIP_YPORT : FD5
FIN_ACK
磁盘4K
NIO
内核
netstat -natp 0.0.0.0:8090 0.0.0.0:* LISTEN
PageCachekernel 折中方案
写入buffer.put(\"123\".getBytes());
kernelVFS(虚拟文件系统) 树FDinode相当于idpagecache 大小为4kb的整数倍dirty 脏flush
CLIENT
appwhile(){select(fds) 复杂度 O(1)recv(fd) 复杂度O(m) 知道具体的M个fd要读取}
flip
2 是否是dirty是写入磁盘
Kernel
保护现场切换用户态内核态
SELECT(FDS)POLL
延伸
重复调起send-queue
selectkeys()
put写入
appW
时钟中断硬中断晶振
3root/boot/dev/etc
File ifile = new File(\"/ooxx.txt\")out (fd) = new outputstream(ifile)out.write(\"fdsfsdf\")
kernelpc
-Xmx1Gjvm heap
缓冲区
Server app:ip 200 port 80
s
Mappedmmap()逻辑地址
client端关闭,服务端没有发送fin(也就是他也要关闭的请求)时的状态
FD4buffer
pagecachedirty
程序是逻辑地址,是线性连续的,若干个4k的page内存是物理地址,一块区域作为cache,相对程序是碎片化的,通过fd来关联比如程序中的逻辑地址是80,通过mmu的映射表,找到对应的物理地址是222
main_thread
内核级开辟资源
读buffer.get();读取后,从ByteBuffer剔除
键盘
IO中断
受内核影响
鼠标dpi100016000
syn+ack
fd6<红黑树>FD4 -> accept
app2-y
app1和app2都读取同一个文件,各自进程的fd会维护各自的seek
I/O
链表FD4
SXIPXPORT:80YPORT:9090
app1-y
epoll_wait == select
同步模型下的非阻塞多路复用器:系统调用方法SELECT POSIX标准的POLLEPOLL linux中kqueue unix中
唯一性
system call
OS NONBLOCKINIG
ooxx[cache]
冯诺依曼计算器,控制器主存储器输入输出设备 I/O
allocate堆内
{ a= 9; echo \"sdfsdf\"; }代码块是在子进程中执行的进程间是隔离的,所以不会影响主进程中的a值
/proc/proc/$$$$ 当前bash的pid $BASHPID进入fd目录:cd /proc/$$/fd 命令 lsof -op $$ 重定向:不是命令,是机制输入,输出 I/O<>管道 | 管道在执行的时候左右两端会启动两个子进程,左边子进程的输出 传给右边子进程的输入,但是要看优先级echo $$的优先级就高于管道
问题
服务端是否需要为client的连接分配一个随机端口号?不需要
Client300,123
DMA协处理器
目录树结构趋向于稳定有一个映射的过程
通过accept 将 socket与FD进行连接
SELECTsynchronous I/O multiplexing受FD_SETSIZE (1024)限制POLL里面没有1024的限制
C10K
1,package2,buffer3,轮询
OS 没有觉得数据可靠性为什么设计pagecache ,减少 硬件 IO 调用,提速,优先使用内存即便你想要可靠性,调成最慢的方式但是单点问题会让你的性能损耗,没有收益主从复制,主备HAkafka/ES 副本(socket io) (同步/异步)。。。
page cache内核维护 中间层使用多大内存是否淘汰是否延时,是否丢数据
寄存器
面向连接的,可靠的传输协议
app2fd 指针 seek(偏移) 8
keepalive
epoll的限制/proc/sys/fs/epoll/max_user_watches
是你能控制的
table 1~10 -》30-40访问80 异常 缺页用户态切到内核态,然后将80 -》 222 映射到table中然后从内核态切回用户态,完成pagecache处理
buffer
1create不是dirty状态
APP Serversocket -> fd4bindlisten fd4
selector
FD22
抽象一切皆文件
多路复用器
中断是为了进程间的切换
native维护一个集合
linux : heap
任何程序都有0:标准输入1:标准输出2:报错输出
根据给出的fd
NIOapp通过系统调用全量遍历每一个io,才能知道数据在哪条io上。需要每条io都要用户态内核态切换才能实现
同步异步阻塞非阻塞指令:strace -ff -o out cmd
向pagecache中写入
软中断陷阱int 80
磁盘文件
写入磁盘
fd8
同步阻塞:用一个不能响的水壶烧水,你要一直等;同步非阻塞:定时来看水壶的水开了没有;异步非阻塞:用一个能响的水壶烧水,水开了它自己响
/boot/dev/loop0/mnt/ooxx
DMA协处理器CPU的助手
socket
clone系统调用还需要kernel处理
四次分手双端的状态
C100_123P+S200_80P
yum install man man-pages命令:man 2 select
修改vi /etc/sysctl.conf
select
Server端main主线程while{accept 系统调用}
epoll_create-> fd6开辟fd6的红黑树空间
系统中文件描述符最大的数量,大概是内存大小的10倍左右4G的内存大约38万的文件描述符1G大概10万个
2swap2G
1G也是若干个4k的page
closed
在TIME_WAIT没有结束前,内核中的socket的四元组被占用,相同的对端不能使用这个资源建立新的连接浪费的是名额!这个不是DDOS攻击
clone出的线程接收信息recv(fd5--> /blocking
将pcstat拷贝到/bin下chmod 777 pcstat查看某个文件的pc
c
app2
四元组(CIP_CPORT+SIP_SPORT)
netty
最终也是堆内到堆外先内到外
CPU
一次write就是一次用户态与内核态的切换buffer为什么快,减少用户态与内核态的切换
内核中,程序在红黑树中放过一些FD,那么伴随内核基于中断处理完fd的buffer、状态之后,继续把有状态的fd,copy到链表中
中断描述符表012...128 call back方法...255
循环遍历
lsof -p PID号netstat -natp tcpdump -nn -i eth0 port 9090
0x80: 1281000 0000值寄存器
dma
pagecache1个
以下图示:是以client为断开发起方的状态,如果是Server发起断开,那么Server端的状态与Client的状态对调也会出现相应的状态。
txt1个
程序只要调用wait,能及时取走有状态fd的结果集
内存
读写交替buffer.compact();说明想要写入
compact
NIO优势:通过1个或几个线程,来解决N个IO连接的处理弊端:每循环一次:O(n)复杂度recv 很多系统调用是无用的。*read 有瓶颈是因为 无效的无用的read被调起
磁盘
close_wait
0 条评论
下一页