用systemtap對sysbench IO測試結果的分析-愛可生

測試環境準備

  • 運行前,通過echo 1 > /proc/sys/vm/drop_caches清理IO cache
  • 運行前,通過iostat -x -p {dev} 1確認沒有其它IO影響結果
  • sysbench參數
<code>sysbench --test=fileio --num-threads=$SYSBENCH_NUM_THREADS --file-num=$SYSBENCH_FILE_NUM --file-block-size=$SYSBENCH_BLOCK_SIZE --file-total-size=$SYSBENCH_FILE_TOTAL_SIZE --file-test-mode=$1 --file-io-mode=sync --file-extra-flags=$DIRECT --file-fsync-all=$FSYNC --file-fsync-mode=fsync --file-fsync-freq=0 --file-merged-requests=0 --max-time=$SYSBENCH_TIME --max-requests=0/<code>

其中的變量參數

<code>binlog 異常暴漲分析SYSBENCH_FILE_TOTAL_SIZE=16G
SYSBENCH_FILE_NUM=16
SYSBENCH_NUM_THREADS=16
DIRECT=
FSYNC=off
SYSBENCH_BLOCK_SIZE=4096
SYSBENCH_TIME=60/<code>

附件中的run_sysbench.sh是運行sysbench的腳本,每個實驗的輸出都附在附件中,樣例輸出:

用systemtap對sysbench IO測試結果的分析-愛可生

現象1

步驟1

1.非Direct I/O模式,測試順序寫

<code>./run_sysbench.sh seqrewr run | tee 1_sysbench_seqrewr/<code>

2.非Direct I/O模式測試隨機寫

<code>./run_sysbench.sh rndwr run | tee 2_sysbench_rndwr/<code>

3.Direct I/O模式,測試順序寫(seqrewr)

<code>DIRECT=1 ./run_sysbench.sh seqrewr run | tee 3_sysbench_direct_seqrewr/<code>

4.Direct I/O模式,測試隨機寫(rndwr)

<code>DIRECT=1 ./run_sysbench.sh rndwr run | tee 4_sysbench_direct_rndwr/<code>

結果1

用systemtap對sysbench IO測試結果的分析-愛可生

對於磁盤的I/O測試,直覺上順序寫比隨機寫要快很多。從測試結果可以看到:

  1. 在Direct I/O模式下,與直覺結果相符
  2. 在非Direct I/O模式下,隨機寫比順序寫IOPS快4倍, 吞吐與IOPS成正比。這一點是違反直覺的

對結果的分析將集中在非Direct I/O模式下。

分析1

我們一時間對上述結果沒有任何頭緒,也不大可能是意外發明瞭隨機寫更快的磁盤. 先嚐試觀察對磁盤的IO壓力分佈:

<code>iostat -x -p /dev/sdb 1/<code>

觀察到在sysbench結束後,順序寫的I/O壓力為0,但隨機寫的I/O壓力仍將持續一些時間。隨即懷疑sysbench在順序寫時用fsync進行刷盤,並等待刷盤結束。在等待期間沒有sysbench不發出新的IO請求,自然IOPS會降低。但sysbench參數中已經設置了--file-fsync-all=off,與現象衝突。

用strace確認這一結論:

<code>strace -e trace=fsync -f ./run_sysbench.sh seqrewr run 2>&1 | tee 5_strace_sysbench_seqrewr/<code>

可以看到顯式的fsync調用。

在sysbench源碼中可以找到與FILE_OP_TYPE_FSYNC相關的一段代碼:

<code>    if (file_fsync_end && file_req->operation == FILE_OP_TYPE_WRITE &&
        fsynced_file2 < num_files)
    {
      file_req->file_id = fsynced_file2;
      file_req->pos = 0;
      file_req->size = 0;
      file_req->operation = FILE_OP_TYPE_FSYNC;
      fsynced_file2++;
    }/<code>

意味著這個fsync與sysbench參數file-fsync-end相關。解決方案:1. 設置--file-fsync-end=no2. 在測試中sysbench順序寫 寫完所有文件的時間--max-time, 避免多出的fsync

