Linux使用FIO測試磁盤的IOPS
FIO 安裝
wget http://brick.kernel.dk/snaps/fio-2.2.5.tar.gz
tar zxvf fio-2.2.5.tar.gz
cd fio-2.2.5
./configure
make
make install
FIO 用法
隨機讀
fio -filename=/tmp/test_randread -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest
說明:
filename=/dev/sdb1 測試文件名稱,通常選擇需要測試的盤的data目錄。
direct=1 測試過程繞過機器自帶的buffer。使測試結果更真實。
rw=randwrite 測試隨機寫的I/O
rw=randrw 測試隨機寫和讀的I/O
bs=16k 單次io的塊文件大小為16k
bsrange=512-2048 同上,提定數據塊的大小范圍
size=5g 本次的測試文件大小為5g,以每次4k的io進行測試。
numjobs=30 本次的測試線程為30.
runtime=1000 測試時間為1000秒,如果不寫則一直將5g文件分4k每次寫完為止。
ioengine=psync io引擎使用pync方式
rwmixwrite=30 在混合讀寫的模式下,寫占30%
group_reporting 關於顯示結果的,匯總每個進程的信息。
此外
lockmem=1g 只使用1g內存進行測試。
zero_buffers 用0初始化系統buffer。
nrfiles=8 每個進程生成文件的數量。
結果分析:
io總的輸入輸出量
bw:帶寬 KB/s
iops:每秒鍾的IO數
runt:總運行時間
lat (msec):延遲(毫秒)
msec: 毫秒
usec: 微秒
FIO特性
fio這個工具實在太強大了,列舉一下他的NB之處吧
1)支持十幾種存儲引擎,可以自定義
2)自帶做圖工具,調用gnuplot做圖
3)支持幾乎所有的存儲描述參數
4)大量對CPU,內存,進程/線程,文件,IO特性的配置
5)壓縮,trace回放,。。。這些都包含,靈活的配置
簡介
fio最初是用來節省為特定負載寫專門測試程序,或是進行性能測試,或是找到和重現bug的時間。寫這么一個測試應用是非常浪費時間的。因此需要一個工具來模擬給定的io負載,而不用重復的寫一個又一個的特定的測試程序。但是test負載很難定義。因為可能會產生很多進程或線程,他們每一個都用他們自己的方式產生io。fio需要足夠靈活得來模擬這些case。
典型的fio的工作過程
-
寫一個job文件來描述要訪真的io負載。一個job文件可以控制產生任意數目的線程和文件。典型的job文件有一個global段(定義共享參數),一個或多少job段(描述具體要產生的job)。
-
運行時,fio從文件讀這些參數,做處理,並根據這些參數描述,啟動這些訪真線程/進程
運行fio
- 運行方式
$fio job_file
它會根據job_file的內容來運行。你可以在命令行中指定多個job file,fio進串行化運行這些文件。相當於在同一個job file不同的section之間使用了stonewall參數。
如果某個job file只包含一個job,可以在命令行中給出參數,來直接運行,不再需要讀取job file。命令行參數同job file參數的格式是一樣的。比如,在job file中的參數iodepth=2,在命令行中可以寫為–iodepth 2 或是 –iodepth=2。
fio不需要使用root來執行。除非使用到的文件或是設備需要root權限。一些選項可能會被限制,比如內存鎖,io調度器切換,或是nice value降級。
job文件格式
job file格式采用經典的ini文件,[]中的值表示job name,可以采用任意的ASCII字符,‘global’除外,global有特殊的意義。Global section描述了job file中各個job的默認配置值。一個job section可以覆蓋global section中的參數,一個job file可以包含幾個global section.一個job只會受到它上面的global section的影響。‘;’和‘#’可以用作注釋兩個進程,分別從一個從128MB文件中,隨機讀的job file.
;–start job file–
[global]
rw=randread
size=128m
[job1]
[job2]
;–end job file–
job1和job2 section是空的,因為所有的描述參數是共享的。沒有給出filename=選項,fio會為每一個job創建一個文件名,如果用命令寫,則是:$fio –name=global –rw=randread –size=128m –name=job1 –name=job2
多個進程隨機寫文件的實例
;–start job file —
[random-writers]
ioengine=libaio
iodepth=4
rw=randwrite
bs=32k
direct=0
size=64m
numjobs=4
;–end job file–
沒有global section,只有一個job section.
上一個實例的說明:采用async,每一個文件的隊列長度為4,采用隨機寫,采用32k的塊,采用非direct io,共有4個進程,每個進程隨機寫64M的文件。也可以采用下面的命令
$fio –name=random-writers –ioengine=libaio –iodepth=4 –rw=randwrite –bs=32k –direct=0 –size=64m –numjobs=4
環境變量
在job file中支持環境變量擴展。類似於${VARNAME}可以作為選項的值(在=號右邊)。
實例:
$SIZE=64m NUMJOBS=4 fio jobfile,fio
;–start job files–
[random-writers]
rw=randwrite
size=${SIZE}
numjobs=${NUMJOBS}
;–end job file–
將被擴展為
;–start job file–
[random-writers]
rw=randwrite
size=64m
numjobs=4
;–end job file–
保留keywords
fio有一些保留keywords,在內部將其替換成合適的值,這些keywords是:
$pagesize 當前系統的頁大小
$mb_memory 系統的總內存的大小,以MB為單位
$ncpus 在線有效的cpu數
這引起在命令行中和job file中都可以用,當job運行的時候,會自動的用當前系統的徝進行替換。支持簡單的數學計算,如:
size=8*$mb_memory
類型
str 字符串
time時間(int)
int 整數
bool
irange 整數范圍
float_list 符點數列
一個job包含的基本的參數
IO類型
向文件發起的IO類型。
- readwrite=str,rw=str
read 順序讀
write 順序寫
randwrite 隨機寫
randread 隨機讀
rw,readwrite 順序混合讀寫
randrw 隨機混合讀寫
[參數備注]
對於混合io類型,混認是50%的讀,50%的寫,對於特定的io類型,因為速度可能不同,結果可能會有稍有偏差.
通過在在str之后加“:
- rw_sequencer=str
如果rw=
sequential 產生順序的offset
identical 產生相同的offset
[參數備注]
‘sequential’僅用於隨機IO。通常情況下,fio在每次IO之后,將會生成一個新的隨機IO。e.g.rw=randread:8,將會在每8次IO之后執行seek,而不是每次IO之后。順序IO已經是順序的,再設置為‘sequential’將不會產生任何不同。‘identical’會產生同‘sequential’相似的行為,只是它會連續產生8次相同的offset,然后生成一個新的offset.
block size
產生的IO單元的大小,可以是一個孤立的值,也可以是一個范圍。
- blocksize=int,bs=int
單次IO的block size,默認為4k。如果是單個值的話,將會對讀寫都生效。如果是一個逗號,再跟一個int值的話,則是僅對於寫有效。也就是說,格式可以是bs=read_end_write或是bs=read,write。e.g. bs=4k,8k讀使用4k的塊,寫使用8k的塊。e.g.bs=,8k將使得寫采用8k的塊,讀采用默認的值。
IO size
將會讀/寫多少數據
- size=int
這個job IO總共要傳輸的數據的大小。FIO將會執行到所有的數據傳輸完成,除非設定了運行時間(‘runtime’選項)。除非有特定的‘nrfiles’選項和‘filesize’選項被設置,fio將會在job定義的文件中平分這個大小。如果這個值不設置的話,fio將會使用這個文件或設備的總大小。如果這些文件不存在的話,size選項一定要給出。也可以給出一個1到100的百分比。e.g. size=20%,fio將會使用給定的文件或設備的20%的空間。
IO引擎
發起IO的方式。
- ioengine=str
定義job向文件發起IO的方式
sync 基本的read,write.lseek用來作定位
psync 基本的pread,pwrite
vsync 基本的readv,writev
libaio Linux專有的異步IO。Linux僅支持非buffered IO的隊列行為。
posixaio glibc posix異步IO
solarisaio solaris獨有的異步IO
windowsaio windows獨有的異步IO
mmap 文件通過內存映射到用戶空間,使用memcpy寫入和讀出數據
splice 使用splice和vmsplice在用戶空間和內核之間傳輸數據
syslet-rw 使用syslet 系統調用來構造普通的read/write異步IO
sg SCSI generic sg v3 io.可以是使用SG_IO ioctl來同步,或是目標是一個sg字符設備,我們使用read和write執行異步IO
null 不傳輸任何數據,只是偽裝成這樣。主要用於訓練使用fio,或是基本debug/test的目的。
net 根據給定的host:port通過網絡傳輸數據。根據具體的協議,hostname,port,listen,filename這些選項將被用來說明建立哪種連接,協議選項將決定哪種協議被使用。
netsplice 像net,但是使用splic/vmsplice來映射數據和發送/接收數據。
cpuio 不傳輸任何的數據,但是要根據cpuload=和cpucycle=選項占用CPU周期.e.g. cpuload=85將使用job不做任何的實際IO,但要占用85%的CPU周期。在SMP機器上,使用numjobs=<no_of_cpu>來獲取需要的CPU,因為cpuload僅會載入單個CPU,然后占用需要的比例。
guasi GUASI IO引擎是一般的用於異步IO的用戶空間異步系統調用接口
rdma RDMA I/O引擎支持RDMA內存語義(RDMA_WRITE/RDMA_READ)和通道主義(Send/Recv)用於InfiniBand,RoCE和iWARP協議
external 指明要調用一個外部的IO引擎(二進制文件)。e.g. ioengine=external:/tmp/foo.o將載入/tmp下的foo.o這個IO引擎
IO depth
如果IO引擎是異步的,這個指定我們需要保持的隊列深度
- iodepth=int
加於文件之上的保持的IO單元。默認對於每個文件來說是1,可以設置一個更大的值來提供並發度。iodepth大於1不會影響同步IO引擎(除非verify_async這個選項被設置)。even async engines may impose OS restrictions causing the desired depth not to be achieved.這會在Linux使用libaio並且設置direct=1的時候發生,因為buffered io在OS中不是異步的。在外部通過類似於iostat這些工具來觀察隊列深度來保證這個IO隊列深度是我們想要的。這個可以參考褚霸的博客http://blog.yufeng.info/archives/2104
IO type
- direct=bool
true,則標明采用non-buffered io.同O_DIRECT效果一樣。ZFS和Solaris不支持direct io,在windows同步IO引擎不支持direct io
- buffered=bool
true,則標明采用buffered io。是direct的反義詞,默認是true
Num files
負載將分發到幾個文件之中
- nrfiles=int
用於這個job的文件數目,默認為1
- openfiles=int
在同一時間可以同時打開的文件數目,默認同nrfiles相等,可以設置小一些,來限制同時打開的文件數目。
Num threads
- numjobs=int
創建特定數目的job副本。可能是創建大量的線程/進程來執行同一件事。我們將這樣一系列的job,看作一個特定的group
詳細參數:
- name=str
job名,用於輸出信息用的名字。如果不設置的話,fio輸出信息時將采用job name,如果設置的話,將用設置的名字。在命令行中,這個參數有特殊的作用,標明一個新job的開始。
- description=str
job的說明信息,在job運行的時候不起作用,只是在輸出文件描述信息的時候才起作用。
- directory=str
使用的文件的路徑前綴,默認是./
- filename=str
一般情況下,fio會根據job名,線程號,文件名來產生一個文件名。如果,想在多個job之間共享同一個文件的話,可以設定一個名字來代替默認的名字.如果ioengine是‘net’的話,文件名則是以這種格式=host,port,protocol.如果ioengine是基於文件的話,可以通過‘:’分割來設定一系列的文件。e.g. filename=/dev/sda:/dev/sdb 希望job打開/dev/sda和/dev/sdb作為兩個工作文件。
- opendir=str
讓fio遞歸的添加目錄下和子目錄下的所有文件。
- lockfile=str
fio在文件上執行IO之前默認是不鎖文件的,這樣的話,當有多個線程在此文件上執行IO的話,會造成結果的不一致。這個選項可以用來共享文件的負載,支持的鎖類型:
none 默認不使用鎖
exclusive 排它鎖
readwrite 讀寫鎖
在后面可以加一個數字后綴,如果設置的話,每一個線程將會執行這個數字指定的IO后才會放棄鎖,因為鎖的開銷是比較大的,所以這種方式可以加速IO。
- kb_base=int
size換算單位,1000/1024,默認為1024
- randrepeat=bool
對於隨機IO負載,配置生成器的種子,使得路徑是可以預估的,使得每次重復執行生成的序列是一樣的。
- use_os_rand=bool
fio可以使用操作系統的隨機數產生器,也可以使用fio內部的隨機數產生器(基於tausworthe),默認是采用fio內部的產生器,質量更數,速度更快。
- fallocate=str
如何准備測試文件
none 不執行預分配空間
posix 通過posix_fallocate()預分配空間
keep 通過fallocate()(設置FALLOC_FL_KEEP_SIZE)預分配空間
0 none的別名,出於兼容性
1 posix的別名,出於兼容性
並不是在所有的平台上都有效,‘keep’僅在linux上有效,ZFS不支持。默認為‘posix’
- fadvise_hint=bool
默認fio將使用fadvise()來告知內核fio要產生的IO類型,如果不想告訴kernel來執行一些特定的IO類型的話,可行關閉這個選項。如果設置的話,fio將使用POSIX_FADV_SEWUENTIAL來作順序IO,使用POSIX_FADV_RANDOM來做隨機IO
- filesize=int
單個文件的大小,可以是一個范圍,在這種情況下,fio將會在一個范圍內選擇一個大小來決定單個文件大小,如果沒有設置的話,所有的文件將會是同樣的大小。
- fill_device=bool,fill_fs=bool
填滿空間直到達到終止條件ENOSPC,只對順序寫有意義。對於讀負載,首行要填滿掛載點,然后再啟動IO,對於裸設備結點,這個設置則沒有什么意義,因為,它的大小已被被文件系統知道了,此外寫的超出文件將不會返回ENOSPC.
- blockalign=int,ba=int
配置隨機io的對齊邊界。默認是與blocksize的配置一致,對於direct_io,最小為512b,因為它與依賴的硬件塊大小,對於使用文件的隨機map來說,這個選項不起作用。
- blocksize_range=irange,bsrange=irange
不再采用單一的塊大小,而是定義一個范圍,fio將采用混合io塊大小.IO單元大小一般是給定最小值的備數。同時應用於讀寫,當然也可以通過‘,’來隔開分別配置讀寫。
- bssplit=str
可以更為精確的控制產生的block size.這個選項可以用來定義各個塊大小所占的權重.格式是
bssplit=blocksize/percentage;blocksize/percentage
bssplit=4k/10:64k/50;32k/40
產生的這樣的負載:50% 64k的塊,10% 4k的塊, 40% 32k的塊
可以分別為讀和寫來設置
e.g. bssplit=2k/50:4k/50,4k/90:8k/10
產生這樣的負載:讀(50% 64k的塊,50% 4k的塊),寫(90% 4k的塊, 10% 8k的塊)
- blocksize_unaligned,bs_unaligned
如果這個選項被設置的,在bsrange范圍內的大小都可以產生,這個選項對於direct io沒有作用,因為對於direct io至少需要扇區對齊
- zero_buffers
如果這個選項設置的話,IO buffer全部位將被初始為0,如果沒有置位的話,將會是隨機數.
- refill_buffers
如果這個選項設置的話,fio將在每次submit之后都會將重新填滿IO buffer,默認都會在初始是填滿,以后重復利用。這個選項只有在zero_buffers沒有設置的話,這個選項才有作用。
- scramble_buffer=bool
如果refilee_buffers成本太高的話,但是負載要求不使用重復數據塊,設置這個選項的話,可以輕微的改動IO buffer內容,這種方法騙不過聰明的塊壓縮算法,但是可以騙過一些簡單的算法。
- buffer_compress_percentage=int
如果這個設置的話,fio將會嘗試提供可以壓縮到特定級別的Buffer內容。FIO是能完提供混合的0和隨機數來實現的。Note that this is per block size unit, for file/disk wide compression level that matches this setting, you’ll also want to set refill_buffers.
- buffer_compress_chunk=int
See buffer_compress_percentage. This setting allows fio to manage how big the ranges of random data and zeroed data is. Without this set, fio will provide buffer_compress_percentage of blocksize random data, followed by the remaining zeroed. With this set to some chunk size smaller than the block size, fio can alternate random and zeroed data throughout the IO buffer.
- file_service_type=str
fio切換job時,如何選擇文件,支持下面的選項
random 隨機選擇一個文件
roundrobin 循環使用打開的文件,默認
sequential 完成一個文件后,再移動到下一個文件
這個選項可以加后綴數字,標明切換到下一個新的頻繁程度。
e.g. random:4 每4次IO后,將會切換到一下隨機的文件
- iodepth_batch_submit=int,iodepth_batch=int
這個定義了一次性提交幾個IO,默認是1,意味着一旦准備好就提交IO,這個選項可以用來一次性批量提交IO
- iodepth_batch_complete=int
這個選項定義了一次取回多少個IO,如果定義為1的話,意味着我們將向內核請求最小為1個IO.The IO retrieval will go on until we hit the limit set by iodetph_low.If this variable is set to 0, then fi will always check for completed events before quuing more IO.This helps reduce IO latency, at the cost of more retrieval sysstem calls.
- iodepth_low=int
這個水位標志標明什么時候開始重新填充這個隊列,默認是同iodepth是一樣的,意味着,每時每刻都在嘗試填滿這個隊列。如果iodepth設置為16,而iodepth設置為4的話,那么fio將等到depth下降到4才開始重新填充
- offset=int
在文件特定的偏移開始讀數據,在這個offset之前的數據將不會被使用,有效的文件大小=real_size-offset
- offset_increment=int
如果這個選項被設置的話,實際的offset=offset+offset_increment * thread_number,線程號是從0開始的一個計數器,對於每一個job來說是遞增的。這個選項對於幾個job同時並行在不交界的地方操作一個文件是有用的。
- fsync=int
如果寫一個文件的話,每n次IO傳輸完block后,都會進行一次同步臟數據的操作。
e.g. fsync=int
fio每32次寫之后,同步一次文件。如果采用non-buffered io,不需要使用sync同步文件
對於sg io引擎的話,可以在任何情況下同步磁盤cache.
- fdatasync=int
同fsync,但是采用fdatasync()來同步數據,但不同步元數據
- sync_file_range=str:val
對於每‘val’個寫操作,將執行sync_file_range()。FIO將跟蹤從上次sync_file_range()調用之扣的寫范圍,‘str’可以是以下的選擇
wait_before SYNC_FILE_RANGE_WAIT_BEFORE
write SYNC_FILE_RANGE_WRITE
wait_after SYNC_FILE_RANGE_WAIT_AFTER
e.g.sync_file_range=wait_before,write:8,fio將在每8次寫后使用SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE
- overwrite=bool
如果是true的話,寫一個文件的話,將會覆蓋已經存在的數據。如果文件不存在的話,它將會在寫階段開始的時候創建這個文件。
- end_fsync=bool
如果是true的話,當job退出的話,fsync將會同步文件內容
- fsync_on_close=bool
如果是true的話,關閉時,fio將會同步臟文件,不同於end_fsync的時,它將會在每個文件關閉時都會發生,而不是只在job結束時。
- rwmixread=int
混合讀寫中,讀占的百分比
- rwmixwrite=int
混合讀寫中,寫占的百分比;如果rwmixread=int和rwmixwrite=int同時使用的話並且相加不等於100%的話,第二個值將會覆蓋第一個值。這可能要干擾比例的設定,如果要求fio來限制讀和寫到一定的比率。在果在這種情況下,那么分布會的有點的不同。
- norandommap
一般情況下,fio在做隨機IO時,將會覆蓋文件的每一個block.如果這個選項設置的話,fio將只是獲取一個新的隨機offset,而不會查詢過去的歷史。這意味着一些塊可能沒有讀或寫,一些塊可能要讀/寫很多次。在個選項與verify=互斥,並只有多個塊大小(bsrange=)正在使用,因為fio只會記錄完整的塊的重寫。
- softrandommap=bool
See norandommap. If fio runs with the random block map enabled and it fails to allocate the map, if this option is set it will continue without a random block map. As coverage will not be as complete as with random maps, this option is disabled by default.
- nice=int
根據給定的nice值來運行這個job
- prio=int
設置job的優先級,linux將這個值限制在0-7之間,0是最高的。
- prioclass=int
設置優先級等級。
- thinktime=int
上一個IO完成之后,拖延x毫秒,然后跳到下一個。可以用來訪真應用進行的處理。
- thinktime_spin=int
只有在thinktime設置時才有效,在為了sleep完thinktime規定的時間之前,假裝花費CPU時間來做一些與數據接收有關的事情。
- thinktime_blocks
只有在thinktime設置時才有效,控制在等等‘thinktime’的時間內產生多少個block,如果沒有設置的話,這個值將是1,每次block后,都會將等待‘thinktime’us。
- rate=int
限制job的帶寬。
e.g.rate=500k,限制讀和寫到500k/s
e.g.rate=1m,500k,限制讀到1MB/s,限制寫到500KB/s
e.g.rate=,500k , 限制寫到500kb/s
e.g.rate=500k, 限制讀到500KB/s
- ratemin=int
告訴fio盡最在能力來保證這個最小的帶寬,如果不能滿足這個需要,將會導致程序退出。
- rate_iops=int
將帶寬限制到固定數目的IOPS,基本上同rate一樣,只是獨立於帶寬,如果job是指定了一個block size范圍,而不是一個固定的值的話,最小blocksize將會作為標准。
- rate_iops_min=int
如果fio達不到這個IOPS的話,將會導致job退出。
- ratecycle=int
幾個毫秒內的平均帶寬。用於‘rate’和‘ratemin’
- cpumask=int
設置job使用的CPU.給出的參數是一個掩碼來設置job可以運行的CPU。所以,如果要允許CPU在1和5上的話,可以通過10進制數來設置(1<<1 | 1<<5),或是34。查看sched_setaffinity的man page。它可能並不是支持所有的操作系統和kernel版本。This option doesn’t work well for a higher CPU count than what you can store in an integer mask, so it can only control cpus 1-32. For boxes with larger CPU counts, use cpus_allowed.
- cpus_allowed=str
功能同cpumask一樣,但是允許通過一段文本來設置允許的CPU。e.g.上面的例子可是這樣寫cpus_allowed=1,5。這個選項允許設置一個CPU范圍,如cpus_allowed=1,5,8-15
- startdelay=time
fio啟動幾秒后再啟動job。只有在job文件包含幾個jobs時才有效,是為了將某個job延時幾秒后執行。
- runtime=time
控制fio在執行設定的時間后退出執行。很難來控制單個job的運行時間,所以這個參數是用來控制總的運行時間。
- time_based
如果設置的話,即使file已被完全讀寫或寫完,也要執行完runtime規定的時間。它是通過循環執行相同的負載來實現的。
- ramp_tim=time
設定在記錄任何性能信息之前要運行特定負載的時間。這個用來等性能穩定后,再記錄日志結果,因此可以減少生成穩定的結果需要的運行時間。Note that the ramp_time is considered lead in time for a job, thus it will increase the total runtime if a special timeout or runtime is specified.
- invalidate=bool
Invalidate the buffer/page cache parts for this file prior to starting io. Defaults to true.
- sync=bool
使用sync來進行buffered寫。對於多數引擎,這意味着使用O_SYNC
- iomem=str,mem=str
fio可以使用各種各樣的類型的內存用來io單元buffer.
malloc 使用malloc()
shm 使用共享內存.通過shmget()分配
shmhuge 同shm一樣,可以使用huge pages
mmap 使用mmap。可以是匿名內存,或是支持的文件,如果一個文件名在選項后面設置的話,格式是mem=mmap:/path/to/file
mmaphuge 使用mmapped huge file.在mmaphuge扣面添加文件名,alamem=mmaphuge:/hugetlbfs/file
分配的區域是由job允許的最大block size * io 隊列的長度。對於shmhuge和mmaphuge,系統應該有空閑的頁來分配。這個可以通過檢測和設置reading/writing /proc/sys/vm/nr_hugepages來實現(linux)。FIO假設一個huge page是4MB。所以要計算對於一個JOB文件需要的Huge page數量,加上所有jobs的隊列長度再乘以最大塊大小,然后除以每個huge page的大小。可以通過查看/proc/meminfo來看huge pages的大小。如果通過設置nr_hugepages=0來使得不允許分配huge pages,使用mmaphug或是shmhuge將會失敗。
mmaphuge需要掛載hugelbfs而且要指定文件的位置,所以如果要掛載在/huge下的話,可以使用mem=mmaphuge:/huge/somefile
- iomem_align=int
標明IO內存緩沖的內存對齊方式。Note that the given alignment is applied to the first IO unit buffer, if using iodepth the alignment of the following buffers are given by the bs used. In other words, if using a bs that is a multiple of the page sized in the system, all buffers will be aligned to this value. If using a bs that is not page aligned, the alignment of subsequent IO memory buffers is the sum of the iomem_align and bs used.
- hugepage-size=int
設置huge page的大小。至少要與系統的設定相等。默認是4MB,必然是MB的倍數,所以用hugepage-size=Xm是用來避免出現不是2的整數次方的情況。
- exitall
當一個job退出時,會終止運行其它的job,默認是等待所有的job都完成,FIO才退出,但有時候這並不是我們想要的。
- bwavgtime=int
在給定時間內的平均帶寬。值是以毫秒為單位的
- iopsavgtime=int
在給定時間內的平均IOPS,值是以毫秒為單位的
- create_serialize=bool
job將會串行化創建job,這將會用來避免數據文件的交叉,這依賴於文件系統和系統的CPU數
- create_fsync=bool
創建后同步數據文件,這是默認的值
- create_on_open=bool
不會為IO預先創建文件,只是在要向文件發起IO的時候,才創建open()
- create_only=bool
如果設置為true的話,fio將只運行到job的配置階段。如果文件需要部署或是更新的磁盤的話,只有上面的事才會做,實際的文件內容並沒有執行。
- pre_read=bool
如果這個選項被設置的話,在執行IO操作之前,文件將會被預讀到內存.這會刪除‘invalidate’標志,因為預讀數據,然后丟棄cache中的數據的話,是沒有意義的。這只是對可以seek的IO引擎有效,因為這允許讀相同的數據多次。因此對於network和splice不起作用。
- unlink=bool
完成后將刪除job產生的文件。默認是not,如果設置為true的話,將會花很多時間重復創建這些文件。
- loops=int
重復運行某個job多次,默認是1
- do_verify=bool
寫完成后,執行一個校驗的階段,只有當verify設置的時候才有效。默認是true
- verify=str
寫一個文件時,每次執行完一個job扣,fio可以檢驗文件內容.允許的校驗算法是:
md5,crc64,crc32c,crc32c-intel,crc32,crc16,crc7,sha512,sha256,sha1,meta,null.
這個選項可以用來執行重復的burn-in測試,來保證寫數據已經正確的讀回。如果是read或隨機讀,fio將假設它將會檢驗先前寫的文件。如果是各種格式的寫,verify將會是對新寫入的數據進行校驗。
- verifysort=bool
如果設置的話,fio will sort written verify blocks when it deems it faster to read them back in a sorted manner. This is often the case when overwriting an existing file, since the blocks are already laid out in the file system. You can ignore this option unless doing huge amounts of really fast IO where the red-black tree sorting CPU time becomes significant.
- verify_offset=int
Swap the verification header with data somewhere else in the block before writing. Its swapped back before verifying.
- verify_interval=int
Write the verification header at a finer granularity than the blocksize. It will be written for chunks the size of header_interval. blocksize should divide this evenly
-
verify_pattern=str
-
verify_fatal=bool
-
verify_dump=bool
-
verify_async=int
-
verify_async_cpus=str
-
verify_backlog=int
-
verify_backlog_batch=int
-
stonewall,wait_for_previous
等待先前的job執行完成后,再啟動一個新的job。可以用來在job文件中加入串行化的點。stone wall也用來啟動一個新reporting group
- new_group
啟動一個新的reporting group。如果這個選項沒有設置的話,在job文件中的job將屬於相同的reporting group,除非通過stonewall隔開
- group_reporting
如果‘numjobs’設置的話,我們感興趣的可能是打印group的統計值,而不是一個單獨的job。這在‘numjobs’的值很大時,一般是設置為true的,可以減少輸出的信息量。如果‘group_reporting’設置的話,fio將會顯示最終的per-groupreport而不是每一個job都會顯示
- thread
fio默認會使用fork()創建job,如果這個選項設置的話,fio將使用pthread_create來創建線程
- zonesize=int
將一個文件分為設定的大小的zone
- zoneskip=int
跳過這個zone的數據都被讀完后,會跳過設定數目的zone.
- write_iolog=str
將IO模式寫到一個指定的文件中。為每一個job指定一個單獨的文件,否則iolog將會分散的的,文件將會沖突。
- read_iolog=str
將開一個指定的文件,回復里面的日志。這可以用來存儲一個負載,並進行重放。給出的iolog也可以是一個二進制文件,允許fio來重放通過blktrace獲取的負載。
- replay_no_stall
當使用read_iolog重放I/O時,默認是嘗試遵守這個時間戳,在每個IOPS之前會有適當的延遲。通過設置這個屬性,將不會遵守這個時間戳,會根據期望的順序,嘗試回復,越快越好。結果就是相同類型的IO,但是不同的時間
- replay_redirect
當使用read_iolog回放IO時,默認的行為是在每一個IOP來源的major/minor設備上回放IOPS。這在有些情況是不是期望的,比如在另一台機器上回放,或是更換了硬件,使是major/minor映射關系發生了改變。Replay_redirect將會導致所有的IOPS回放到單個設備上,不管這些IO來源於哪里。e.g.replay_redirect=/dev/sdc將會使得所有的IO都會重定向到/dev/sdc.這就意味着多個設備的數據都會重放到一個設置,如果想來自己多個設備的數據重放到多個設置的話,需要處理我們的trace,生成獨立的trace,再使用fio進行重放,不過這會破壞多個設備訪問的嚴格次序。
- write_bw_log=str
在job file寫這個job的帶寬日志。可以在他們的生命周期內存儲job的帶寬數據。內部的fio_generate_plots腳本可以使用gnuplot將這些文本轉化成圖。
- write_lat_log=str
同write_bw_log類似,只是這個選項可以存儲io提交,完成和總的響應時間。如果沒有指定文件名,默認的文件名是jobname_type.log。即使給出了文件名,fio也會添加兩種類型的log。
e.g.如果我們指定write_lat_log=foo
實際的log名將是foo_slat.log,foo_slat.log和foo_lat.log.這會幫助fio_generate_plot來自動處理log
- write_iops_log=str
類似於write_bw_log,但是寫的是IOPS.如果沒有給定文件名的話,默認的文件名是jobname_type.log。
- log_avg_msec=int
默認,fio每完成一個IO將會記錄一個日志(iops,latency,bw log)。當向磁盤寫日志的時候,將會很快變的很大。設置這個選項的話,fio將會在一定的時期內平均這些值,指少日志的數量,默認是0
- lockmem=int
使用mlock可以指定特定的內存大小,用來訪真少量內存
- exec_preren=str
運行job之前,通過過system執行指定的命令
- exec_postrun=str
job執行完成后,通過system執行指定的命令
- ioscheduler=str
在運行之前,嘗試將文件所在的設備切換到指定的調度器。
- cpuload=int
如果job是非常占用CPU周期的,可以指定戰勝CPU周期的百分比。
- cpuchunks=int
如果job是非常戰勝CPU周期的,將load分拆為時間的cycles,以毫秒為單位
- disk_util=bool
產生磁盤利用率統計信息。默認是打開的
- disable_lat=bool
延遲的有效數字。Disable measurements of total latency numbers. Useful only for cutting back the number of calls to gettimeofday,as that does impact performance at really high IOPS rates.Note that to really get rid of a large amount of these calls, this option must be used with disable_slat and disable_bw as well.
-
disable_clat=bool
-
disable_slat_bool
-
disable_bw=bool
-
clat_percentiles=bool
允許報告完成完成響應時間的百分比
-
percentile_list=float_list
-
gtod_reduce=bool
-
gtod_cpu=int
-
continue_on_error=str
一般情況下,一旦檢測到錯誤,fio將會退出這個job.如果這個選項設置的話,fio將會一直執行到有‘non-fatal錯誤‘(EIO或EILSEQ)或是執行時間耗完,或是指定的I/Osize完成。如果這個選項設置的話,將會添加兩個狀態,總的錯誤計數和第一個error。允許的值是
none 全部IO或檢驗錯誤后,都會退出
read 讀錯誤時會繼續執行,其它的錯誤會退出
write 寫錯誤時會繼續執行,其它的錯誤會退出
io 任何IO error時會繼續執行,其它的錯誤會退出
verify 校驗錯誤時會繼續執行,其它的錯誤會退出
all 遇到所有的錯誤都會繼續執行
-
cgroup=str
-
cgroup_weitht=int
-
cgroup_weight=int
-
cgroup_nodelete=bool
-
uid=int
不是使用調用者的用戶來執行,而是指定用戶ID
- gid=int
設置group id
-
flow_id=int
-
flow=int
-
flow_watermark=int
-
flow_sleep=int
下面的參數只對指定的IO引擎有效:
[libaio] userspace_reap
[netsplice]hostname=str
[net]hostname=str
[netsplice]port=int
[netsplice]proto=str
[net]protocol=str
[net]proto=str
[net]listen
輸出
在運行時,fio將打印當前job創建的狀態
e.g.
Threads: 1: [_r] [24.8% done] [ 13509/ 8334 kb/s] [eta 00h:01m:31s]
生命周期
P 線程已經啟動,還沒有啟動
C 線程啟動
I 純種已經初始化,等待中
p 線程運行中,預讀文件
R 順序讀
r 隨機讀
W 順序寫
w 隨機寫
M 混合順序讀寫
m 混合隨機讀寫
F 等待執行fsync()
V 運行,檢驗寫的數據
E 線程退出,還沒有被主線程獲取狀態
_ Thread reaped, or
X Thread reaped, exited with an error.
K Thread reaped, exited due to signal.
其它的值都是可以自解釋的:
當前正在運行的IO線程數。
從上次檢查之后的IO速度(讀速度/寫速度)
估計的完成百分比
整個group的估計完成時間
當fio完成的時候(或是通過ctrl-c終止的時候),將會打印每一個線程的數據,每個group的數據,和磁盤數據。
io= 執行了多少M的IO
bw= 平均IO帶寬
iops= IOPS
runt= 線程運行時間
slat 提交延遲
clat 完成延遲
lat響應時間
bw 帶寬
cpu利用率
IO depths=io隊列
IO submit=單個IO提交要提交的IO數
IO complete= Like the above submit number, but for completions instead.
IO issued= The number of read/write requests issued, and how many
of them were short.
IO latencies=IO完延遲的分布
io= 總共執行了多少size的IO
aggrb= group總帶寬
minb= 最小.平均帶寬.
maxb= 最大平均帶寬.
mint= group中線程的最短運行時間.
maxt= group中線程的最長運行時間.
ios= 所有group總共執行的IO數.
merge= 總共發生的IO合並數.
ticks= Number of ticks we kept the disk busy.
io_queue= 花費在隊列上的總共時間.
util= 磁盤利用率
為了便於腳本分析,可能需要將結果生成表或圖,fio可以生成以分號分割的結果。
trace文件格式
磁盤IOPS概念及IOPS的計算
IOPS概念
IOPS (Input/Output Per Second)即每秒的輸入輸出量(或讀寫次數),是衡量磁盤性能的主要指標之一。IOPS是指單位時間內系統能處理的I/O請求數量,一般以每秒處理的 I/O請求數量為單位,I/O請求通常為讀或寫數據操作請求。隨機讀寫頻繁的應用,如OLTP(Online Transaction Processing),IOPS是關鍵衡量指標。另一個重要指標是數據吞吐量(Throughput),指單位時間內可以成功傳輸的數據數量。對於大量 順序讀寫的應用,如電視台的視頻編輯,視頻點播VOD(Video On Demand),則更關注吞吐量指標。
IOPS計算方法
傳統磁盤本質上一種機械裝置,如FC, SAS, SATA磁盤,轉速通常為5400/7200/10K/15K rpm不等。影響磁盤的關鍵因素是磁盤服務時間,即磁盤完成一個I/O請求所花費的時間,它由尋道時間、旋轉延遲和數據傳輸時間三部分構成。
尋道時間Tseek是指將讀寫磁頭移動至正確的磁道上所需要的時間。尋道時間越短,I/O操作越快,目前磁盤的平均尋道時間一般在3-15ms。
旋 轉延遲Trotation是指盤片旋轉將請求數據所在扇區移至讀寫磁頭下方所需要的時間。旋轉延遲取決於磁盤轉速,通常使用磁盤旋轉一周所需時間的1/2 表示。比如,7200 rpm的磁盤平均旋轉延遲大約為60*1000/7200/2 = 4.17ms,而轉速為15000 rpm的磁盤其平均旋轉延遲約為2ms。
數據傳輸時間Ttransfer是指完成傳輸所請求的數據所需要的時間,它取決於數據傳輸率,其值等於數據大小除以數據傳輸率。目前IDE/ATA能達到133MB/s,SATA II可達到300MB/s的接口數據傳輸率,數據傳輸時間通常遠小於前兩部分時間。
因此,理論上可以計算出磁盤的最大IOPS,即IOPS = 1000 ms/ (Tseek + Troatation),忽略數據傳輸時間。假設磁盤平均物理尋道時間為3ms, 磁盤轉速為7200,10K,15K rpm,則磁盤IOPS理論最大值分別為,
IOPS = 1000 / (3 + 60000/7200/2) = 140
IOPS = 1000 / (3 + 60000/10000/2) = 167
IOPS = 1000 / (3 + 60000/15000/2) = 200
固態硬盤SSD是一種電子裝置, 避免了傳統磁盤在尋道和旋轉上的時間花費,存儲單元尋址開銷大大降低,因此IOPS可以非常高,能夠達到數萬甚至數十萬。實際測量中,IOPS數值會受到 很多因素的影響,包括I/O負載特征(讀寫比例,順序和隨機,工作線程數,隊列深度,數據記錄大小)、系統配置、操作系統、磁盤驅動等等。因此對比測量磁 盤IOPS時,必須在同樣的測試基准下進行,即便如何也會產生一定的隨機不確定性。通常情況下,IOPS可細分為如下幾個指標:
Toatal IOPS,混合讀寫和順序隨機I/O負載情況下的磁盤IOPS,這個與實際I/O情況最為相符,大多數應用關注此指標。
Random Read IOPS,100%隨機讀負載情況下的IOPS。
Random Write IOPS,100%隨機寫負載情況下的IOPS。
Sequential Read IOPS,100%順序負載讀情況下的IOPS。
Sequential Write IOPS,100%順序寫負載情況下的IOPS。
IOPS的測試benchmark工具主要有Iometer, IoZone, FIO等,可以綜合用於測試磁盤在不同情形下的IOPS。對於應用系統,需要首先確定數據的負載特征,然后選擇合理的IOPS指標進行測量和對比分析,據此選擇合適的存儲介質和軟件系統。