导航:首页 > 文件教程 > linux文件io

linux文件io

发布时间:2023-03-21 10:31:35

A. linux 文件IO操作中,用read函数读取文件,有没有办法每次只读取一行,而不是读取指定的字节数

sorry,开始来没注源意空格
char buf[256]; //一行超过256个字节??
char temp;
int i = 0;
do
{
if(read(fd, &temp, 1) == 0)break;
if(temp == '\n') break;
buf[i++] = temp;
}while(1);
buf[i] =='\0';

B. linux查看磁盘io的几种方法

linux查看磁盘io的几种方法

怎样才能快速的定位到并发高是由于磁盘io开销大呢?可以通过三种方式:

第一种:用 top 命令 中的cpu 信息观察

Top可以看到的cpu信息有:

Tasks: 29 total, 1 running, 28 sleeping, 0 stopped, 0 zombie

Cpu(s): 0.3% us, 1.0% sy, 0.0% ni, 98.7% id, 0.0% wa, 0.0% hi, 0.0% si

具体的解释如下:

Tasks: 29 total 进程总数

1 running 正在运行的进程数

28 sleeping 睡眠的进程数

0 stopped 停止的进程数

0 zombie 僵尸进程数

Cpu(s):

0.3% us 用户空间占用CPU百分比

1.0% sy 内核空间占用CPU百分比

0.0% ni 用户进程空间内改变过优先级的进程占用CPU百分比

98.7% id 空闲CPU百分比

0.0% wa 等待输入输出的CPU时间百分比

0.0% hi

0.0% si

0.0% wa 的百分比可以大致的体现出当前的磁盘io请求是否频繁。如果 wa的数量比较大,说明等待输入输出的的io比较多。

第二种:用vmstat

vmstat 命令报告关于线程、虚拟内存、磁盘、陷阱和 CPU 活动的统计信息。由 vmstat 命令生成的报告可以用于平衡系统负载活动。系统范围内的这些统计信息(所有的处理器中)都计算出以百分比表示的平均值,或者计算其总和。

输入命令:

vmstat 2 5

如果发现等待的进程和处在非中断睡眠状态的进程数非常多,并且发送到块设备的块数和从块设备接收到的块数非常大,那就说明磁盘io比较多。

vmstat参数解释:

Procs

r: 等待运行的进程数 b: 处在非中断睡眠状态的进程数 w: 被交换出去的可运行的进程数。此数由 linux 计算得出,但 linux 并不耗尽交换空间

Memory

swpd: 虚拟内存使用情况,单位:KB

free: 空闲的内存,单位KB

buff: 被用来做为缓存的内存数,单位:KB

Swap

si: 从磁盘交换到内存的交换页数量,单位:KB/秒

so: 从内存交换到磁盘的交换页数量,单位:KB/秒

IO

bi: 发送到块设备的块数,单位:块/秒

bo: 从块设备接收到的块数,单位:块/秒

System

in: 每秒的中断数,包括时钟中断

cs: 每秒的环境(上下文)切换次数

CPU

按 CPU 的总使用百分比来显示

us: CPU 使用时间

sy: CPU 系统使用时间

id: 闲置时间

准测

更多vmstat使用信息

第二种:用iostat

安装:

Iostat 是 sysstat 工具集的一个工具,需要安装。

Centos的安装方式是:

yum install sysstat

Ubuntu的安装方式是:

aptitude install sysstat

使用:

iostat -dx 显示磁盘扩展信息

root@fileapp:~# iostat -dx

r/s 和 w/s 分别是每秒的读操作和写操作,而rKB/s 和wKB/s 列以每秒千字节为单位显示了读和写的数据量

如果这两对数据值都很高的话说明磁盘io操作是很频繁。

+++++++++++++++++++++++++++++++++++++

linux wa%过高,iostat查看io状况

1, 安装  iostat  

yum install sysstat

之后就可以使用 iostat 命令了,

2,入门使用

iostat -d -k 2

参数 -d 表示,显示设备(磁盘)使用状态;-k某些使用block为单位的列强制使用Kilobytes为单位;2表示,数据显示每隔2秒刷新一次。

tps:该设备每秒的传输次数(Indicate the number of transfers per second that were issued to the device.)。"一次传输"意思是"一次I/O请求"。多个逻辑请求可能会被合并为"一次I/O请求"。"一次传输"请求的大小是未知的。kB_read/s:每秒从设备(drive expressed)读取的数据量;

kB_wrtn/s:每秒向设备(drive expressed)写入的数据量;