之後的測試中, 將置--file-fsync-end=no, 並將--max-time設為30, 避免fsync, 且減少測試時間成本。

插曲1

在分析的過程中,實際過程要比上述描述艱辛一些。

觀測工具使用不當帶來測試偏差。

用strace確定是否有fsync調用時,最初用的命令是:

<code>strace -f ./run_sysbench.sh seqrewr run 2>&1 | tee 5_strace_sysbench_seqrewr/<code>

由於缺少了-e trace=fsync參數,strace的成本上升,導致sysbench的性能下降,使得寫完所有文件的時間>--max-time,就沒有發現fsync調用。

這一結果與預期不符,一時陷入僵局。繞了一圈後懷疑和觀測工具相關,雖沒有定位到是因為觀測工具引起的性能下降,但可以嘗試用另一個觀測工具來校準偏差。在此選定的工具是systemtap。

使用另一觀測工具用於校準 — systemtap

Systemtap 提供了極低成本的內核檢測能力,類似於Dtrace,詳細的介紹請找官方文檔。

以檢測fsync調用為例演示systemtap的用法:

  1. 環境準備請找官方文檔
  2. 編輯systemtap腳本 6_systemtap_fsync_summary.stp
<code>!/usr/bin/env stap
global r
probe syscall.fsync {
        r[pid()] < 1
}

probe end {
        foreach ([pid-] in r) {
                printf ("pid=%d, fsync=%d times\n", pid, @count(r[pid]))
        }
}/<code>

3.編譯

<code>stap -v -r $(uname -r) -DMAXSKIPPED=100000 -DSTP_NO_OVERLOAD 6_systemtap_fsync_summary.stp -m 6_systemtap_fsync_summary.ko/<code>

systemtap在觀測負荷會顯式影響系統性能時,會”跳過”一些觀測點,這樣不會影響系統性能,可以安全地使用,但會造成結果不準確。-DMAXSKIPPED=100000 -DSTP_NO_OVERLOAD 這兩個參數能systemtap儘量”不計成本”地觀測,但需要警惕其帶來的開銷。後續編譯中默認會使用這兩個參數,但所有結果需要和不使用參數的情況進行對比,來發現並規避其影響。本文不記述對比的過程。

4.使用

<code>staprun -v fsync_summary.ko | tee 6_systemtap_fsync_summary/<code>

輸出如下:

<code>pid=34888, fsync=16 times/<code>

可以看到16個fsync調用,與sysbench配置的線程數一致。即證明之前不當使用strace造成了觀測結果的偏差。

5.說明systemtap可以一鍵運行腳本,但我們用了編譯+運行兩個步驟,原因是systemtap的編譯環境配置比較繁複,因此我們將編譯環境隔離到了一個容器中,而將編譯好的.ko文件放到目標機上運行,目標機只需安裝簡單的依賴就可以運行。避免環境汙染。

覆盤1

回頭重看現象1的分析過程, 有幾點教訓:1.其實sysbench的標準輸出已經給出了問題原因:

<code>...
Extra file open flags: 0
16 files, 1Gb each
16Gb total file size
Block size 4Kb
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
.../<code>

Calling fsync() at the end of test, Enabled.,藏在一堆數字中信息容易被忽略

2.對觀測工具要進行校準

現象2

步驟2

根據現象1的分析,調整sysbench參數:置--file-fsync-end=no,並將--max-time設為30。重新運行非Direct IO模式的順序寫和隨機寫的測試。

1.測試順序寫

<code>SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run | tee 7_sysbench_seqrewr/<code>

2.測試隨機寫

<code>SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run | tee 8_sysbench_rndwr/<code>

結果2

用systemtap對sysbench IO測試結果的分析-愛可生

比之前的結果好一些,但觀察仍到兩個異常現象:

1. 現象2的隨機寫效率高於現象1。猜測是因為縮短了--max-time,導致文件系統緩存仍然在預熱過程中,不需等待回刷。之後的分析中將略過這一點,並不影響分析結果。2. 順序寫的效率仍然低於隨機寫。對這個現象完全沒有想法。

分析2.1 – 端到端的延遲分佈

