2020年4月12日 星期日

Fio 輸出內容的解釋 與 設定檔案 範例


翻譯原文來源

fio,又稱為Flexible IO Tester,是Jens Axboe編寫的應用程序。Jens是Linux Kernel中block IO subsystem的維護者。fio從多個方面來看類似於更古老的ffsb工具,但他們之間似乎沒有任何關係。作為一個強大的工具,fio可以產生足夠多的任意類型的負載(arbitrary load)。作為權衡,fio不容易學習,這就是這篇文章的目的。

  • 配置
  • 原始輸出
配置
以下是一個50/50讀寫的垃圾處理IO (Trashing IO)負載,對於多個盤進行的讀寫。
5分鐘,磁盤垃圾處理測試,50/50讀寫在每個盤上產生相同數量的隨機讀和寫IO,為每個盤產生測試數據。
# a 5 minute disk thrashing benchmark
# generates equal amounts of random read and write IO on every drive
# will generate metrics for each drive
[global]
ioengine=libaio
direct=1
unified_rw_reporting=1
rw=randrw
time_based=1
runtime=300s

<strong># Seagate 7200RPM SAS 512G ST9500430SS (sdb)</strong>
[/dev/disk/by-path/pci-0000:03:00.0-sas-0x5000c5000d7f96d9-lun-0]
write_lat_log=7200RPMSAS-0x5000c5000d7f96d9

<strong># Seagate 7200RPM Enterprise SATA 1TB ST31000340NS (sdg)</strong>
[/dev/disk/by-id/wwn-0x5000c500151229dd]
write_lat_log=7200RPMEnterpriseSATA-0x5000c500151229dd

<strong># Samsung 840 Pro 128GB (on a 3G SATA port) (sdd)</strong>
[/dev/disk/by-id/ata-Samsung_SSD_840_PRO_Series_S1ANNSADB05219A]
write_lat_log=SSDSATA-S1ANNSADB05219A

# 2x SAS drives with GPT partition & MDRAID0 (sdi1 + sdc1)
<strong># Seagate 7200RPM SAS 512G ST9500430SS</strong>
[/dev/disk/by-id/md-uuid-6bb71ed6:e4410fc9:b27af0b7:0afe758d]
write_lat_log=7200RPMSAS-MDRAID0

原始輸出
以上鍊接可打開上述fio配置的原始輸出。

接下來按照每個部分分析輸出內容。這裡顯示的數據是Samsung 840 Pro SSD,其他盤的數據稍後再深入研究。
對於每一個部分的描述在輸出文字下面。

read : io=10240MB, bw=63317KB/s, iops=15829, runt=165607msec
第一行很容易讀懂。fio做了10GB的IO,速率63.317MB/s,總IOPS 15829 (默認4k block size),運行了2分鐘45秒。

你看到的第一個延遲(Latency)數據是slat,或稱為submission latency。這個值和他的名字很相像,代表“盤需要多久將IO提交到kernel做處理?”。
slat (usec): min=3, max=335, avg= 9.73, stdev= 5.76
我起初認為submission latency對於性能調試沒有用,但是下面的數據讓我改變了觀點。269usec或1/4 ms看起來是噪音(noise),需要關註一下。我還沒有做任何調試,所以我猜測改變scheduler以告訴kernel這不是機械硬盤會有效果。
以下是從其他盤上得到的更多例子。
 slat (usec): min=3, max=335, avg= 9.73, stdev= 5.76 (SATA SSD)
 slat (usec): min=5, max=68,  avg=26.21, stdev= 5.97 (SAS 7200)
 slat (usec): min=5, max=63,  avg=25.86, stdev= 6.12 (SATA 7200)
 slat (usec): min=3, max=269, avg= 9.78, stdev= 2.85 (SATA SSD)
 slat (usec): min=6, max=66,  avg=27.74, stdev= 6.12 (MDRAID0/SAS)

 clat (usec): min=1, max=18600, avg=51.29, stdev=16.79
接下來是completion latency。這是命令提交到kernel到IO做完之間的時間,不包括submission latency。在老版本的fio中,這是估計應用級延遲的最好指標。

緯度(USEC):最小值= 44,最大值= 18627,平均= 61.33,標準差= 7.91
在我看來,'lat'是一個新的指標,在man或者文檔中都沒有描述。分析C代碼,似乎這個值是從IO結構體創建時刻開始,直到緊接著clat完成,這個算法最好地表現出了應用程序的行為。

  1. clat percentiles (usec):
  2. | 1.00th=[ 42], 5.00th=[ 45], 10.00th=[ 45], 20.00th=[ 46],
  3. | 30.00th=[ 47], 40.00th=[ 47], 50.00th=[ 49], 60.00th=[ 51],
  4. | 70.00th=[ 53], 80.00th=[ 56], 90.00th=[ 60], 95.00th=[ 67],
  5. | 99.00th=[ 78], 99.50th=[ 81], 99.90th=[ 94], 99.95th=[ 101],
  6. | 99.99th=[ 112]
Completion latency百分數的解釋一目了然,可能是輸出信息中最有用的部分。我看了代碼,這不是slat+clat,而是用了單獨的結構體記錄。
這個列表可以在config文件中配置。在精簡輸出模式下有20個這樣的格式,%f=%d; %f=%d;... 解析這樣的輸出格式會很有趣。

