在专栏一开始的时候,我和你说过,在计算机组成原理这门课里面,不少设计的核心思路,都来源于性能。在前免讲解CPU的时候,相信你已经有了切身的感觉了。ios
大部分程序员开发的都是应⽤系统。在开发应用系统的时候,咱们遇到的性能瓶颈大部分都在I/O上。在第36讲讲解局部性原理的时候,咱们一块儿看了经过把内存看成是缓存,
来提高系统的总体性能。在第37讲讲解CPU Cache的时候,咱们一块儿看了CPU Cache和主内存之间性能的巨大差别nginx
然而,咱们知道,并非全部问题都能靠利⽤内存或者CPU Cache作一层缓存来解决。特别是在这个“大数据”的时代。咱们在硬盘上存储了愈来愈多的数据,
一个MySQL数据库的单表有个几千万条记录,早已经不算是什么罕见现象了。这也就意味着,用内存当缓存,存储空间是不够用的。大部分时间,
咱们的请求仍是要打到硬盘上。那么,这⼀讲咱们就来看看硬盘I/O性能的事儿。程序员
光看响应时间和吞吐率这两个指标,彷佛咱们的硬盘性能很不错、咱们平时往数据库里写入一条记录,也就是1KB左右的大小。咱们拿200MB去除以1KB,数据库
也可以在几毫秒时间返回、一秒钟可以传输的数据,也有200MB左右缓存
随机读写bash
顺序读写服务器
和咱们硬盘可以进⾏的操做数,也有好一个数量级的差别,由于不少时候,CPU指令发出去以后,不得不去“等”咱们的I/O操做完成,才能进入下一步的操做并发
那么,在实际遇到服务端程序的性能问题的时候,咱们怎么知道这个问题是否是来自于CPU等I/O来完成操做呢?别着急,咱们接下来,
就经过top和iostat这些命令,一块儿来看看CPU到底有没有在等待io操做。性能
top - 06:26:30 up 4 days, 53 min, 1 user, load average: 0.79, 0.69, 0.65 Tasks: 204 total, 1 running, 203 sleeping, 0 stopped, 0 zombie %Cpu(s): 20.0 us, 1.7 sy, 0.0 ni, 77.7 id, 0.0 wa, 0.0 hi, 0.7 si, 0.0 st KiB Mem: 7679792 total, 6646248 used, 1033544 free, 251688 buffers KiB Swap: 0 total, 0 used, 0 free. 4115536 cached Mem
avg-cpu: %user %nice %system %iowait %steal %idle 17.02 0.01 2.18 0.04 0.00 80.76 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 1.81 2.02 30.87 706768 10777408
你会看到,这个命令⾥,不只有iowait这个CPU等待时间的百分⽐,还有⼀些更加具体的指标了,而且它仍是按照你机器上安装的多块不一样的硬盘划分的。
这⾥的tps指标,其实就对应着咱们上⾯所说的硬盘的IOPS性能。⽽kB_read/s和kB_wrtn/s指标,就对应着咱们的数据传输率的指标。
知道实际硬盘读写的tps、kB_read/s和kb_wrtn/s的指标,咱们基本上能够判断出,机器的性能是否是卡在I/O上了。那么,接下来,
咱们就是要找出究竟是哪个进程是这些I/O读写的来源了。这个时候,你须要“iotop”这个命令。测试
iotop Total DISK READ : 0.00 B/s | Total DISK WRITE : 15.75 K/s Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 35.44 K/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 104 be/3 root 0.00 B/s 7.88 K/s 0.00 % 0.18 % [jbd2/sda1-8] 383 be/4 root 0.00 B/s 3.94 K/s 0.00 % 0.00 % rsyslogd -n [rs:main Q:Reg] 1514 be/4 www-data 0.00 B/s 3.94 K/s 0.00 % 0.00 % nginx: worker process
经过iotop这个命令,你能够看到具体是哪⼀个进程实际占⽤了⼤量I/O,那么你就能够有的放⽮,去优化对应的程序了。
上面的这些示例里,不论是wa也好,tps也好,它们都很小。那么,接下来,我就给你用Linux下,用stress命令,来模拟一个高I/O复杂的状况,来看看这个时候的iowait是怎么样的。
我在一台云平台上的单个CPU核⼼的机器上输⼊“stress-i2”,让stress这个程序模拟两个进程不停地从内存里往硬盘上写数据。
stress -i 2
top top - 06:56:02 up 3 days, 19:34, 2 users, load average: 5.99, 1.82, 0.63 Tasks: 88 total, 3 running, 85 sleeping, 0 stopped, 0 zombie %Cpu(s): 3.0 us, 29.9 sy, 0.0 ni, 0.0 id, 67.2 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 1741304 total, 1004404 free, 307152 used, 429748 buff/cache KiB Swap: 0 total, 0 free, 0 used. 1245700 avail Mem
iostat 2 5 avg-cpu: %user %nice %system %iowait %steal %idle 5.03 0.00 67.92 27.04 0.00 0.00 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 39762.26 0.00 0.00 0 0
若是咱们经过iostat,查看硬盘的I/O,你会看到,里面的tps很快就到了4万左右,占满了对应硬盘的IOPS。
iotop Total DISK READ : 0.00 B/s | Total DISK WRITE : 0.00 B/s Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 0.00 B/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 29161 be/4 xuwenhao 0.00 B/s 0.00 B/s 0.00 % 56.71 % stress -i 2 29162 be/4 xuwenhao 0.00 B/s 0.00 B/s 0.00 % 46.89 % stress -i 2 1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init
相信到了这里,你也应该学会了怎么经过top、iostat以及iotop,一步一步快速定位服务器端的I/O带来的性能瓶颈了。
你也能够本身经过Linux的man命令,看一看这些命令还有哪些参数,以及经过stress来模拟其余更多不一样的性能压力,看看咱们的机器负载会发生什么变化。
这一讲里,咱们从硬盘的两个核心指标,响应时间和数据传输率,来理解和研究I/O的性能问题。你也本身能够经过as ssd这样的性能评测软件,看一看本身的硬盘性能。
在顺序读取的状况下,不管是HDD硬盘仍是SSD硬盘,性能看起来都是很不错的。不过,等到进行随机读取测试的时候,硬盘的性能才能见了真章。由于在大部分的应用开发场景下,
咱们关注的并非在顺序读写下的数据量,而是每秒钟可以进行输入输出的操做次数,也就是IOPS这个核心性能指标。
你会发现,即便是使PCI Express接口的SSD硬盘,IOPS也就只是到了2万左右。这个性能,和咱们CPU的每秒20亿次操做的能⼒⽐起来,可就差得远了。
因此不少时候,咱们的程序对外响应慢,其实都是CPU在等待I/O操做完成。
在Linux下,咱们能够经过top这样的命令,来看整个服务器的总体负载。在应⽤响应慢的时候,咱们能够先经过这个指令,来看CPU是否在等待I/O完成⾃⼰的操做。
进一步地,咱们能够经过iostat这个命令,来看到各个硬盘这个时候的读写状况。⽽iotop这个命令,可以帮助咱们定位到究竟是哪⼀个进程在进行大量的I/O操做。
这些命令的组合,能够快速帮你定位到是否是咱们的程序遇到了I/O的瓶颈,以及这些瓶颈来自于哪些程序,你就能够根据定位的结果来优化你本身的程序了。