前言
关于本章内容,设计的东西比较多。这里会有关于文件系统、磁盘、CPU等方面的知识,以及涉及到关于这方面的性能排查等。
术语
文件系统通过缓存和缓冲以及异步I/O等手段来缓和磁盘的延时对应用程序的影响。为了更详细的了解文件系统,以下就简单介绍一些相关术语:
- 文件系统:一种把数据组织成文件和目录的存储方式,提供了基于文件的存取接口,并通过文件权限控制访问。另外,一些表示设备、套接字和管道的特殊文件类型,以及包含文件访问时间戳的元数据。
- 文件系统缓存:主存(通常是DRAM) 的一块区域,用来缓存文件系统的内容,可能包含各种数据和元数据。
- 操作:文件系统的操作是对文件系统的请求,包括读、写、打开、关闭、创建以及其他操作。
- I/O:输入/输出。文件系统I/O有多种定义,这里仅指直接读写(执行I/O)的操作,包括读、写、状态统计、创建。I/O不包括打开文件和关闭文件。
- 逻辑I/O:由应用程序发给文件系统的I/O。
- 物理I/O:由文件系统直接发给磁盘的I/O。
- 吞吐量:当前应用程序和文件系统之间的数据传输率,单位是B/S。
- inode:一个索引节点时一种含有文件系统对象元数据的数据结构,其中有访问权限、时间戳以及数据指针。
- VFS:虚拟文件系统,一个为了抽象与支持不同文件系统类型的内核接口。
磁盘相关术语:
- 存储设备的模拟。在系统看来,这是一块物理磁盘,但是,它可能由多块磁盘组成。
- 传输总线:用来通信的物理总线,包括数据传输以及其他磁盘命令。
- 扇区:磁盘上的一个存储块,通常是512B的大小。
- I/O:对于磁盘,严格地说仅仅指读、写,而不包括其他磁盘命令。I/O至少由方向(读或写)、磁盘地址(位置)和大小(字节数)组成。
- 磁盘命令:除了读写之外,磁盘还会被指派执行其他非数据传输的命令(例如缓存写回)。
- 带宽:存储传输或者控制器能够达到的最大数据传输速率。
- I/O延时:一个I/O操作的执行时间,这个词在操作系统领域广泛使用,早已超出了设备层。
相关概念
文件系统延时
文件系统延时是文件系统性能一项主要的指标,指的是一个文件系统逻辑请求从开始到结束的时间。它包括消耗在文件系统、内核磁盘I/O子系统以及等待磁盘设备——物理I/O的时间。应用程序的线程通常在请求时阻塞,等地文件系统请求的结束。这种情况下,文件系统的延时与应用程序的性能直接和成正比关系。在某些情况下,应用程序并不受文件系统的直接影响,例如非阻塞I/O或者I/O由一个异步线程发起。
缓存
文件系统启动之后会使用主存(RAM)当缓存以提供性能。缓存大小随时间增长而操作系统的空余内存不断减小,当应用程序需要更多内存时,内核应该迅速从文件系统缓存中释放一些内存空间。文件系统用缓存(caching)提高读性能,而用缓冲(buffering)提高写性能。文件系统和块设备子系统一般使用多种类型的缓存。
随机I/O与顺序I/O
一连串的文件系统逻辑I/O,按照每个I/O的文件偏移量,可以分为随机I/O与顺序I/O。顺序I/O里每个I/O都开始于上一个I/O结束的地址。随机I/O则找不出I/O之间的关系,偏移量随机变化。随机的文件系统负载也包括存取随机的文件。由于存储设备的某些性能特征的缘故,文件系统一直以来在磁盘上顺序和连续的存放文件数据,以努力减小随机I/O的数目。当文件系统未能达到这个目标时,文件的摆放变得杂乱无章,顺序的逻辑I/O被分解成随机的物理I/O,这种情况被称为碎片化。
提示:关于文件系统更多内容,还请自行查阅相关理论。比如你还需要了解文件系统的预读、预取、写回缓存、同步写、裸I/O、直接I/O、内存映射文件、元数据等相关知识。
性能分析
具备背景知识是分析性能问题时需要了解的。比如硬件 cache;再比如操作系统内核。应用程序的行为细节往往是和这些东西互相牵扯的,这些底层的东西会以意想不到的方式影响应用程序的性能,比如某些程序无法充分利用 cache,从而导致性能下降。比如不必要地调用过多的系统调用,造成频繁的内核 / 用户切换等。如果想深入了解Linux系统,建议购买相关书籍进行系统的学习。下面我们介绍如何分析磁盘性能工具(其实准确来说,不只是磁盘):
iostat
汇总了单个磁盘的统计信息,为磁盘负载、使用率和饱和度提供了指标。默认显示一行系统总结信息,包括内核版本、主机名、日志、架构和CPU数量等,每个磁盘设备都占一行。
[root@localhost ~]# iostat
Linux 3.10.0-514.el7.x86_64 (localhost.localdomain) 2017年09月18日 _x86_64_(1 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.74 0.00 1.24 1.35 0.00 96.67
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
sda 14.43 456.85 60.82 218580 29098
scd0 0.02 0.09 0.00 44 0
dm-0 13.65 404.58 56.50 193571 27030
dm-1 0.27 2.23 0.00 1068 0
参数说明
- tps: 每秒事物数(IOPS)。
- kB_read/s、kB_wrtn/s: 每秒读取KB数和每秒写入KB数。
- kB_read、kB_wrtn: 总共读取和写入的KB数。
如下想输出更详细的内容,可以试试下面这个命令组合:
[root@localhost ~]# iostat -xkdz 1
Linux 3.10.0-514.el7.x86_64 (localhost.localdomain) 2017年09月18日 _x86_64_(1 CPU)
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.01 2.43 13.81 2.32 510.51 67.96 71.74 0.22 13.94 8.72 44.95 2.37 3.82
scd0 0.00 0.00 0.03 0.00 0.10 0.00 8.00 0.00 0.27 0.27 0.00 0.27 0.00
dm-0 0.00 0.00 10.52 4.73 452.10 63.13 67.56 0.44 28.56 10.41 68.93 2.47 3.76
dm-1 0.00 0.00 0.30 0.00 2.49 0.00 16.69 0.00 1.50 1.50 0.00 1.38 0.04
参数说明
- rrqm/s:每秒合并放入驱动请求队列的读请求数(当系统调用需要读取数据的时候,VFS将请求发到各个FS,如果FS发现不同的读取请求读取的是相同Block的数据,FS会将这个请求合并Merge)。
- wrqm/s:每秒合并放入驱动请求队列的写请求数。
- rsec/s:每秒发给磁盘设备的读请求数。
- wsec/:每秒发给磁盘设备的写请求数。
- rKB/s:每秒从磁盘设备读取的KB数。
- wKB/s:每秒向磁盘设备写入的KB数。
- avgrq-sz 平均每次请求大小,单位为扇区(512B)。
- avgqu-sz 在驱动请求队列和在设备中活跃的平均请求数。
- await: 平均I/O响应时间,包括在驱动请求队列里等待和设备的I/O响应时间(ms)。一般地系统I/O响应时间应该低于5ms,如果大于10ms就比较大了。这个时间包括了队列时间和服务时间,也就是说,一般情况下,await大于svctm,它们的差值越小,则说明队列时间越短,反之差值越大,队列时间越长,说明系统出了问题。
- svctm:磁盘设备的I/O平均响应时间(ms)。如果svctm的值与await很接近,表示几乎没有I/O等待,磁盘性能很好,如果await的值远高于svctm的值,则表示I/O队列等待太长系统上运行的应用程序将变慢。
- %util: 设备忙处理I/O请求的百分比(使用率)。在统计时间内所有处理IO时间,除以总共统计时间。例如,如果统计间隔1秒,该设备有0.8秒在处理IO,而0.2秒闲置,那么该设备的%util = 0.8/1 = 80%,所以该参数暗示了设备的繁忙程度。一般地,如果该参数是100%表示设备已经接近满负荷运行了(当然如果是多磁盘,即使%util是100%,因为磁盘的并发能力,所以磁盘使用未必就到了瓶颈)。
既然avgrq-sz是合并之后的数字,小尺寸(16个扇区或者更小)可以视为无法合并的实际I/O负载的迹象。大尺寸有可能是大I/O,或者是合并的连续负载。输出性能里最重要的指标是await。如果应用程序和文件系统使用了降低写延时的方法,w_await可能不那么重要,而更应该关注r_await。
对于资源使用和容量规划,%util仍然很重要,不过记住这只是繁忙度的一个度量(非空闲时间),对于后面有多块磁盘支持的虚拟设备意义不大。可以通过施加负载更好地了解这些设备:IOPS(r/s + w/s)以及吞吐量(rkB/s + wkB/s)。
iotop
包含磁盘I/O的top工具。
批量模式(-b)可以提供滚动输出。下面的演示仅仅显示I/O进程(-o),每5秒输出一次(-d5):
[root@localhost ~]# iotop -bod5
Total DISK READ : 0.00 B/s | Total DISK WRITE : 8.76 K/s
Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 24.49 K/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO COMMAND
21203 be/3 root 0.00 B/s 815.58 B/s 0.00 % 0.01 % [jbd2/dm-2-8]
22069 be/3 root 0.00 B/s 0.00 B/s 0.00 % 0.01 % [jbd2/dm-1-8]
1531 be/0 root 0.00 B/s 6.37 K/s 0.00 % 0.01 % [loop0]
3142 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.01 % [kworker/7:0]
21246 be/4 root 0.00 B/s 1631.15 B/s 0.00 % 0.00 % java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start
提示:
输出显示java进程正在以大约1631.15 B/s的速率施加磁盘写负载。其他有用的选项有-a,可以输出累计I/O而不是一段时间内的平均值,选项-o,只打印那些正在执行的磁盘I/O的进程。
当然显示磁盘的命令还有例如sar、iosnoop、perf、blktrace等命令,这里只列举常用命令即可。
性能调优
文件系统优化
关于文件系统优化,并没有太多的内容需要说明。就目前的情况,Redhat Enterprise 7系列默认更换为性能更好的XFS,这也是由于XFS在性能表现确实很好的原因。在我们使用的过程中,建议对XFS做一些简单的优化即可,比如执行格式化时指定额外的一些参数,挂载该分区时指定一些额外的挂载参数,这些都能够提高文件系统的相关性能。
格式化时的参数:
mkfs.xfs -d agcount=256 -l size=128m,lazy-count=1,version=2 /dev/diska1
mount时的参数:
defaults,noatime,nodiratime,nobarrier,discard,allocsize=256m,logbufs=8,attr2,logbsize=256k
磁盘相关优化
- 操作系统可调参数
包括ionice、资源控制和内核可调参数。
ionice
Linux中的ionice命令可以设置一个进程I/O调度级别和优先级。调度级别为整数,0表示无,不指定级别,内核会挑选一个默认值,优先级根据进程nice值选定;1表示实时,对磁盘的*别访问,如果误用会导致其他进程饿死;2表示尽力,默认调度级别,包括优先级 0~7,0为*;3表示空闲,在一段磁盘空闲的期限过后才允许进行I/O。如下:
ionice -c 3 -p 65552
cgroup
通过cgroup为进程或进程组提供存储设备资源控制机制。一般很少用到,不用考虑。
可调参数
/sys/block/sda/queue/scheduler:选择I/O调度器策略,是空操作、最后期限、an还是cfq;
- 磁盘设备可调参数
Linux上的hdparm(磁盘测试工具)工具可以设置多种磁盘设备的可调参数。
- 磁盘控制器可调参数