kB_read:读取的总数据量;kB_wrtn:写入的总数量数据量;这些单位都为Kilobytes。

指定监控的设备名称为sda,该命令的输出结果和上面命令完全相同。

iostat -d sda 2

默认监控所有的硬盘设备,现在指定只监控sda。 

3, -x 参数

iostat还有一个比较常用的选项 -x ,该选项将用于显示和io相关的扩展数据。

iostat -d -x -k 1 10

输出信息的含义



4, 常见用法

iostat -d -k 1 10        #查看TPS和吞吐量信息(磁盘读写速度单位为KB)

iostat -d -m 2            #查看TPS和吞吐量信息(磁盘读写速度单位为MB)

iostat -d -x -k 1 10      #查看设备使用率(%util)、响应时间(await) iostat -c 1 10 #查看cpu状态

5, 实例分析

iostat -d -k 1 | grep vda

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn

sda10            60.72        18.95        71.53  395637647 1493241908

sda10          299.02      4266.67      129.41      4352        132

sda10          483.84      4589.90      4117.17      4544      4076

sda10          218.00      3360.00      100.00      3360        100

sda10          546.00      8784.00      124.00      8784        124

sda10          827.00    13232.00      136.00      13232        136

上面看到,磁盘每秒传输次数平均约400;每秒磁盘读取约5MB,写入约1MB。

iostat -d -x -k 1

Device:    rrqm/s wrqm/s  r/s  w/s  rsec/s  wsec/s    rkB/s    wkB/s avgrq-sz avgqu-sz  await  svctm  %util

sda          1.56  28.31  7.84 31.50  43.65    3.16    21.82    1.58    1.19    0.03    0.80  2.61  10.29

sda          1.98  24.75 419.80  6.93 13465.35  253.47  6732.67  126.73    32.15    2.00    4.70  2.00  85.25

sda          3.06  41.84 444.90 54.08 14204.08 2048.98  7102.04  1024.49    32.57    2.10    4.21  1.85  92.24

可以看到磁盘的平均响应时间<5ms,磁盘使用率>80。磁盘响应正常,但是已经很繁忙了。

可以看到磁盘的平均响应时间<5ms,磁盘使用率>90。磁盘响应正常,但是已经很繁忙了。

await:  每一个IO请求的处理的平均时间(单位是微秒毫秒)。这里可以理解为IO的响应时间,一般地系统IO响应时间应该低于5ms,如果大于10ms就比较大了

svctm    表示平均每次设备I/O操作的服务时间(以毫秒为单位)。如果svctm的值与await很接近,表示几乎没有I/O等待,磁盘性能很好,

如果await的值远高于svctm的值,则表示I/O队列等待太长,  系统上运行的应用程序将变慢。

%util: 在统计时间内所有处理IO时间,除以总共统计时间

所以该参数暗示了设备的繁忙程度

。一般地,如果该参数是100%表示设备已经接近满负荷运行了(当然如果是多磁盘,即使%util是100%,因为磁盘的并发能力,所以磁盘使用未必就到了瓶颈)。

也可以使用下面的命令,同时显示cpu和磁盘的使用情况

等待时间超过5ms, 磁盘io有问题

C. 在linux系统中如何查看cpu和io

在 Linux 系统中,可以使用以下命令查看 CPU 信息:

D. Linux系统I/O模型及select、poll、epoll原理和应用

理解Linux的IO模型之前,首先要了解一些基本概念,才能理解这些IO模型设计的依据

操作系统使用虚拟内存来映射物理内存,对于32位的操作系统来说,虚拟地址空间为4G(2^32)。操作系统的核心是内核,为了保护用户进程不能直接操作内核,保证内核安全,操作系统将虚拟地址空间划分为内核空间和用户空间。内核可以访问全部的地址空间,拥有访问底层硬件设备的权限,普通的应用程序需要访问硬件设备必须通过 系统调用 来实现。

对于Linux系统来说,将虚拟内存的最高1G字节的空间作为内核空间仅供内核使用,低3G字节的空间供用户进程使用,称为用户空间。

又被称为标准I/O,大多数文件系统的默认I/O都是缓存I/O。在Linux系统的缓存I/O机制中,操作系统会将I/O的数据缓存在页缓存(内存)中,也就是数据先被拷贝到内核的缓冲区(内核地址空间),然后才会从内核缓冲区拷贝到应用程序的缓冲区(用户地址空间)。

这种方式很明显的缺点就是数据传输过程中需要再应用程序地址空间和内核空间进行多次数据拷贝操作,这些操作带来的CPU以及内存的开销是非常大的。