作為比較,這裡列出一個7200RPM SAS硬盤運行完全相同的負載的統一部分數據。
希捷7200RPM SAS 512G ST9500430SS
clat percentiles (usec):
     |  1.00th=[ 3952],  5.00th=[ 5792], 10.00th=[ 7200], 20.00th=[ 8896],
     | 30.00th=[10304], 40.00th=[11456], 50.00th=[12608], 60.00th=[13760],
     | 70.00th=[15168], 80.00th=[16768], 90.00th=[18816], 95.00th=[20608],
     | 99.00th=[23424], 99.50th=[24192], 99.90th=[26752], 99.95th=[28032],
     | 99.99th=[30080]

    bw (KB  /s): min=52536, max=75504, per=67.14%, avg=63316.81, stdev=4057.09
帶寬(bandwidth)的意思顯而易見,而per=part就不是很好理解。文檔上說這個值是指在單個盤上跑多個負載,可以用來看每個進程消耗了多少IO。對於我這樣把fio跑在多個盤的情況,這個值意義不大。但由於SSD和機械硬盤混合使用,這個值挺有趣。
下面是另一個SAS硬盤,佔測試的所有4個盤總IO的0.36%。
    bw (KB  /s): min=   71, max=  251, per=0.36%, avg=154.84, stdev=18.29

    lat (usec) :   2= 0.01%,   4=0.01%,  10=0.01%,   20=0.01%, 50=51.41%
    lat (usec) : 100=48.53%, 250=0.06%, 500=0.01%, 1000=0.01%
    lat (msec) :   2= 0.01%,   4=0.01%,  10=0.01%,   20=0.01%

latency分佈部分我看了幾遍才理解。這是一組數據。與三行使用一樣的單位不同,第三行使用了毫秒(ms),使得文本寬度可控。把第三行讀成2000, 4000, 10000, 20000微秒(us)就更清晰了。
這組數據表示latency的分佈,說明了51.41%的request延遲小於50微秒,48.53%的延遲小於100微秒(但是大於50微秒),以此類推。

lat (msec) : 4=1.07%, 10=27.04%, 20=65.43%, 50=6.46%, 100=0.01%
如果想用快速腳本解析這些繁瑣的數據,你可能需要知道,最後一部分會省略那些沒有數據的項。例如,我使用的SAS盤沒有IO可以在1毫秒中完成,所以只有一行。

cpu          : usr=5.32%, sys=21.95%, ctx=2829095, majf=0, minf=21
這是用戶/系統CPU佔用率,進程上下文切換(context switch)次數,主要和次要(major and minor)頁面錯誤數量(page faults)。由於測試是配置成使用直接IO,page faults數量應該極少。

IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
Fio有一個iodepth設置,用來控制同一時刻發送給OS多少個IO。這完全是純應用層面的行為,和盤的IO queue不是一回事。這裡iodepth設成1,所以IO depth在全部時間都是1。

     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
submit和complete代表同一時間段內fio發送上去和已完成的IO數量。對於產生這個輸出的垃圾回收測試用例來說,iodepth是默認值1,所以100%的IO在同一時刻發送1次,放在1-4欄位裡。通常來說,只有iodepth大於1才需要關注這一部分數據。
我會找時間測試多種調度策略,這些數據會變得更有趣。

issued    : total=r=2621440/w=0/d=0, short=r=0/w=0/d=0
發送的IO數量。這裡出現了奇怪的現象,因為這是50/50的讀寫負載,照道理應該有相同數量的write。我猜測把unified_rw_reporting打開是的fio把所有的IO都認為是read。
如果你在直接IO測試是看到了IO值很低,那麼可能是出問題了。我在Linux kernel中找到參考說這種現象發生在文件末尾EOL或可能是設備的尾端。

latency   : target=0, window=0, percentile=100.00%, depth=1
Fio可以配置一個延遲目標值,這個值可以調節吞吐量直到達到預設的延遲目標。我還沒有太多深入了解這部分。在基於時間或和容量的測試中,這行通常看起來一樣。四個值分別代表預設的latency_target, latency_window, latency_percentile和iodepth。

Run status group 0 (all jobs):
Fio支持把不同的測試聚合。例如,我可以用一個配置文件混合包含SSD和HDD,但是設置分組(group)把IO單獨匯總。我現在還沒涉及這個功能,但未來會用到。

MIXED: io=12497MB, aggrb=42653KB/s, minb=277KB/s, maxb=41711KB/s, mint=300000msec, maxt=300012msec

最後,匯總輸出吞吐量和時間。io=表示總共完成的IO數量。在基於時間的測試中這是一個變量,在基於容量的測試中,這個值能匹配size參數。aggrb是所有進程/設備的匯總帶寬。minb/maxb表示測量到的最小/最大帶寬。mint/maxt表示測試的最短和最長耗時。和io=參數類似,時間值對於基於時間的測試應該能匹配runtime參數,對於基於容量的測試是一個變量。



LINUX FIO 測試IO工具 設定檔


[global]

filename=/dev/nullb0

ioengine=libaio
#ioengine=sync

#direct=bool
#If value is true, use non-buffered I/O. This is usually O_DIRECT.
#Note that OpenBSD and ZFS on Solaris don’t support direct I/O.
#On Windows the synchronous ioengines don’t support direct I/O. Default: false.
direct=1

time_based
ramp_time=5
refill_buffers
group_reporting
wait_for_previous

#size=200G
runtime=1m

#This option also allows a range of CPUs to be specified
#say you wanted a binding to CPUs 0, 5, and 8 to 15, you would set cpus_allowed=0,5,8-15.
#cpus_allowed=0,1

[JOB1]
bs=1M
rw=read
numjobs=4
iodepth=1

[JOB2]
bs=1M
rw=write
numjobs=8
iodepth=1

#[JOB3]
#bs=4k
#rw=write

#[JOB4]
#bs=32k
#rw=write

沒有留言:

張貼留言