IO多路复用发展史

 2023-09-15 阅读 19 评论 0

摘要:引言 java程序对系统内核io的时候有哪些系统调用发生 内核有没有参与到io中? NIO 模拟socket通讯TestSocket类 简单描述 1、创建一个socketserver进程绑定8090端口2、等待客户端连接一有客户端连接则创建一个线程来解析数据流 抓取指定进程及子进程和子线程对内核系统有没有调

引言

java程序对系统内核io的时候有哪些系统调用发生 内核有没有参与到io中?

NIO

模拟socket通讯TestSocket类

简单描述

1、创建一个socket server进程绑定8090端口
2、等待客户端连接 一有客户端连接则创建一个线程来解析数据流

抓取指定进程及子进程和子线程对内核系统有没有调用

strace -ff -o ./ooxx java TestSocket
每个线程对应一个文件 最大的文件是主线程即2879
根据上面代码 主线程也打印了一个日志 通过日志也可以确定主线程

查看2879文件

可以看到写入日志的时候 调用的是内核函数write

查看java进程

进程id是2878

通过进程号可以得到该进程下有多少个线程
该进程有多少个文件描述符
也可以查看该进程的网络状态


查看该进程的情况 
cd /proc/2878
cd task
查看当前进程开启了多少线程
cd fd
查看文件描述符
1、任何一个程序都有io
标准输入0 system.in ,标准输出1 system.out ,错误输出2 system.error

2、java中以对象形式存在 linux一切皆文件 以数字代表
java中变量在linux中用数值代替变量 引用了其中一个流

3、runtime运行时的jar包库 jvm启动的时候会加载

4、2个socket 一个是ipv4 一个是ipv6
没有客户端与服务端连接 却有了socket文件描述符

网络状态命令

netstat -antp
显示所有 tcp协议 打出进程号
只有服务端有监听状态

客户端与socket服务端建立连接

nc(netcat)是linux操作系统程序 
可以任何人建立tcp socket连接

nc localhost 8090

网络连接状态中会出现一个新的状态
文件描述符中会多一个 代表新的连接

此时只建立了tcp连接 还没有发送数据

查看socket server进程

有了一个客户端连接记录

查看主线程系统调用情况

该内核函数 c语言 accept函数对应到java代码

查看文件描述符fd5系统调用

vim ooxx.2879
/socket.*5$

绑定8090端口

监听该端口

查看内核函数accept

man accept 相当于访问了一个外壳
man 2 accept
socket会返回一个文件描述符

man bind

里面有socket demo程序 
可以看到socket建立的整个过程

监听fd5处于阻塞状态

再来个客户端连接

客户端的连接生成fd7
线程3111来处理这个连接

查看3111这个线程的sc

同步读取read/recvfrom fd7

客户端发送数据

3111进程读取fd7数据

write1是标准输出

查看socket server

NIO弊端

1、每一个线程对应一个client 线程太多 消耗内存栈 默认1M 创建线程也要走系统调用
2、cpu调度 资源浪费 
比如C10K或C100K
客户端1万个连接
但可能还有2个连接有数据
3、根本问题 blocking 阻塞的


man 2 socket

NIO

socket 非阻塞

在app 级别 NewIO 比如channel buffer
在内核级别 nonblocking
不用开辟很多线程了

listen、accept、recvfrom fd6 这些都可以是非阻塞的

内核增加了一个系统调用 select

man 2 select

告诉内核有多少个文件描述符会传过去

如果有1w次系统调用 通过select将这1万个文件描述符传给内核
内核返回m个可用的状态
程序读取具体个数的recvfrom O(m)

NIO弊端

1、重复传数据到内核
2、一次调用 内核本地方法的10万次遍历
内核 主动遍历 O(n)

解决方法

在内核开辟空间 1万 不用每次都传
不主动遍历 基于事件驱动

EPOLL

man epoll

man epoll_create

man epoll_ctl

man 2 epoll_wait

每个客户端生命周期中至少一个epoll_ctl添加到fd8中
1、在内核中创建一个fd8空间
2、新的连接都加入到这里 通过事件驱动 监听fd5文件描述符获得数据 将fd5到另外一个内核空间中去
3、程序从fd5内核空间读取数据即可

epoll充分利用硬件 尽量不浪费cpu

Nginx EPOLL

外壳进程启动过渡进程
即3259生出了3260(master nginx),3259 exited

nginx监听80端口

master clone worker

worker

fd6/7 一个是ipv4 一个是ipv6

查看master 3260情况

查看worker 3261

nginx epoll 阻塞不动

Redis Epoll

redis 默认单线程 redis 5.x之前版本
redis是轮询的线程 
文件大小一直在变大
因为单线程 还在干别的事情
比如LRU LFU 淘汰过滤
RDB 后台fork 子进程 镜像 AOF重写
redis 6.x版本 IO threads

为了留住串行化原子性
epoll 知道哪些客户端可读可写了
读让线程并发读io
多核并行读
谁先读完了 计算 由工作线程串行执行

零拷贝

KafKa

mmap写磁盘

未零拷贝读取的过程

零拷贝 man sendfile

前提是数据不需要加工 不需要回到用户空间 比如nginx 图片 css 静态东西

Netty

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/59870.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息