由于Linux系统采用的缓存I/O模式,对于一次I/O访问,以读操作举例,数据先会被拷贝到内核缓冲区,然后才会从内核缓冲区拷贝到应用程序的缓存区,当一个read系统调用发生的时候,会经历两个阶段:

正是因为这两个状态,Linux系统才产生了多种不同的网络I/O模式的方案

Linux系统默认情况下所有socke都是blocking的,一个读操作流程如下:

以UDP socket为例,当用户进程调用了recvfrom系统调用,如果数据还没准备好,应用进程被阻塞,内核直到数据到来且将数据从内核缓冲区拷贝到了应用进程缓冲区,然后向用户进程返回结果,用户进程才解除block状态,重新运行起来。

阻塞模行下只是阻塞了当前的应用进程,其他进程还可以执行,不消耗CPU时间,CPU的利用率较高。

Linux可以设置socket为非阻塞的,非阻塞模式下执行一个读操作流程如下:

当用户进程发出recvfrom系统调用时,如果kernel中的数据还没准备好,recvfrom会立即返回一个error结果,不会阻塞用户进程,用户进程收到error时知道数据还没准备好,过一会再调用recvfrom,直到kernel中的数据准备好了,内核就立即将数据拷贝到用户内存然后返回ok,这个过程需要用户进程去轮询内核数据是否准备好。

非阻塞模型下由于要处理更多的系统调用,因此CPU利用率比较低。

应用进程使用sigaction系统调用,内核立即返回,等到kernel数据准备好时会给用户进程发送一个信号,告诉用户进程可以进行IO操作了,然后用户进程再调用IO系统调用如recvfrom,将数据从内核缓冲区拷贝到应用进程。流程如下:

相比于轮询的方式,不需要多次系统调用轮询,信号驱动IO的CPU利用率更高。

异步IO模型与其他模型最大的区别是,异步IO在系统调用返回的时候所有操作都已经完成,应用进程既不需要等待数据准备,也不需要在数据到来后等待数据从内核缓冲区拷贝到用户缓冲区,流程如下:

在数据拷贝完成后,kernel会给用户进程发送一个信号告诉其read操作完成了。

是用select、poll等待数据,可以等待多个socket中的任一个变为可读,这一过程会被阻塞,当某个套接字数据到来时返回,之后再用recvfrom系统调用把数据从内核缓存区复制到用户进程,流程如下:

流程类似阻塞IO,甚至比阻塞IO更差,多使用了一个系统调用,但是IO多路复用最大的特点是让单个进程能同时处理多个IO事件的能力,又被称为事件驱动IO,相比于多线程模型,IO复用模型不需要线程的创建、切换、销毁,系统开销更小,适合高并发的场景。

select是IO多路复用模型的一种实现,当select函数返回后可以通过轮询fdset来找到就绪的socket。

优点是几乎所有平台都支持,缺点在于能够监听的fd数量有限,Linux系统上一般为1024,是写死在宏定义中的,要修改需要重新编译内核。而且每次都要把所有的fd在用户空间和内核空间拷贝,这个操作是比较耗时的。

poll和select基本相同,不同的是poll没有最大fd数量限制(实际也会受到物理资源的限制,因为系统的fd数量是有限的),而且提供了更多的时间类型。

总结:select和poll都需要在返回后通过轮询的方式检查就绪的socket,事实上同时连的大量socket在一个时刻只有很少的处于就绪状态,因此随着监视的描述符数量的变多,其性能也会逐渐下降。

epoll是select和poll的改进版本,更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的只需一次。

epoll_create()用来创建一个epoll句柄。
epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个就绪链表中管理。
epoll_wait() 可以从就绪链表中得到事件完成的描述符,因此进程不需要通过轮询来获得事件完成的描述符。

当epoll_wait检测到描述符IO事件发生并且通知给应用程序时,应用程序可以不立即处理该事件,下次调用epoll_wait还会再次通知该事件,支持block和nonblocking socket。

当epoll_wait检测到描述符IO事件发生并且通知给应用程序时,应用程序需要立即处理该事件,如果不立即处理,下次调用epoll_wait不会再次通知该事件。

ET模式在很大程度上减少了epoll事件被重复触发的次数,因此效率要比LT模式高。epoll工作在ET模式的时候,必须使用nonblocking socket,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。

【segmentfault】 Linux IO模式及 select、poll、epoll详解
【GitHub】 CyC2018/CS-Notes