如果對Linux I/O棧比較陌生,可以查看Linux Storage Stack Diagram 做初步瞭解。

由於對”順序寫的效率低於隨機寫”這一現象沒有任何想法,就先測量一下端到端的延遲分佈,即站在vfs層的角度看延遲分佈。

期望是能判斷延遲是否平均,是否由於個別I/O的異常拖慢了整體水平。

還是用到了systemtap腳本,此處略去編譯過程,直接給出腳本和結果。

systemtap腳本2.1

vfs_write_latency.stp

<code>global input_devname="sdb"
global io_latency

probe vfs.write.return {
        if (bytes_to_write > 0 && input_devname == devname) {
                time = gettimeofday_ns() - @entry(gettimeofday_ns())
                io_latency < time
        }
}

probe end {
        print (@hist_log(io_latency))
}/<code>

運行2.1

1.測試順序寫

<code>1> staprun -v vfs_write_latency.ko 2>&1 | tee 9_systemtap_vfs_write_latency_seqrewr
2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>

2.測試隨機寫

<code>1> staprun -v vfs_write_latency.ko 2>&1 | tee 10_systemtap_vfs_write_latency_rndwr
2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>

結果2.1

1.順序寫

用systemtap對sysbench IO測試結果的分析-愛可生

2.隨機寫

用systemtap對sysbench IO測試結果的分析-愛可生

可以看到:1. 存在skipped probes. systemtap認為有一個觀測點影響太大,因此跳過。2. 存在一個非常離譜的異常點:1152921504606846976ns,以至對平均值產生了很大影響。這可能是由於skipped probes引起的。之後的分析將這個異常點去掉。3. 存在兩段峰值:2048~524288ns,2097152~1073741824ns。第二段的命中次數遠低於第一段,但延遲佔有一定比例。由於一時沒有頭緒,先忽略這一現象,留待之後解決。4. 隨機寫比順序寫的低延遲段(4096ns附近)的分佈要多一些。

目前為止沒有進展。下一步試試研究設備層的I/O請求特徵,期望是設備層的I/O請求特徵正常,從而確認問題出在文件系統和IO調度上。

分析2.2 – 設備層的I/O請求特徵

systemtap腳本2.2

用systemtap對sysbench IO測試結果的分析-愛可生

運行2.2

1.測試順序寫

<code>1> staprun -v ioblock_request_summary.ko 2>&1 | tee 11_systemtap_ioblock_write_latency_seqrewr
2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>

2.測試隨機寫

<code>1> staprun -v ioblock_request_summary.ko 2>&1 | tee 12_systemtap_ioblock_write_latency_rndwr
2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>

結果2.2

  1. 測試順序寫 (結果經過縮減)
  2. 測試隨機寫 (結果經過縮減)rw是讀寫模式,io_size是設備I/O的大小,count是次數,avg_latency是平均延遲。

可以看到:

  1. 順序寫的設備I/O的大小集中在大於4k的區域,即在之前經過了合併。隨機寫的設備I/O的大小几種在4k,即沒有經過合併. 符合預期
  2. 從延遲上沒有發現明顯的差異

可以得到的結論是:順序寫和隨機寫的反常的性能差異很大程度來自於文件系統和IO調度。

分析2.3 – 文件系統的緩存命中率

想到問題可能在文件系統,那可能性比較大的是緩存系統的命中率。順序寫的緩存命中率較低,隨機寫的緩存命中率較高,即幾個發往文件系統的隨機寫請求可能寫的是同一個數據塊。猜測隨機寫在文件系統緩存的代價較小,因此性能較好。

下面驗證文件系統的緩存命中率。可以參考Brendan Gregg神的cachestat。不過此處由於只需要對比趨勢而不需要保證絕對值正確,所以可以簡化實現。

systemtap腳本2.3.1

用systemtap對sysbench IO測試結果的分析-愛可生

運行2.3.1

1.測試順序寫

<code>1> staprun -v io_cache_hit_ratio.ko 2>&1 | tee 13_systemtap_io_cache_hit_ratio_seqrewr
2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>

2.測試隨機寫

<code>1> staprun -v io_cache_hit_ratio.ko 2>&1 | tee 14_systemtap_io_cache_hit_ratio_rndwr
2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code> 

