当前位置: 首页 > 科技观察

Linux优化IO子系统监控调优

时间:2023-03-12 01:53:19 科技观察

Linux优化IO子系统作为服务器主机,最好的两种IO类型:1.磁盘IO2。NetworkIO这是我们调整最多的两个部分diskIO是如何实现的?在内存调优中已经提到,为了加速性能,linux内核一般会尝试将磁盘上慢速设备上的文件缓存到内存中,以达到加速的效果;虚拟内存概念:读写都是在内存中完成的。当进程运行在cpu上时,进程需要访问自己地址空间中的某个内存页。当进程需要访问页面中的数据时,这个页面最终必然对应于物理内存中的某个物理页面,进程只能看到自己的线性地址空间,而这个地址是不存在的。这个地址一旦被访问,就会通过MMU(内存管理单元)机制存储当前进程。线性地址到物理地址的映射表,通过MMU实现对应的地址查询,得到映射地址。虽然最终进程访问的数据来自于映射地址,但这种访问称为虚拟地址或虚拟内存如果这个进程打开的文件由于使用了交换内存或其他原因,很长时间没有被访问过methods,这个文件对应的内存已经被清空了,所以内存中存放的是mmu地址转换后的地址对应的数据,如果数据不存在,这时候就会出现pagefault。我们也称它为页面错误。CPU将进入内核模式并访问磁盘。CPU每次访问内存需要3个周期,访问磁盘需要N个周期。首先,它需要定位到数据的确切位置,然后定位到物理内存中的数据空间,最后将数据与存储总线相连,从而实现数据从磁盘传输到内存——blockin是当我们找到一个空闲空间,但实际上当进程访问这个数据时,需要访问新位置的数据,所以我们需要更新映射表,明确说明要访问什么空间对应的转换位置到逻辑地址的逻辑地址,让进程重新发起一次访问。这时候就需要先查TLB(cachebuffer),然后再查表,磁盘加载到内存的过程会引起IO。如果进程修改了数据,最后需要将数据写入磁盘,而写入磁盘的过程使得数据比原来的文件大。具体来说,文件系统模块按照流程发起请求,内核指挥文件系统模块打开更多的存储块,然后存储数据,这个过程叫做blockout#buffer负责缓存之前缓冲的,然后如果有N个entry,buffer只能缓存有限的个数,那么命中率可能会很低,如果我们使用hugepages,那么命中率率可以大大提高机械硬盘的特点同一个方向的操作组合起来完成,然后这个方向结束之后,就是另一个方向。对于硬盘来说,读写是不同类型的操作,读写不能同时进行。磁盘如何运行?将一个或多个进程的读操作合并在一起,将一个或多个进程的写操作读并合并在一起,所以读写操作是两种不同类型的操作,是同向合并的。如果是读文件,这个文件一定来自磁盘。如果是写文件,那么对于进程来说,写内存就已经完成了。那么用户对计算机性能的感知来自阅读,因为阅读必须和IO交互1.阅读是同向合并2.写作也需要合并,两者是不同方向的操作,因为很多资源可以保存在同一个方向。读要先满足,写不能等太久,所以必须要有一个好的算法,让其在不让用户觉得性能下降的情况下,尽可能的满足。因此,在IO系统上有一个非常重要的模块---IO调度器。这可能是一个理想的情况。IO调度器本身完成后,终端用户实现写入时在进程层面看到的数据是文件接口,所以当输出文件接口时,也就意味着以文件接口的形式输出磁盘空间。它需要文件系统,也就是说进程和磁盘上的数据都依赖于文件系统,所以用户的请求首先到文件系统,文件系统通过内核输出一个虚拟文件接口(VFS)。通过VFS系统相关模块找到每个具体的文件,当然就是对应的文件,然后通过vfs转换成什么就可以了。文件系统接下来将数据存储之后,最终以磁盘块的形式存储在磁盘上,所以这些文件系统最终会将数据转化为磁盘块,所以接下来就有了块层。块层主要是将数据转换成磁盘块格式,再将磁盘块格式转换成调度存储在磁盘上,如下图所示:(1)用户进程实现写操作实现系统调用(2)用户的写操作必须与VFS进行交互(3)VFS需要将其替换为特定的文件系统(4)存储在虚拟文件系统中的单个文件将转换为页模式(pagecache)(5)写入后,使用blockbuffer快速缓冲(缓冲的原因是因为磁盘太慢,所以写的时候需要缓冲)(6)然后每个pagecache通过bio转换成一个block,在block中缓冲在这一层缓存下来#p#这是bufferqueue,block层实现缓冲后,每个block最终都会交给block层处理。块层中最重要的组件是IO调度程序。IO调度器接收blockbuffer发送的多个请求块,这多个请求块需要排序:同向合并,图中都是写操作至于怎么排序,最接近写请求的先满足,然后IOschedulingcontroller的主要作用是尽可能将随机IO合并为顺序IO。本文转载自http://yijiu.blog.51cto.com,但是我们要读饥饿,不能写饥饿,所以我们要交替。所以:(10)IO调度器调度完成后提交给DeviceDriver,DeviceDriver控制磁盘控制器,控制器将电信号转换为磁信号写入磁盘为什么随机读写是比sequentialreadandwrite慢:Randomreadandwrite:我们可以写入任意磁道的任意扇区,然后硬盘磁头可能来回摇动完成一次写入SequenceReadandwrite:可以通过一个方向转动来完成,无需移动磁臂。磁头运行是电磁运动,而磁臂运行是机械运动,所以随机读写性能比任何时候的顺序读写都要差。许多调度算法IO调度器实际上是由程序完成的调度算法。对于Linux,2.6内核一共有四个1.CFQ是完全公平队列,比较适合交互场景。写请求有自己的满足期限。当deadline到来时,必须满足要求(一般推荐在数据库服务器上使用这种调度算法)3.Anticpatory期望任何一个数据被读取后,可能与其相邻的数据也可能被读取,所以它实现的一般方法是,如果读取后不满足,则不处理。需要等待一段时间,检查是否访问过类似的数据。如果是,马上满足,所以这个只能用在行为估计的场景4.noop不排队不合并,先到先得#像固态硬盘,因为不是机械硬盘驱动,它的读写即使是随机IO,它的性能和顺序IO相差不是很大,但是如果你想让调度器调用它的算法,那么调度器本身会占用大量的CPU时钟周期,并且可能得不偿失,所以这种场景下noop是最好的算法up和reordered在操作系统级别,这是得不偿失的,所以RAID设备有自己的scheduler,***也使用noop。一般来说,默认是CFQ同样的场景,适用的算法可能不同。例如,如果是web服务器,它只访问web上分区的页面数据。如果是db数据库,则访问db数据库的文件。适用的算法可能不一样,因为他们的访问方式不同,所以这时候我们需要修改他们的调度算法CFQ更适合交互场景,所以很多情况下服务器会设置为Deadline,当然了只是一个假设具体需要自己测试再做决定观察当前磁盘IO活动,一般使用ethstatusiotiopt-ioprofilesar等工具查看哪些进程导致IO较高等。这里我们使用sar观察其状态信息。本文来自http://yijiu.blog。51cto.com转载请说明,转载可耻示例:[root@node3~]#sar-d15Linux2.6.32-431.20.3.el6.x86_64(node3.test.com)09/20/2014_x86_64_(4CPU)09:16:00PMDEVtpsrd_sec/swr_sec/savgrq-szavgqu-szawaitsvctm%util09:16:01PMdev252-046.460.0046795.961007.132.65580.002.2610.5109:16:01PMDEVtpsrd_sec/swr_sec/savgrq-szavgqu-szawaitsvctm%util09:16:02PMdev252-03.000。00144.0048.000.001.331.000.3009:16:02PMDEVTPSRD_SEC/SWR_SEC/SAVGRQSZAVGRQ-SZAVGQUQUSVCTMSVCTM;09:16:16:16:03%util09:16:04PMdev252-00.000.000.000.000.000.000.000.0009:16:04PMDEVtpsrd_sec/swr_sec/savgrq-szavgqu-szawaitsvctm%util09:16:05PMdev252-072.730.0059967.68824.562.6135.881.218.79使用参数-p打印出sda,hdc等磁盘设备名,如果不使用参数-p,设备节点可能是dev8-0,dev22-0参数说明:tps:每秒物理磁盘的I/O次数。多个逻辑请求会合并为一个I/O磁盘请求,一次传输的大小是不确定的。rd_sec/s:每秒读取的扇区数。avgrq-sz:平均每个从设备的I/O操作的数据大小(扇区)。avgqu-sz:磁盘请求队列的平均长度。await:每次请求从请求磁盘操作到系统处理完成的平均消耗时间,包括请求队列等待时间,单位为毫秒(1秒=1000毫秒)。(一个完成的任务,完成它的IO所花费的平均时间)svctm:系统处理每个请求的平均时间,不包括在请求队列中消耗的时间,%util:I/O请求占CPU的百分比,比值越大越饱满,我们通常经验:svctm不超过0.5;await不超过5;主要看当前设备的核心点:1.tps(iops)越高,但%util越低,iocapability的容量越大。2、await和svctm越低越好,说明io响应延迟很低,iops能力高。手动做。增加队列长度#p#格式:/sys/block/vda(特定设备)/queue/nr_requests由于我这里运行的是kvm虚拟机,所以设备号默认以vdx开头。默认队列是128长度[root@node3~]#cat/sys/block/vda/queue/nr_requests128这个值可以调大一点读取数据的kb数也是默认128[root@node3~]#cat/sys/block/vda/queue/read_ahead_kb128这个值也可以调大,具体多少看你自己了。本文来自http://yijiu.blog。51cto.com转载,请说明一下,CFQ完全公平队列IO调度的耻辱副本,在进程间平均分配,主要是根据进程的IO需求。IO容量是均匀分布和调度的。所以在交互环境下,这种方法比较实用,但是在RHEL6.4上是提供三种不同的调度级别:1.实时RT2。***效果BE3。空闲我们可以使用ionice命令手动分配调度级别,或者使用iopro_set系统调用以编程方式分配。当然,这涉及到发展水平。real-timeschedulinglevel和***Effect两个level都有8个IOlevel。数字越小,优先级越高。***效果是默认的调度级别是4,不需要改变和修改CFQ来调整它的性能。Parameterfile:/sys/block/vda/queue/iosched/修改默认调度器算法:[root@node3~]#cd/sys/block/vda/queue/[root@node3queue]#lsadd_randomhw_sector_sizemax_hw_sectors_kbminimum_io_sizephysical_block_sizeschedulerdiscard_granularityioschedmax_sectors_kbnomergesread_ahead_kbunpriv_sgiodiscard_max_bytesiostatsmax_segmentsnr_requestsrotationaldiscard_zeroes_datalogical_block_sizemax_segment_sizeoptimal_io_sizerq_affinity而在其上层目录里,有一个scheduler文件查看scheduler文件[root@node3queue]#catschedulernoopanticipatorydeadline[cfq]因此,如果更改磁盘IOscheduler,会发现这个目录对应的scheduler。请注意,它仅针对每个磁盘进行调整。如果有很多块磁盘的话,需要对应每个磁盘进行修改。没办法用sysctl来控制。要想启动生效,只能写到rc.local或者init脚本中。更改调度算法后,可以查看目录[root@node3queue]#ls/sys/block/vda/queue/iosched/back_seek_maxfifo_expire_asyncgroup_idlelow_latencyslice_asyncslice_idleback_seek_penaltyfifo_expire_syncgroup_i目录下的文件solationquantumslice_async_rqslice_sync修改算法[root@node3queue]#echodeadline>scheduler[root@node3queue]#catschedulernoopanticipatory[deadline]cfq再次观察iosched目录,查看是否有变化[root@node3queue]#ls/sys/block/vda/queue/iosched/fifo_batchfront_mergesread_expirewrite_expirewrites_starved所以我们改变调度算法后,每个调度算法在这个目录下都有很多可调参数,每个参数都有一个值,但是表示为它的文件内容,每个调度器的值通过修改可以优化调度器的工作特性。例如,对于CFQ,可以调整以下值:back_seek_maxreverseseek可能会有负面影响,可以在负载小的时候启用,否则不要使用过多的reverseseek值back_seek_penal作为惩罚用于反向搜索。如果一定要使用reverseseek,就必须对其进行一定的惩罚。一旦惩罚完成,你必须向前寻找更多的次数。fifo_expire_async用于控制异步请求等待的时间长短,默认为250毫秒,超时后无法满足的异步请求会被移到调度队列中,也就是重新调度通常同步请求的fifo_expire_sync不需要调整这些值。严格来说,写操作是在内存中完成一个周期后同步到硬盘的。从计算机的角度来看,这种操作称为异步,而同步就是保证数据尽快写入磁盘,数据不会停留在内存中,直接写入数据到具有low_latecy和低延迟的磁盘。简单的说,每个进程都可能发起读写请求。这意味着用户读写请求的最终满足是按进程划分的。在这个前提下,需要考虑每个进程都需要满足。所以,我们一定要关注每个进程在发起IO请求后等待的时间。如果启用这个值,意味着只要每个进程发起读写请求,就必须尽快满足。默认情况下,启用低延迟。在桌面系统环境中,低延迟是非常必要的。quantumCFQ一次可以发出的IO请求数,一个batch***可以调度的IO数和IO队列的深度是有限制的。简单的说,就是定义设备一次可以接收到的IO请求的队列长度。有很多,这个值可以适当调整,如果有很多顺序写,那么不建议调整#p#设置IO允许消耗一个IO请求操作的时间,应该执行多长时间一次,应该执行多长时间,按理说只要没有硬盘损坏,就可以正常运行,在正常范围内,那就应该写入和读取了。所以我们需要定义每次读写请求允许的时间,那么就是以下参数的含义:slice_async定义异步写的超时值。每个异步写操作的最长持续时间是多少?默认值为40秒。空闲时间slice_idle等待IO请求。slice_sync定义同步写操作的超时值。因为同步比较慢,它的默认值是100秒,因为是直接从进程到磁盘,所以超时时间会比较长。在桌面环境和服务环境下,如果都使用CFQ调度器,它们的工作特性不一定,也就是说我们要注意其背后的工作机制参数也不同,所以需要调整一些值并做一些测试判断Deadline***DeadlineScheduling***deadline如图,分为3个队列,分别是:·Readqueue·Writequeue·Sortingqueues这些队列都集成到dispatch中队列,然后满足磁盘。在我们从任何队列中选择一个要满足的操作之前,我们必须确保此类操作不能超过截止日期。当操作被放入队列时,给他一个倒数计时器。在倒数计时器用完之前,它需要赶紧放入分发队列,然后同步到硬盘。对于服务器来说,这种方法是很理想的。常用的可调参数fifo_batch发送单个batch的读写次数。数据取出并满足,但有写操作需要排序;默认是16,设置更多的值会得到更好的流量,但是会增加延迟。比如一个batchreads是16个,那么我们改成32个,那就意味着写的时间会更高。当然,一切还要看测试数据。不管怎么调整,还是换成SSD硬盘比较好。front_merges可以将多个请求合并在一起,但是有些请求根本不连续,无法合并。一起,那么我们就可以在IO满足之前禁止合并。禁止合并可能会带来随机读写的特性,但是允许合并也有一定的副作用,就是必须要花时间去排序read_expire每次读操作必须有多长时间?满足之内,默认半秒write_expire每次写操作必须满足多长时间,默认5秒#写操作可以延迟满足writes_starved定义一个batch可以处理多少个readbatches,值越大,读的效果越好,默认为2,表示读2批,写1批。如果服务器读多写少,内存缓冲区足够大,可以增加。Noop如果系统绑定CPU,使用高速存储(SSD),这是最好的IO调度器。如果改成noop,调整参数的话,需要直接挑战/sys/block/vda/queue下的参数,而不是scheduler参数add_random,它的作用是不是使用业务池max_sectors_kb,是什么默认情况下发送到磁盘的最大请求?,默认为512kb。我们知道每个扇区是512字节,所以每次发送512kb就是发送N个扇区,我们可以调整或者增减这个值,对于固态硬盘来说不是所谓的扇区概念,所以我们可以Tune。在这种情况下,建议减少max_hw_sectors_kb以删除块大小。我们可以使用压力测试工具进行测试。记录大小范围从512kb到1MB。将该值设置为具有最佳效果的值。当然,压力测试与实际场景不同。in和out,所以充分考虑环境尽量模拟真实场景,尽量模拟随机读写nr_request请求队列的值,可以降低rotational的值如果是SSD硬盘,将该值设置为0,在不同CPU处理IO时,禁用TriggerIO中的轮转方式rq_affinity。一般来说,同一个IO最好在同一个CPU上处理,因为CPU只处理中断。所以SSD环境下常用的调整参数有:max_sectors_kbnr_requestsoptimal_io_sizerotational如何测试性能是否调整?完善常用的硬盘压力测试工具aio-stressiozonefio了解磁盘IO活动状态分析工具blktrace磁盘IO瓶颈分析工具blkparsegnuplot本文来自http://yijiu.blog.51cto.com:GeneralideaofIO优化·***更换SSD·调整raid级别·选择IO调度器·根据场景选择合适的文件系统·配置所选调度器的参数·使用工具分析优化结果是否满意·写在博客启动项中的帖子地址:http://yijiu.blog.51cto.com/433846/1556382