E. Linux 磁盘IO

磁盘结构与数据存储方式, 数据是如何存储的,又通过怎样的方式被访问?

机械硬盘主要由磁盘盘片、磁头、主轴与传动轴等组成;数据就存放在磁盘盘片中

现代硬盘寻道都是采用CHS( Cylinder Head Sector )的方式,硬盘读取数据时,读写磁头沿径向移动,移到要读取的扇区所在磁道的上方,这段时间称为 寻道时间(seek time) 因读写磁头的起始位置与目标位置之间的距离不同,寻道时间也不同 。磁头到达指定磁道后,然后通过盘片的旋转,使得要读取的扇区转到读写磁头的下方,这段时间称为 旋转延迟时间(rotational latencytime) 。然后再读写数据,读写数据也需要时间,这段时间称为 传输时间(transfer time)

固态硬盘主要由主控芯片、闪存颗粒与缓存组成;数据就存放在闪存芯片中
通过主控芯片进行寻址, 因为是电信号方式, 没有任何物理结构, 所以寻址速度非常快且与数据存储位置无关

如何查看系统IO状态

查看磁盘空间

调用 open , fwrite 时到底发生了什么?

在一个IO过程中,以下5个API/系统调用是必不可少的
Create 函数用来打开一个文件,如果该文件不存在,那么需要在磁盘上创建该文件
Open 函数用于打开一个指定的文件。如果在 Open 函数中指定 O_CREATE 标记,那么 Open 函数同样可以实现 Create 函数的功能
Clos e函数用于释放文件句柄
Write 和 Read 函数用于实现文件的读写过程

O_SYNC (先写缓存, 但是需要实际落盘之后才返回, 如果接下来有读请求, 可以从内存读 ), write-through
O_DSYNC (D=data, 类似O_SYNC, 但是只同步数据, 不同步元数据)
O_DIRECT (直接写盘, 不经过缓存)
O_ASYNC (异步IO, 使用信号机制实现, 不推荐, 直接用aio_xxx)
O_NOATIME (读取的时候不更新文件 atime(access time))

sync() 全局缓存写回磁盘
fsync() 特定fd的sync()
fdatasync() 只刷数据, 不同步元数据

mount noatime(全局不记录atime), re方式(只读), sync(同步方式)

一个IO的传奇一生 这里有一篇非常好的资料,讲述了整个IO过程;
下面简单记录下自己的理解的一次常见的Linux IO过程, 想了解更详细及相关源码,非常推荐阅读上面的原文

Linux IO体系结构

[站外图片上传中...(image-38a7b-1644137945193)]

Superblock 超级描述了整个文件系统的信息。为了保证可靠性,可以在每个块组中对superblock进行备份。为了避免superblock冗余过多,可以采用稀疏存储的方式,即在若干个块组中对superblock进行保存,而不需要在所有的块组中都进行备份
GDT 组描述符表 组描述符表对整个组内的数据布局进行了描述。例如,数据块位图的起始地址是多少?inode位图的起始地址是多少?inode表的起始地址是多少?块组中还有多少空闲块资源等。组描述符表在superblock的后面
数据块位图 数据块位图描述了块组内数据块的使用情况。如果该数据块已经被某个文件使用,那么位图中的对应位会被置1,否则该位为0
Inode位图 Inode位图描述了块组内inode资源使用情况。如果一个inode资源已经使用,那么对应位会被置1
Inode表 (即inode资源)和数据块。这两块占据了块组内的绝大部分空间,特别是数据块资源

一个文件是由inode进行描述的。一个文件占用的数据块block是通过inode管理起来的 。在inode结构中保存了直接块指针、一级间接块指针、二级间接块指针和三级间接块指针。对于一个小文件,直接可以采用直接块指针实现对文件块的访问;对于一个大文件,需要采用间接块指针实现对文件块的访问

最简单的调度器。它本质上就是一个链表实现的 fifo 队列,并对请求进行简单的 合并 处理。
调度器本身并没有提供任何可以配置的参数

读写请求被分成了两个队列, 一个用访问地址作为索引,一个用进入时间作为索引,并且采用两种方式将这些request管理起来;
在请求处理的过程中,deadline算法会优先处理那些访问地址临近的请求,这样可以最大程度的减少磁盘抖动的可能性。
只有在有些request即将被饿死的时候,或者没有办法进行磁盘顺序化操作的时候,deadline才会放弃地址优先策略,转而处理那些即将被饿死的request

