在專欄一開始的時候,我和你說過,在計算機組成原理這門課裏面,不少設計的核心思路,都來源於性能。在前免講解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的瓶頸,以及這些瓶頸來自於哪些程序,你就能夠根據定位的結果來優化你本身的程序了。