Linux 效能優化之 IO 子系統

liaoph發表於2016-05-12

本文介紹了對 Linux IO 子系統效能進行優化時需要考慮的因素,以及一些 IO 效能檢測工具。

本文的大部分內容來自 IBM Redbook - Linux Performance and Tuning Guidelines

FileSystem

VFS(Virtual FileSystem) 虛擬檔案系統

檔案系統是核心的功能,是一種工作在核心空間的軟體,訪問一個檔案必須要需要檔案系統的存在才可以。Linux 可以支援多達數十種不同的檔案系統,它們的實現各不相同,因此 Linux 核心向使用者空間提供了虛擬檔案系統這個統一的介面用來對檔案系統進行操作。

虛擬檔案系統是位於使用者空間程式和核心空間中多種不同的底層檔案系統的實現之間的一個抽象的介面層,它提供了常見的檔案系統物件模型(如 i-node, file object, page cache, directory entry, etc.)和訪問這些物件的方法(如 open, close, delete, write, read, create, fstat, etc.),並將它們統一輸出,類似於庫的作用。從而向使用者程式隱藏了各種不同的檔案系統的具體實現,這樣上層軟體只需要和 VFS 進行互動而不必關係底層的檔案系統,簡化了軟體的開發,也使得 linux 可以支援多種不同的檔案系統。

Journaling

非日誌型檔案系統

在非日誌型檔案系統中,對檔案系統實施一個寫操作,核心會首先修改對應的後設資料,然後修改資料塊。如果在寫入後設資料時,檔案系統發生崩潰或某種故障,那麼資料的一致性將會遭到破壞。fsck 命令可以在下次重啟時檢查所有的後設資料並修復資料一致性,但是如果檔案系統非常大,或者系統執行關鍵業務不允許停機,使用非日誌型檔案系統的風險會非常高。

日誌型檔案系統

日誌型檔案系統的區別在於,在進行對檔案系統寫資料之前,寫將資料寫到「日誌區」,然後再寫入檔案系統,在寫入檔案系統之後刪除日誌。日誌區可以在檔案系統內部也可以在檔案系統外部。日誌區的資料稱作檔案系統日誌,這些資料包含了修改了的後設資料,也可能包含將要修改的資料。寫日誌也會帶來一定的額外開銷。

EXT2

ext2 檔案系統組成不再贅述,需要注意的是 ext2 檔案系統沒有日誌功能。

EXT3

ext3 是帶有日誌功能檔案系統,它基於ext2檔案系統實現。

  • 以一致性的方式寫入資料,即使斷電或檔案系統崩潰,恢復的時間會大大減少
  • 資料完整性:在掛載時指定選項 data=journal 則可以使日誌記錄下後設資料和檔案資料
  • 速度:指定掛載選項 data=writeback 使用回寫的方式寫資料
  • 靈活性:可以從 ext2 系統升級,而不需要重新格式化檔案系統,也可以以非日誌模式掛載,就如同 ext2 一樣

ext3的日誌模式

  • journal,提供最大資料完整性,日誌會記錄後設資料和檔案資料
  • ordered,日誌只記錄後設資料。但是會保證檔案資料先被寫入,這是預設選項。
  • writeback,使用回寫的方式寫資料,只保證記錄後設資料至日誌。

其他檔案系統

  • ReiserFS,ReiserFS是一個快速的日誌型檔案系統,有著良好的磁碟空間使用和快速的崩潰恢復。屬於 Novell 公司,在 SUSE Linux 中使用。
  • JFS (Journal File System), JFS 是一個完全 64 位檔案系統,可以支援非常大的檔案和分割槽,早先由 IBM 公司為 AIX 作業系統開發,現已使用 GPL 協議開源。JFS適用於非常大的分割槽和檔案如 HPC 或者資料庫業務。
  • XFS (eXtended File System), 一個高效能的日誌型檔案系統,和 JFS 比較相似。

I/O子系統架構