deadline算法可调整参数
read_expire : 读请求的超时时间设置(ms)。当一个读请求入队deadline的时候,其过期时间将被设置为当前时间+read_expire,并放倒fifo_list中进行排序
write_expire :写请求的超时时间设置(ms)
fifo_batch :在顺序(sort_list)请求进行处理的时候,deadline将以batch为单位进行处理。每一个batch处理的请求个数为这个参数所限制的个数。在一个batch处理的过程中,不会产生是否超时的检查,也就不会产生额外的磁盘寻道时间。这个参数可以用来平衡顺序处理和饥饿时间的矛盾,当饥饿时间需要尽可能的符合预期的时候,我们可以调小这个值,以便尽可能多的检查是否有饥饿产生并及时处理。增大这个值当然也会增大吞吐量,但是会导致处理饥饿请求的延时变长
writes_starved :这个值是在上述deadline出队处理第一步时做检查用的。用来判断当读队列不为空时,写队列的饥饿程度是否足够高,以时deadline放弃读请求的处理而处理写请求。当检查存在有写请求的时候,deadline并不会立即对写请求进行处理,而是给相关数据结构中的starved进行累计,如果这是第一次检查到有写请求进行处理,那么这个计数就为1。如果此时writes_starved值为2,则我们认为此时饥饿程度还不足够高,所以继续处理读请求。只有当starved >= writes_starved的时候,deadline才回去处理写请求。可以认为这个值是用来平衡deadline对读写请求处理优先级状态的,这个值越大,则写请求越被滞后处理,越小,写请求就越可以获得趋近于读请求的优先级
front_merges :当一个新请求进入队列的时候,如果其请求的扇区距离当前扇区很近,那么它就是可以被合并处理的。而这个合并可能有两种情况,一个是向当前位置后合并,另一种是向前合并。在某些场景下,向前合并是不必要的,那么我们就可以通过这个参数关闭向前合并。默认deadline支持向前合并,设置为0关闭

在调度一个request时,首先需要选择一个一个合适的cfq_group。Cfq调度器会为每个cfq_group分配一个时间片,当这个时间片耗尽之后,会选择下一个cfq_group。每个cfq_group都会分配一个vdisktime,并且通过该值采用红黑树对cfq_group进行排序。在调度的过程中,每次都会选择一个vdisktime最小的cfq_group进行处理。
一个cfq_group管理了7棵service tree,每棵service tree管理了需要调度处理的对象cfq_queue。因此,一旦cfq_group被选定之后,需要选择一棵service tree进行处理。这7棵service tree被分成了三大类,分别为RT、BE和IDLE。这三大类service tree的调度是按照优先级展开的

通过优先级可以很容易的选定一类Service tree。当一类service tree被选定之后,采用service time的方式选定一个合适的cfq_queue。每个Service tree是一棵红黑树,这些红黑树是按照service time进行检索的,每个cfq_queue都会维护自己的service time。分析到这里,我们知道,cfq算法通过每个cfq_group的vdisktime值来选定一个cfq_group进行服务,在处理cfq_group的过程通过优先级选择一个最需要服务的service tree。通过该Service tree得到最需要服务的cfq_queue。该过程在 cfq_select_queue 函数中实现

一个cfq_queue被选定之后,后面的过程和deadline算法有点类似。在选择request的时候需要考虑每个request的延迟等待时间,选择那种等待时间最长的request进行处理。但是,考虑到磁盘抖动的问题,cfq在处理的时候也会进行顺序批量处理,即将那些在磁盘上连续的request批量处理掉

cfq调度算法的参数
back_seek_max :磁头可以向后寻址的最大范围,默认值为16M
back_seek_penalty :向后寻址的惩罚系数。这个值是跟向前寻址进行比较的