結果2.3.1


可以看到, 隨機寫的緩存命中率(1-add_to_page_cache_lru/pagecache_get_page)比順序寫要高。之後的測試,我們增大sysbench文件的總大小到64G,來降低隨機寫的緩存命中率。

運行2.3.2

1.測試順序寫

<code>1> staprun -v io_cache_hit_ratio.ko 2>&1 | tee 15_systemtap_io_cache_hit_ratio_64G_seqrewr
2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>

2.測試隨機寫

<code>1> staprun -v io_cache_hit_ratio.ko 2>&1 | tee 16_systemtap_io_cache_hit_ratio_64G_rndwr
2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>

結果2.3.2

用systemtap對sysbench IO測試結果的分析-愛可生

可以看到,隨著測試文件增大,隨機寫的緩存命中率下降,性能也隨之下降。寫緩存的命中率是隨機寫和順序寫性能差異的影響因素之一。

分析2.4 – 文件系統的緩存延遲分析

分析2.3的結果是隨機寫和順序寫的性能差不多,但我們仍可以進一步分析緩存的延時:找一個使用緩存的堆棧,逐層做延遲分析,這是個笨拙但有效的方法。

Systemtap本身提供了大量腳本,其中就有一些成熟的函數入口可以直接借用,而不用自己讀Linux源碼分析backtrace,比如對於緩存,找到/usr/share/systemtap/tapset/linux/vfs.stp文件,搜一下cache,就可以找到以下入口點:

<code>probe vfs.add_to_page_cache =
        kernel.function("add_to_page_cache_locked") !,
        kernel.function("add_to_page_cache")
{
...
}/<code>

之後可以通過systemtap打印出add_to_page_cache的調用棧 (在3.19內核中, 實際使用了add_to_page_cache_lru,這個需要查看源碼才能知道此處的變更),此處不詳述,結果如下:

用systemtap對sysbench IO測試結果的分析-愛可生

然後觀測這個堆棧中每個函數的延遲,這個過程中需要特別注意如果觀測點過多,那麼對性能結果會有較大影響,以致影響分析的結論。因此每一次觀測後需要對比觀測前後的性能差別,如果差異過大,應調整觀測手段或減小觀測的範圍。

在此我們就假設運氣很好,一次觀測就能命中要害。

systemtap腳本2.4.1

ext4_write_latency.stp

<code>global input_devname="sdb"

global latency_ext4_file_write_iter
probe kernel.function("ext4_file_write_iter").return {
        dev = __file_dev($iocb->ki_filp)
        devname = __find_bdevname(dev, __file_bdev($iocb->ki_filp))
        if (devname == input_devname) {
                latency_ext4_file_write_iter < gettimeofday_ns()-@entry(gettimeofday_ns())
        }
}

global latency___generic_file_write_iter
probe kernel.function("__generic_file_write_iter").return {
        dev = __file_dev($iocb->ki_filp)
        devname = __find_bdevname(dev, __file_bdev($iocb->ki_filp))
        if (devname == input_devname) {
                latency___generic_file_write_iter < gettimeofday_ns()-@entry(gettimeofday_ns())
        }
}

probe end {
        printf ("ext4_file_write_iter latency: %d\n", @avg(latency_ext4_file_write_iter))
        printf ("__generic_file_write_iter latency: %d\n", @avg(latency___generic_file_write_iter))
}/<code>

運行2.4.1

1.測試順序寫

<code>1> staprun -v ext4_write_latency.ko 2>&1 | tee 17_systemtap_ext4_write_latency_seqrewr
2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>

2.測試隨機寫

<code>1> staprun -v ext4_write_latency.ko 2>&1 | tee 18_systemtap_ext4_write_latency_rndwr
2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>

結果2.4.1

用systemtap對sysbench IO測試結果的分析-愛可生

可以看到:1. 順序寫與隨機寫相比,__generic_file_write_iter的開銷明顯減小,符合常識2. 順序寫與隨機寫相比,ext4_file_write_iter在其他方面的開銷佔比明顯增加

分析2.4.1