上圖概括了一次磁碟 write 操作的過程,假設檔案已經被從磁碟中讀入了 page cache 中

  1. 一個使用者程式通過 write() 系統呼叫發起寫請求
  2. 核心更新對應的 page cache
  3. pdflush 核心執行緒將 page cache 寫入至磁碟中
  4. 檔案系統層將每一個 block buffer 存放為一個 bio 結構體,並向塊裝置層提交一個寫請求
  5. 塊裝置層從上層接受到請求,執行 IO 排程操作,並將請求放入IO 請求佇列中
  6. 裝置驅動(如 SCSI 或其他裝置驅動)完成寫操作
  7. 磁碟裝置韌體執行對應的硬體操作,如磁碟的旋轉,尋道等,資料被寫入到磁碟扇區中

Block Layer

Block layer 處理所有和塊裝置相關的操作。block layer 最關鍵是資料結構是 bio 結構體。bio 結構體是 file system layer 到 block layer 的介面。 當執行一個寫操作時,檔案系統層將資料寫入 page cache(由 block buffer 組成),將連續的塊放到一起,組成 bio 結構體,然後將 bio 送至 block layer。

block layer 處理 bio 請求,並將這些請求連結成一個佇列,稱作 IO 請求佇列,這個連線的操作就稱作 IO 排程(也叫 IO elevator 即電梯演算法).

IO scheduler

IO 排程器的總體目標是減少磁碟的尋道時間(因此排程器都是針對機械硬碟進行優化的),IO 排程器通過兩種方式來減少磁碟尋道:合併排序

合併即當兩個或多個 IO 請求的是相鄰的磁碟扇區,那麼就將這些請求合併為一個請求。通過合併請求,多個 IO 請求只需要向磁碟傳送一個請求指令,減少了磁碟的開銷。

排序就是將不能合併的 IO 請求,根據請求磁碟扇區的順序,在請求佇列中進行排序,使得磁頭可以按照磁碟的旋轉順序的完成 IO 操作,可以減小磁碟的尋道次數。

排程器的演算法和電梯執行的策略相似,因此 IO 排程器也被稱作 IO 電梯( IO Elevator )。由於對請求進行了重排,一部分的請求可能會被延遲,以提升整體的效能。

Linux 2.4 只使用了一種通用的 IO 演算法。到 Linux 2.6 實現了 4 種 IO 排程模型,其中 anticipatory 在 2.6.33 中被移除

Linus Elevator

早先的 IO 排程器就叫做 Linus Elevator,當一個請求被加入到請求佇列中,它首先檢查佇列中是否存在相鄰的請求以合併兩個請求,這可能包含前合併和後合併。如果不能合併,則尋找是否能夠將新請求按扇區順序插入到請求佇列,如果沒有找到適合插入的位置,那麼就將這個請求插入到佇列的末尾。另外,如果請求佇列中的某個請求超過的預先定義的過期閾值,新請求即使可以進行排序,也被插入到佇列的末尾。這樣可以防止磁碟上某個區域產生大量請求,而其他區域的請求被餓死。然而,這種過期策略並不十分高效。

這種演算法可能導致請求餓死的情況,它是 Linux 2.4 的唯一排程器。

當一個請求加入到請求佇列時,IO 排程器所完成的操作如下

  1. 如果佇列中存在對相鄰扇區的請求,則合併兩個請求為一個
  2. 如果佇列中存在超過過期時間的請求,那麼新請求被插入到佇列的末尾,以防止餓死老的請求
  3. 如果佇列中存在可以按扇區地址排序的合適位置,那麼將請求插入到這個位置
  4. 如果佇列中沒有合適的可插入位置,請求被插入到佇列末尾

Deadline – latency-oriented

Deadline 排程器是設計用來解決 Linus Elevator 導致的 I/O 餓死的問題。對磁碟上某個區域的大量請求,會無限期的餓死 (starvation) 對磁碟其他區域上的請求。

請求餓死的一個特例是 寫請求餓死讀請求 (writes starving reads),對於程式來說,當需要進行寫操作時,由於需要寫的資料在記憶體的 page cache 中,程式是需要修改對應的記憶體,向核心傳送寫請求即可,之後程式可以去進行其他操作,由核心負責將資料同步至磁碟中即可。對於程式來說,寫請求是非同步操作。而讀操作是完全不同的,當程式需要讀取資料時,需要向核心傳送讀請求,核心將資料載入到記憶體中,由於程式往往需要處理讀取的資料,因此程式將處於阻塞狀態,直到請求被處理完成。對於程式來說,讀請求是同步的操作。寫請求延遲對系統的效能影響不大,而讀請求延遲對系統效能影響是非常大的,因此兩種 IO 請求需要區別對待。

Dealine 排程器專門針對讀請求延遲進行了優化,在 deadline 演算法中,每一個請求都有一個過期時間。預設情況下,讀請求的過期時間是 500ms,寫請求的過期時間是 5s。Dealine 排程器也會對請求佇列進行合併和排序操作,這個佇列稱作排序佇列(sorted queue)。當新請求被提交,Deadline將其加入到排序佇列中進行合併和排序。同時 Deadline 將這個請求加入到第二種型別的佇列中,讀請求被加入至讀FIFO佇列 (Read FIFO queue),寫請求被加入到寫FIFO佇列 (Write FIFO queue),這兩個佇列中,請求完全按照 FIFO 順序排列,即新請求永遠被放入到佇列的末尾。

這樣一來 Dealine 就維護三個佇列,正常情況下,Deadline 將排序佇列中的請求放入到排程佇列 (dispatch queue,即將寫入磁碟的佇列)中,排程佇列把請求傳送至磁碟驅動。如果寫 FIFO 佇列或讀 FIFO 佇列中的請求發生了超時,Deadline 排程器就不再使用排序佇列,而是開始將發生超時的 FIFO 佇列的請求放入排程佇列,直至佇列中沒有超時的請求,Deadline 通過這樣的方式保證所有的請求都不會長時間超時。

Deadling 防止了請求餓死的出現,由於讀請求的超時時間遠小於寫請求,它同時也避免了出現寫請求餓死讀請求。

Deadline 比較適合於MySQL資料庫。

Anticipatory(AS)

AS 排程器是基於 Deadline 排程器,加上了一個啟發式的「預測」,假設系統中有大量的寫請求,這時如果夾雜幾個讀請求,由於讀請求的過期時間短,讀請求立即在多個寫請求的中間產生,這樣會導致磁碟的來回尋道,AS 試圖減少大量寫請求夾雜少量讀請求產生的尋道風暴(seek storm)。當一個讀請求完成後,AS不會立即返回處理佇列中的剩餘請求,而是等待一個預測時間(預設為 6ms),如果等待的時間內發生了相鄰位置的讀請求,那麼立即處理這個相鄰位置的讀請求,再返回處理佇列中的請求,這樣可以優化多餘的尋道時間。

它可以為連續 IO 請求(如順序讀)進行了一定的優化,但是對於隨機讀的場景 AS 會產生較大的延遲,對於資料庫應用很糟糕,而對於 Web Server 可能會表現的不錯。這個演算法也可以簡單理解為面向低速磁碟的,對於使用了 TCG(Tagged Command Queueing)高效能的磁碟和 RAID,使用 AS 會降低效能。

在 Linux 2.6 – 2.6.18 AS 是核心預設排程器,然而大多數的企業發行版選擇的是 CFQ 排程器。

到Linux 2.6.33 版本,AS 被從核心中移除,因為可以通過調整其他排程器(如 CFQ)來實現與其相似的功能。

Complete Fair Queuing(CFQ)- fairness-oriented

CFQ 為每個程式分配一個 I/O 請求佇列,在每個佇列的內部,進行合併和排序的優化。CFQ 以輪詢的方式處理這些佇列,每次從一個佇列中處理特定數量的請求(預設為 4 個)。它試圖將 I/O 頻寬均勻的分配至每個程式。CFQ 原本針對的是多媒體或桌面應用場景,然而,CFQ 其實在許多場景中內表現的很好。CFQ 對每一個 IO 請求都是公平的。這使得 CFQ 很適合離散讀的應用 (eg: OLTP DB)

多數企業髮型版選擇 CFQ 作為預設的 I/O 排程器。

NOOP(No Operation)

該演算法實現了最簡單的 FIFO 佇列,所有 IO 請求按照大致的先後順序進行操作。之所以說「大致」,原因是 NOOP 在 FIFO 的基礎上還做了相鄰 IO 請求的合併,但其不會進行排序操作。