fifo_expire_async :设置异步请求的超时时间。同步请求和异步请求是区分不同队列处理的,cfq在调度的时候一般情况都会优先处理同步请求,之后再处理异步请求,除非异步请求符合上述合并处理的条件限制范围内。当本进程的队列被调度时,cfq会优先检查是否有异步请求超时,就是超过fifo_expire_async参数的限制。如果有,则优先发送一个超时的请求,其余请求仍然按照优先级以及扇区编号大小来处理
fifo_expire_sync :这个参数跟上面的类似,区别是用来设置同步请求的超时时间
slice_idle :参数设置了一个等待时间。这让cfq在切换cfq_queue或service tree的时候等待一段时间,目的是提高机械硬盘的吞吐量。一般情况下,来自同一个cfq_queue或者service tree的IO请求的寻址局部性更好,所以这样可以减少磁盘的寻址次数。这个值在机械硬盘上默认为非零。当然在固态硬盘或者硬RAID设备上设置这个值为非零会降低存储的效率,因为固态硬盘没有磁头寻址这个概念,所以在这样的设备上应该设置为0,关闭此功能
group_idle :这个参数也跟上一个参数类似,区别是当cfq要切换cfq_group的时候会等待一段时间。在cgroup的场景下,如果我们沿用slice_idle的方式,那么空转等待可能会在cgroup组内每个进程的cfq_queue切换时发生。这样会如果这个进程一直有请求要处理的话,那么直到这个cgroup的配额被耗尽,同组中的其它进程也可能无法被调度到。这样会导致同组中的其它进程饿死而产生IO性能瓶颈。在这种情况下,我们可以将slice_idle = 0而group_idle = 8。这样空转等待就是以cgroup为单位进行的,而不是以cfq_queue的进程为单位进行,以防止上述问题产生
low_latency :这个是用来开启或关闭cfq的低延时(low latency)模式的开关。当这个开关打开时,cfq将会根据target_latency的参数设置来对每一个进程的分片时间(slice time)进行重新计算。这将有利于对吞吐量的公平(默认是对时间片分配的公平)。关闭这个参数(设置为0)将忽略target_latency的值。这将使系统中的进程完全按照时间片方式进行IO资源分配。这个开关默认是打开的

target_latency :当low_latency的值为开启状态时,cfq将根据这个值重新计算每个进程分配的IO时间片长度
quantum :这个参数用来设置每次从cfq_queue中处理多少个IO请求。在一个队列处理事件周期中,超过这个数字的IO请求将不会被处理。这个参数只对同步的请求有效
slice_sync :当一个cfq_queue队列被调度处理时,它可以被分配的处理总时间是通过这个值来作为一个计算参数指定的。公式为: time_slice = slice_sync + (slice_sync/5 * (4 - prio)) 这个参数对同步请求有效
slice_async :这个值跟上一个类似,区别是对异步请求有效
slice_async_rq :这个参数用来限制在一个slice的时间范围内,一个队列最多可以处理的异步请求个数。请求被处理的最大个数还跟相关进程被设置的io优先级有关

通常在Linux上使用的IO接口是同步方式的,进程调用 write / read 之后会阻塞陷入到内核态,直到本次IO过程完成之后,才能继续执行,下面介绍的异步IO则没有这种限制,但是当前Linux异步IO尚未成熟

目前Linux aio还处于较不成熟的阶段,只能在 O_DIRECT 方式下才能使用(glibc_aio),也就是无法使用默认的Page Cache机制

正常情况下,使用aio族接口的简要方式如下:

io_uring 是 2019 年 5 月发布的 Linux 5.1 加入的一个重大特性 —— Linux 下的全新的异步 I/O 支持,希望能彻底解决长期以来 Linux AIO 的各种不足
io_uring 实现异步 I/O 的方式其实是一个生产者-消费者模型:

逻辑卷管理
RAID0
RAID1
RAID5(纠错)
条带化

Linux系统性能调整:IO过程
Linux的IO调度
一个IO的传奇一生
理解inode
Linux 文件系统是怎么工作的?
Linux中Buffer cache性能问题一探究竟
Asynchronous I/O and event notification on linux
AIO 的新归宿:io_uring
Linux 文件 I/O 进化史(四):io_uring —— 全新的异步 I/O

F. linux系统如何查看网络IO

首先 、用top命令查看

top - 16:15:05 up 6 days, 6:25, 2 users, load average: 1.45, 1.77, 2.14

Tasks: 147 total, 1 running, 146 sleeping, 0 stopped, 0 zombie

Cpu(s): 0.2% us, 0.2% sy, 0.0% ni, 86.9% id, 12.6% wa, 0.0% hi, 0.0% si

Mem: 4037872k total, 4003648k used, 34224k free, 5512k buffers

Swap: 7164948k total, 629192k used, 6535756k free, 3511184k cached

查看12.6% wa

IO等待所占用的CPU时间的百分比,高过30%时IO压力高

其次、 用iostat -x 1 10

avg-cpu: %user %nice %sys %iowait %idle

0.00 0.00 0.25 33.46 66.29

Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util

sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

sdb 0.00 1122 17.00 9.00 192.00 9216.00 96.00 4608.00 123.79 137.23 1033.43 13.17 100.10

sdc 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

查看%util 100.10 %idle 66.29

如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘可能存在瓶颈。

idle小于70% IO压力就较大了,一般读取速度有较多的wait.

同时可以结合vmstat 查看查看b参数(等待资源的进程数)

vmstat -1

如果你想对硬盘做一个IO负荷的压力测试可以用如下命令

time dd if=/dev/zero bs=1M count=2048 of=direct_2G

此命令为在当前目录下新建一个2G的文件

我们在新建文件夹的同时来测试IO的负荷情况。

G. linux查看网络io使用率

sar -n DEV

不带其他参数 看当天的网络IO 缺省取样时间为1秒,间隔为10分钟
加 -f /var/log/sa/saxx可察看某日的历史,xx为当月或上月的日期(day of the month)前提是改文件存在

察看即时IO用sar -n DEV 1 999 表示取样间隔为1秒,取样999次

具体字段的含义我就不醉赘述了

H. 如何提高Linux服务器磁盘io性能

您好,很高兴为您解答。

在现有文件系统下进行优化:
linux内核和各个文件系统采用了几个优化方案来提升磁盘访问速度。但这些优化方案需要在我们的服务器设计中进行配合才能得到充分发挥。
文件系统缓存
linux内核会将大部分空闲内存交给虚拟文件系统,来作为文件缓存,叫做page cache。在内存不足时,这部分内存会采用lru算法进行淘汰。通过free命令查看内存,显示为cached的部分就是文件缓存了。

如何针对性优化:
lru并不是一个优秀淘汰算法,lru最大的优势是普适性好,在各种使用场景下都能起到一定的效果。如果能找到当前使用场景下,文件被访问的统计特征,针 对性的写一个淘汰算法,可以大幅提升文件缓存的命中率。对于http正向代理来说,一个好的淘汰算法可以用1GB内存达到lru算法100GB内存的缓存 效果。如果不打算写一个新的淘汰算法,一般不需要在应用层再搭一个文件cache程序来做缓存。

最小分配:
当文件扩大,需要分配磁盘空间时,大部分文件系统不会仅仅只分配当前需要的磁盘空间,而是会多分配一些磁盘空间。这样下次文件扩大时就可以使用已经分配好的空间,而不会频繁的去分配新空间。
例如ext3下,每次分配磁盘空间时,最小是分配8KB。
最小分配的副作用是会浪费一些磁盘空间(分配了但是又没有使用)

如何针对性优化:
我们在reiserfs下将最小分配空间从8KB改大到128K后提升了30%的磁盘io性能。如果当前使用场景下小文件很多,把预分配改大就会浪费很多 磁盘空间,所以这个数值要根据当前使用场景来设定。似乎要直接改源代码才能生效,不太记得了,09年的时候改的,有兴趣的同学自己google吧。

io访问调度:
在同时有多个io访问时,linux内核可以对这些io访问按LBA进行合并和排序,这样磁头在移动时,可以“顺便”读出移动过程中的数据。
SATA等磁盘甚至在磁盘中内置了io排序来进一步提升性能,一般需要在主板中进行配置才能启动磁盘内置io排序。linux的io排序是根据LBA进行的,但LBA是一个一维线性地址,无法完全反应出二维的圆形磁盘,所以磁盘的内置io排序能达到更好的效果。

如何针对性优化:
io访问调度能大幅提升io性能,前提是应用层同时发起了足够的io访问供linux去调度。
怎样才能从应用层同时向内核发起多个io访问呢?
方案一是用aio_read异步发起多个文件读写请求。
方案二是使用磁盘线程池同时发起多个文件读写请求。
对我们的http正向代理来说,采用16个线程读写磁盘可以将性能提升到2.5倍左右。具体开多少个线程/进程,可以根据具体使用场景来决定。

小提示:
将文件句柄设置为非阻塞时,进程还是会睡眠等待磁盘io,非阻塞对于文件读写是不生效的。在正常情况下,读文件只会引入十几毫秒睡眠,所以不太明显;而在磁盘io极大时,读文件会引起十秒以上的进程睡眠。

预读取:
linux内核可以预测我们“将来的读请求”并提前将数据读取出来。通过预读取可以减少读io的次数,并且减小读请求的延时。

如何针对性优化:
预读取的预测准确率是有限的,与其依赖预读取,不如我们直接开一个较大的缓冲区,一次性将文件读出来再慢慢处理;尽量不要开一个较小的缓冲区,循环读文件/处理文件。
虽然说“预读取”和“延迟分配”能起到类似的作用,但是我们自己扩大读写缓冲区效果要更好。