從結果1得到結論:ext4_file_write_iter在其他方面的開銷佔比明顯增加。至於哪個方面的開銷增加了,得粗看一下源碼(源碼已將不重要的部分略去):

<code>static ssize_t
ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
       ...

        /*
         * Unaligned direct AIO must be serialized; see comment above
         * In the case of O_APPEND, assume that we must always serialize
         */
        if (o_direct && ...) {
            ...
        }

        mutex_lock(&inode->i_mutex);
        if (file->f_flags & O_APPEND) ...;

        /*
         * If we have encountered a bitmap-format file, the size limit
         * is smaller than s_maxbytes, which is for extent-mapped files.
         */
        if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
                ...
        }

        ...
        if (o_direct) {
                ...
        }

        ret = __generic_file_write_iter(iocb, from);
        mutex_unlock(&inode->i_mutex);

        if (ret > 0) {
                ...
        }
        if (o_direct) ...;

errout:
        if (aio_mutex) ...;
        return ret;
}/<code>

源碼已將分支內的部分略去,只留下主幹。可以看到:1. 代碼特別處理了一些情況(比如, Direct I/O,append模式等)2. 主幹上的操作主要是__generic_file_write_iter和鎖inode->i_mutex

因此可以懷疑鎖inode->i_mutex的代價是否過高

systemtap腳本2.4.2

腳本generic_file_write_iter_concurrency.stp用於觀測__generic_file_write_iter的並行度,以此來估算鎖inode->i_mutex的代價。

<code>global input_devname="sdb"

global concurrency, max_concurrency
probe kernel.function("__generic_file_write_iter") {
        dev = __file_dev($iocb->ki_filp)
        devname = __find_bdevname(dev,
                                  __file_bdev($iocb->ki_filp))
        if (devname == input_devname) {
                concurrency += 1
                max_concurrency < concurrency
        }
}

probe kernel.function("__generic_file_write_iter").return {
        dev = __file_dev($iocb->ki_filp)
        devname = __find_bdevname(dev,
                                  __file_bdev($iocb->ki_filp))
        if (devname == input_devname) {
                concurrency -= 1
        }
}

probe end {
        printf ("concurrency=%d\n", @max(max_concurrency))
}/<code>

運行2.4.2

1.測試順序寫

<code>1> staprun -v generic_file_write_iter_concurrency.ko 2>&1 | tee 19_systemtap_generic_file_write_iter_concurrency_seqrewr
2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>

2.測試隨機寫

<code>1> staprun -v generic_file_write_iter_concurrency.ko 2>&1 | tee 20_systemtap_generic_file_write_iter_concurrency_rndwr
2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>

結果2.4.2

用systemtap對sysbench IO測試結果的分析-愛可生

可以看到,鎖inode->i_mutex限制了__generic_file_write_iter的併發度。由常識得知,一個文件一般對應一個inode結構 (也可以通過systemtap打印inode地址來確認),也就是說:

  1. 順序寫的壓力集中在寫一個文件,因此在inode的鎖上產生了競爭
  2. 隨機寫的壓力比較分散, 因此__generic_file_write_iter的併發度高
  3. 順序寫的最大併發度為2,而不是1,可能是發生在已寫滿某一文件並要寫下一個文件的瞬間

之後,我們將調整sysbench併發數為1,來拉平順序寫和隨機寫的__generic_file_write_iter併發度,創造公平的測試環境。

步驟2.4.3

根據現象2的分析,本次的測試將調整sysbench併發數為1。此處也可以隨手驗證一下現象2中的generic_file_write_iter的併發度,在兩種情況下都相等,在此不詳述。

1.測試順序寫

<code>SYSBENCH_NUM_THREADS=1 SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run | tee 21_sysbench_1thread_seqrewr/<code>

2.測試隨機寫

<code>SYSBENCH_NUM_THREADS=1 SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run | tee 22_sysbench_1thread_rndwr/<code>

結果2.4.3

用systemtap對sysbench IO測試結果的分析-愛可生

可以看到,在相對公平的測試條件下,順序寫比隨機寫的性能更好一些。

現象3