NOOP 適用於底層硬體自身就具有很強排程控制器的塊裝置(如某些SAN裝置),或者完全隨機訪問的塊裝置(如SSD)。

各個排程器在資料庫應用下的效能,可以看出CFQ的效能是比較均衡的

IO 引數調整

佇列長度

檢視佇列長度

/sys/block/<dev>/queue/nr_requests

下圖展示了各種佇列長度時,Deadline 和 CFQ 排程器的效能

 

由 ext3 的表現可以看出,對於大量的小檔案寫操作,佇列長度更長,效能會有所提升,在 16KB 左右,效能提升最為明顯,在 64KB 時,64 至 8192 的佇列長度有著差不多的效能。隨著檔案大小的增大,小佇列長度反而有著更好的效能。 RHEL 作業系統中,每個裝置有一個佇列長度。對於類似資料庫日誌的存放分割槽,大部分寫操作屬於小檔案 IO,可以將佇列長度調小。

對於大量的連續讀取,可以考慮增加讀取首部的視窗大小

/sys/block/<dev>/queue/read_ahead_kb

IO排程器

選擇裝置的IO排程器

/sys/block/<dev>/queue/scheduler

或者在 grub.conf 中加入核心引數 elevator=SCHEDULER

Deadline引數

/sys/block/<device>/queue/iosched/writes_starved

進行一個寫操作之前,允許進行多少次讀操作

/sys/block/<device>/queue/iosched/read_expire

讀請求的過期時間

/sys/block/<device>/queue/iosched/read_expire

寫請求的過期時間,預設為 500ms

/sys/block/sda/queue/iosched/front_merges

是否進行前合併

Anticipatory引數

/sys/block/<device>/queue/iosched/antic_expire

預測等待時長,預設為 6ms

/sys/block/<device>/queue/iosched/{write_expire,read_expire}

讀寫請求的超時時長

/sys/block/<device>/queue/iosched/{write_batch_expire,read_batch_expire}

讀寫的批量處理時長

CFQ引數

/sys/block/<device>/queue/iosched/slice_idle

當一個程式的佇列被分配到時間片卻沒有 IO 請求時,排程器在輪詢至下一個佇列之前的等待時間,以提升 IO 的區域性性,對於 SSD 裝置,可以將這個值設為 0。

/sys/block/<device>/queue/iosched/quantum

一個程式的佇列每次被處理 IO 請求的最大數量,預設為 4,RHEL6 為 8,增大這個值可以提升並行處理 IO 的效能,但可能會造成某些 IO 延遲問題。

/sys/block/<device>/queue/iosched/slice_async_rq

一次處理寫請求的最大數

/sys/block/<device>/queue/iosched/low_latency

如果IO延遲的問題很嚴重,將這個值設為 1

調整CFQ排程器的程式IO優先順序

$ ionice [[-c class] [-n classdata] [-t]] -p PID [PID]...$ ionice [-c class] [-n classdata] [-t] COMMAND [ARG]...

CFQ 的程式 IO 優先順序和程式 CPU 優先順序是獨立的。使用 ionice 調整程式優先順序,有三種排程型別可以選擇

  • idle
    只有在沒有更高優先順序的程式產生 IO 時,idle 才可以使用磁碟 IO,適用於哪些不重要的程式(如 updatedb),讓它們在磁碟空閒時再產生 IO
  • Best-effort
    這個型別共有 8 個優先順序,分別為 0-7,數字越低,優先順序越高,相同級別的優先順序使用輪詢的方式處理。適用於普通的程式。在2.6.26之前,沒有指定排程型別的程式使用”none” 排程型別,IO排程器將其視作Best-effort進行處理,這個類別中程式優先順序由CPU優先順序計算得來: io_priority = (cpu_nice + 20) / 52.6.26之後,沒有指定排程型別的程式將從CPU排程型別繼承而來,這個類別的優先順序仍按照CPU優先順序計算而來: io_priority = (cpu_nice + 20) / 5
  • Real time
    這個排程級別的程式產生的IO被優先處理,這個排程型別應小心使用,防止餓死其他程式IO, 它也有8個優先順序,數字越大分的的IO時間片越長

檔案系統

一般來說 ReiserFS 更適合於小檔案 IO,而 XFS 和 JFS 適合大檔案 IO,ext4 則處於兩種之間。

JFS 和 XFS 適用於大型的資料倉儲,科學計算,大型 SMP 伺服器,多媒體流服務等。ReiserFS 和 Ext4 適合於檔案伺服器,Web 伺服器或郵件伺服器。

noatime

atime 用於記錄檔案最後一次被讀取的時間。預設情況下,檔案每次被讀取或修改(也需要先讀取),系統將更新 atime 並寫入至檔案後設資料中。由於寫操作是很昂貴的,減少不必要的寫操作可以提升磁碟效能。然後,大多數時候,關閉檔案的 atime 也只能獲得非常小的效能提升(這個說法來自於IBM Redbook,表示懷疑)。

使用 noatime 掛載檔案系統,將不對檔案的 atime 進行更新,此時 atime就相當於 mtime。磁碟效能可以得到0-10%的提升。

使用 noatime掛載方法

/dev/sdb1 /mountlocation ext3 defaults,noatime 1 2

nobarrier

barrier 是保證日誌檔案系統的 WAL (write ahead logging) 一種手段,資料寫入磁碟時,理應先寫入 journal 區,再寫入資料在磁碟的實際對應位置,磁碟廠商為了加快磁碟寫入速度,磁碟都內建 cache,資料一般都先寫入磁碟的 cache。

cache 能加快寫入速度,但磁碟一般會對 cache 內快取資料排序使之最優重新整理到磁碟,這樣就可能導致要重新整理的實際資料和 journal 順序錯亂。一旦系統崩潰,下次開機時磁碟要參考 journal 區來恢復,但此時 journal 記錄順序與資料實際重新整理順序不同就會導致資料反而「恢復」到不一致了。而barrier 如其名——「柵欄」,先加一個「柵欄」,保證 journal 總是先寫入記錄,然後對應資料才重新整理到磁碟,這種方式保證了系統崩潰後磁碟恢復的正確性,但對寫入效能有影響。

資料庫伺服器底層儲存裝置要麼採用 RAID 卡,RAID 卡本身的電池可以掉電保護;要麼採用 Flash 卡,它也有自我保護機制,保證資料不會丟失。所以我們可以安全的使用 nobarrier 掛載檔案系統。設定方法如下: 對於 ext3,ext4 和 reiserfs 檔案系統可以在 mount 時指定 barrier=0;對於 xfs 可以指定 nobarrier 選項。

read-ahead 預讀

Linux 把讀模式分為隨機讀和順序讀兩大類,並只對順序讀進行預讀。這一原則相對保守,但是可以保證很高的預讀命中率。

為了保證預讀命中率,Linux只對順序讀 (sequential read) 進行預讀。核心通過驗證如下兩個條件來判定一個 read() 是否順序讀:

  1. 這是檔案被開啟後的第一次讀,並且讀的是檔案首部;
  2. 當前的讀請求與前一(記錄的)讀請求在檔案內的位置是連續的。

如果不滿足上述順序性條件,就判定為隨機讀。任何一個隨機讀都將終止當前的順序序列,從而終止預讀行為(而不是縮減預讀大小)。

預讀視窗

Linux採用了一個快速的視窗擴張過程

  • 首次預讀: readahead_size = read_size * 2 // or *4
    預讀視窗的初始值是讀大小的二到四倍。這意味著在您的程式中使用較大的讀粒度(比如32KB)可以稍稍提升I/O效率。
  • 後續預讀:readahead_size *= 2
    後續的預讀視窗將逐次倍增,直到達到系統設定的最大預讀大小,其預設值是 256KB

檢視和修改預讀視窗

$ blockdev -getra device
$ blockdev -setra N device

日誌模式

大多數檔案系統可以設定三種日誌模式,對於 ext4 檔案系統,日誌模式對磁碟的效能有較大的影響。

  • data=journal
    資料和後設資料都寫入日誌,提供了最高的資料一致性
  • data=ordered (預設)
    只記錄後設資料,然後它會保證先將資料寫入磁碟
  • data=writeback
    採用回寫的方式,犧牲資料一致性,獲得更好的效能。仍然會將後設資料記錄到日誌中,此模式對小檔案 IO 效能提升最為明顯,但可能造成資料丟失。

將日誌放在單獨的裝置中

  1. 解除安裝檔案系統
  2. 檢視檔案系統塊大小和日誌引數
    $ dumpe2fs /dev/sdb1
  3. 移除檔案系統內部的日誌區
    $ tune2fs -O ^has_journal /dev/sdb1
  4. 建立外部的日誌裝置
    $ mke2fs –O journal_dev -b block-size /dev/sdc1
  5. 更新原檔案系統的超級塊
    $ tune2fs -j -J device=/dev/sdc1 /dev/sdb1

commit

設定多少秒從日誌中進行一個同步,預設是5

優化Ext4

  1. 格式大檔案系統化時延遲 inode 的寫入對於超大檔案系統,mkfs.ext4 程式要花很長時間初始化檔案系統中到所有內節點表。可使用 -E lazy_itable_init=1 選項延遲這個程式。如果使用這個選項,核心程式將在掛載檔案系統後繼續初始化該檔案它。
    $ mkfs.ext4 -E lazy_itable_init=1 /dev/sda5
  2. 關閉Ext4的自動 fsync() 呼叫
    -o noauto_da_alloc 或 mount -o noauto_da_alloc
  3. 降低日誌IO的優先順序至與資料IO相同
    -o journal_ioprio=n
    n的用效取值範圍為0-7,預設為3;

檢視檔案系統鎖

$ cat /proc/locks

Benchmark 基準測試

iozone

使用iozone對檔案系統進行基準測試

  • $ iozone -a
    iozone將在所有模式下進行測試,使用記錄塊從4k到16M,測試檔案大小從64k到512M
  • $ iozone -Ra 或 iozone -Rab output.xls
    iozone將測試結果放在Excel中
  • $ iozone -Ra -g 2g
    如果記憶體大於512MB,則測試檔案需要更大;最好測試檔案是記憶體的兩倍。例如記憶體為1G,將測試檔案設定最大為2G

$ iozone -Ra -g 2g -i 0 -i 1

如果只關心檔案磁碟的read/write效能,而不必花費時間在其他模式上測試,則我們需要指定測試模式

$ iozone -Rac

如果測試NFS,將使用-c,這通知iozone在測試過程中執行close()函式。使用close()將減少NFS客戶端快取的影響。但是如果測試檔案比記憶體大,就沒有必要使用引數-c

-a  在所有模式下進行測試,使用記錄塊從4k到16M,測試檔案大小從64k到512M
-b  生成excel檔案
-R  生成excel輸入
-f  指定臨時檔名
-g  自動模式的最大檔案大小
-n  自動模式的最小檔案大小
-s  指定檔案大小,預設單位是KB, 也可以使用m 和 g
-y  自動模式的最小記錄大小,預設單位是KB
-q  自動模式的最大記錄大小,預設單位是KB
-r  指定記錄大小,單位是KB
-i  選擇測試模式
0=write/rewrite
1=read/re-read
2=random-read/write
3=Read-backwards
4=Re-write-record
5=stride-read
6=fwrite/re-fwrite
7=fread/Re-fread,
8=random mix
9=pwrite/Re-pwrite
10=pread/Re-pread
11=pwritev/Re-pwritev
12=preadv/Repreadv

一個例子

$ iozone -a -s 128M -y 512 -q 16384 -i 0 -i 1 -i 2 -f /test/a.out -Rb /root/ext3_writeback.out

dd

$ dd bs=1M count=128 if=/dev/zero of=test conv=fdatasync

使用這個引數,dd命令執行到最後會真正執行一次同步(sync)操作

$ dd bs=1M count=128 if=/dev/zero of=test oflag=direct 使用直接IO(繞過快取)

bonnie++

usage: bonnie++ [-d scratch-dir] [-s size(Mb)[:chunk-size(b)]]
 [-n number-to-stat[:max-size[:min-size][:num-directories]]]
 [-m machine-name]
 [-r ram-size-in-Mb]
 [-x number-of-tests] [-u uid-to-use:gid-to-use] [-g gid-to-use]
 [-q] [-f] [-b] [-p processes | -y]
-d 生成測試檔案的路徑
-s 生成測試檔案的大小,以M為單位(如果不使用-r引數,則要求檔案大小至少是系統實體記憶體的2倍)
-m 機器名,實際上我們可以認為是本次測試的方案名,可以隨便定義。預設是本機的hostname。
-r 記憶體大小,指定記憶體大小,這樣可以通過-s引數建立r*2大小的檔案,通常用於縮短測試時間,但是需要注意這樣由於記憶體的cache可能導致測試結果的不準確
-x 測試的次數
-u 測試檔案的屬主和組,預設是執行bonnie++的當前使用者和當前組
-g 測試檔案的組,預設是執行bonnie++的當前用組
-b 在每次寫檔案時呼叫fsync()函式,對於測試郵件伺服器或者資料庫伺服器這種通常需要同步操作的情況比較適合,而不使用該引數則比較適合測試copy檔案或者編譯等操作的效率。

可以簡單地執行如下命令進行磁碟效能測試:

$ bonnie++ -d /global/oradata –m sun3510

這樣將會在指定的目錄下(通常我們會指定一個盤陣上卷的掛載點),生成相當於主機實體記憶體兩倍的檔案,如果總量大於1G,則生成多個大小為1G的檔案。假設主機記憶體為4G,那麼在測試中就會生成8個1G的檔案,到測試結束,這些檔案會被自動刪除。

如果我們的主機記憶體是4G,但是我們想縮短測試的時間,比如說只寫2G的檔案,就應該執行下面的命令:

$ bonnie++ -d /global/oradata –m sun3510 –s 2048 –r 1024

blktrace & blkparse

blktrace 是一個針對 Linux 核心中塊裝置 IO 層的跟蹤工具,用來收集磁碟IO 資訊中當 IO 進行到塊裝置層(block層,所以叫blk trace)時的詳細資訊(如 IO 請求提交,入隊,合併,完成等等一些列的資訊),blktrace 需要藉助核心經由 debugfs 檔案系統(debugf s檔案系統在記憶體中)來輸出資訊,所以用 blktrace 工具之前需要先掛載 debugfs 檔案系統,blktrace需要結合 blkparse 來使用,由 blkparse 來解析 blktrace 產生的特定格式的二進位制資料。

blktrace語法:

blktrace -d dev [ -r debugfs_path ] [ -o output ] [-k ] [ -w time ] [ -a action ] [ -A action_mask ] [ -v ]

blktrace選項:
 -A hex-mask        #設定過濾資訊mask成十六進位制mask
 -a mask            #新增mask到當前的過濾器
 -b size            #指定快取大小for提取的結果,預設為512KB
 -d dev         #新增一個裝置追蹤
 -I file            #Adds the devices found in file as devices to trace
 -k             #殺掉正在執行的追蹤
 -n num-sub     #指定緩衝池大小,預設為4個子緩衝區 
 -o file            #指定輸出檔案的名字
 -r rel-path        #指定的debugfs掛載點
 -V             #版本號 
 -w seconds     #設定執行的時間

檔案輸出

$ blktrace –d /dev/sda –o trace

解析結果 $ blkparse -i trace -o /root/trace.txt

FIO

FIO 是測試 IOPS 的非常好的工具,用來對硬體進行壓力測試和驗證,支援 13 種不同的 IO 引擎,包括:sync, mmap, libaio, posixaio, SG v3, splice, null, network, syslet, guasi, solarisaio 等等。

隨機讀

$ fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=16k -size=200G 
-numjobs=10 -runtime=1000 -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                每個程式生成檔案的數量。

順序讀

$ fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=read -ioengine=psync -bs=16k -size=200G -numjobs=30 -runtime=1000 -group_reporting -name=mytest

隨機寫

$ fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=16k -size=200G -numjobs=30 -runtime=1000 -group_reporting -name=mytest

順序寫

$ fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=16k -size=200G -numjobs=30 -runtime=1000 -group_reporting -name=mytest

混合隨機讀寫

$ fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=16k -size=200G -numjobs=30 -runtime=100 -group_reporting -name=mytest -ioscheduler=noop

stress

它可以給我們的系統施加 CPU,記憶體,IO 和磁碟的壓力,在模擬極端場景給應用系統造成的壓力方面很有幫助。

示例

$ stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10d

相關文章