延迟分配:
当文件扩大,需要分配磁盘空间时,可以不立即进行分配,而是暂存在内存中,将多次分配磁盘空间的请求聚合在一起后,再进行一次性分配。
延迟分配的目的也是减少分配次数,从而减少文件不连续。

延迟分配的副作用有几个:
1、如果应用程序每次写数据后都通过fsync等接口进行强制刷新,延迟分配将不起作用
2、延迟分配有可能间歇性引入一个较大的磁盘IO延时(因为要一次性向磁盘写入较多数据)
只有少数新文件系统支持这个特性

如何针对性优化:
如果不是对安全性(是否允许丢失)要求极高的数据,可以直接在应用程序里缓存起来,积累到一定大小再写入,效果比文件系统的延迟分配更好。如果对安全性要求极高,建议经常用fsync强制刷新。

在线磁盘碎片整理:
Ext4提供了一款碎片整理工具,叫e4defrag,主要包含三个功能:
1、让每个文件连续存储
2、尽量让每个目录下的文件连续存储
3、通过整理空闲磁盘空间,让接下来的分配更不容易产生碎片

如何针对性优化:
“让每个目录下的文件连续存储”是一个极有价值的功能。
传统的做法是通过拼接图片来将这10张图片合并到一张大图中,再由前端将大图切成10张小图。
有了e4defrag后,可以将需连续访问的文件放在同一个文件夹下,再定期使用e4defrag进行磁盘整理。

实现自己的文件系统:
在大部分服务器上,不需要支持“修改文件”这个功能。一旦文件创建好,就不能再做修改操作,只支持读取和删除。在这个前提下,我们可以消灭所有文件碎片,把磁盘io效率提升到理论极限。

有一个公式可以衡量磁盘io的效率:
磁盘利用率 = 传输时间/(平均寻道时间+传输时间)

如若满意,请点击回答右侧【采纳答案】,如若还有问题,请点击【追问】

~ O(∩_∩)O~

I. Linux磁盘IO流程

文件IO的分层设计

先看图:

malloc的buf对应application buffer,用户空间;

fwrite是系统提供的最上层接口,也是最常用的接纤哗口。它在用户进程空间开辟一个CLib buffer,将多次小数据量相邻写操作(application buffer)先缓存起来,合并,最终调用write函数一次性写入(或者将大块数据分解多次write调用);

write函数通过调用系统调用接口,将数据从应用层到内核慎巧层,所以write会触发内核态/用户态切换。当数据到达page cache后,内核并不会立即把数据往下传递。而是返回用户空间。数据什么时候写入硬盘,有内核IO调度决定,所以write是一个异步调用;

read调用是先检查page cache里面是否有数据,如果有,就取出来返回用户,如果没有,就同步传递宽竖键下去并等待有数据,再返回用户,所以read是一个同步过程;

fclose隐含fflush函数,fflush只负责把数据从Clibbuffer拷贝到pagecache中返回,并没有刷新到磁盘上,刷新到磁盘上可以使用fsync函数;

即便fsync仍有可能没写到磁盘上,一是磁盘有缓存,二是即便关闭缓存也可能为了跑分没有真正关闭;

** 一致性
fwrite使用用户进程私有空间,多线程必然需要做同步。write如果写大小小于PIPE_BUF,是原子操作。根据已知信息,内核所做仅限于此,如果两个进程同时写文件,可能出现错乱,需要实测。

** 安全性
从前面的分层设计来看,使用fsync函数可以最大限度保障安全写入,但仍然没有绝对的安全性。

另外一张图

阅读全文

与linux文件io相关的资料

热点内容
海康威视数据怎么删除 浏览:826
ug编程哪个视图好用 浏览:866
福州龙泉哪里有学编程的 浏览:513
消保整改文件 浏览:145
重度贫血数据是多少 浏览:323
maya粒子表达式教程 浏览:84
抖音小视频如何挂app 浏览:283
cad怎么设置替补文件 浏览:790
win10启动文件是空的 浏览:397
jk网站有哪些 浏览:134
学编程和3d哪个更好 浏览:932
win10移动硬盘文件无法打开 浏览:385
文件名是乱码还删不掉 浏览:643
苹果键盘怎么打开任务管理器 浏览:437
手机桌面文件名字大全 浏览:334
tplink默认无线密码是多少 浏览:33
ipaddgm文件 浏览:99
lua语言编程用哪个平台 浏览:272
政采云如何导出pdf投标文件 浏览:529
php获取postjson数据 浏览:551

友情链接