在結果2.1中還遺留了一個問題:在研究延遲分佈時出現了兩個峰。在之前的試驗中,如果將一些函數的延遲分佈打印出來,也能觀察到兩個峰。這些函數並不集中在某一個邏輯路徑上,比較分散。因此可能是一個共有的機制導致第二個峰的出現,而不是某個邏輯分支導致。

另外可以嘗試用systemtap腳本進行分析,但幾經嘗試,第二個峰的出現並不規律。

偶爾想到這是否由於發生了OS的進程切換而導致的,有了想法就可以快速驗證一下。

systemtap腳本3

vfs_write_latency_and_context_switch.ko

<code>global input_devname="sdb"
global vfs_write_latency

global fire
probe vfs.write {
        if (bytes_to_write > 0 && input_devname == devname) {
                fire[tid()] = 1
        }
}

probe vfs.write.return {
        if (fire[tid()] == 1) {
                delete fire[tid()]
                vfs_write_latency < gettimeofday_ns() - @entry(gettimeofday_ns())
        }
}

global t_switchout, switch_latency
probe scheduler.ctxswitch {
        if (fire[prev_tid] == 1) {
                t_switchout[prev_tid] = gettimeofday_ns()
        }
        if (fire[next_tid] == 1) {
                switch_latency < gettimeofday_ns() - t_switchout[next_tid]
        }
}

probe end {
        printf ("vfs write latency:\n")
        print (@hist_log(vfs_write_latency))
        printf ("switch latency:\n")
        print (@hist_log(switch_latency))
}/<code>

運行3

<code>1> staprun -v vfs_write_latency_and_context_switch.ko 2>&1 | tee 23_systemtap_vfs_write_latency_and_context_switch
2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>

結果3

用systemtap對sysbench IO測試結果的分析-愛可生

可以看到:I/O延遲的第二峰值和OS進程切換相關。

覆盤

現在覆盤整個過程:

1.Direct模式的順序寫性能大於隨機寫,但非Direct模式的順序寫性能小於隨機寫

* 分析:查找fsync系統調用* 結果:調整sysbench參數--file-fsync-end=no2. 順序寫性能仍小於隨機寫* 分析2.1:是否有部分異常I/O延遲拖慢了平均值* 結果2.1:沒有進展。延遲存在兩個峰* 分析2.2:設備層的I/O請求特徵* 結果2.2:設備層的I/O請求特徵無異常,確定問題來自文件系統或IO調度* 分析2.3:文件系統的緩存命中率* 結果2.3:緩存命中率影響了性能,通過調大測試文件大小可降低命中率差異,順序寫性能大於隨機寫* 分析2.4:文件系統的緩存延遲分析* 結果2.4:Ext4的鎖inode->i_mutex的影響, 順序寫受到的影響高於隨機寫3. 對延遲分佈的第二個峰與OS進程切換有關

性能分析經驗

  1. 性能觀測工具的準確性需要校準,要懷疑其正確性
  2. 注意其他程序對觀測目標的影響
  3. systemtap 是強大的觀測工具, 其性能開銷低, 有許多現成的腳本供參考
  4. 有一些結論的得出,比如現象3,不是依靠於邏輯分析,而是猜測-驗證得來,這就要求對相關的技術有所瞭解
  5. 之所以現象3不通過邏輯分析,是因為沒有找到恰當的觀測手段和分析方法

IO測試經驗

IO測試時,如果要對兩個場景做性能對比,要關注一下幾個維度

  1. fsync的調用
  2. 文件系統的緩存命中率
  3. 文件系統的併發度
  4. OS上下文切換的頻度

這幾個維度偏差不大, 才能進行性能對比.

比較順序寫和隨機寫的性能,要確定比較目的,常識中”順序寫性能優於隨機寫”的結論,可能適用於設備I/O,但在文件系統上的某些場景下結論並不適用。


注意

所有的測試結果不能用於生產環境,因為測試時間較短,導致一些因素與生產環境不同,比如文件系統緩存是預熱狀態而並不飽和。得出的結論會有所偏頗,此次試驗只是展示一些分析方法。


用systemtap對sysbench IO測試結果的分析-愛可生


分享到:


相關文章: