iopingでI/Oレイテンシを測定してみる

はじめに

システムのパフォーマンス問題を調査する際、ディスクI/Oのレイテンシは重要な指標の一つである。
特に、データベースやファイルサーバーなど、ディスクアクセスが頻繁に発生するアプリケーションでは、I/Oレイテンシがボトルネックになることが多い。

今回は、iopingというツールを使ってディスクI/Oのレイテンシを測定してみる。
iopingpingコマンドのディスク版のようなツールで、シンプルで直感的にI/Oレイテンシを測定できる。

環境

Ubuntu 24.04.2 LTS
ioping 1.3

iopingとは

iopingは、ディスクI/Oのレイテンシを測定するためのツール。
pingコマンドがネットワークのレイテンシを測定するように、iopingはディスクアクセスのレイテンシを測定する。

測定できる指標について

指標説明
レイテンシ1回のI/O操作にかかる時間
IOPS1秒間に実行できるI/O操作数
スループット1秒間に転送できるデータ量

iopingのインストール

sudo apt update
sudo apt install ioping
ログ
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
  crack-common gyp libcares2 libdouble-conversion3 libgl1-amber-dri libglapi-mesa libjs-async libjs-events
  libjs-inherits libjs-is-typedarray libjs-prettify libjs-regenerate libjs-source-map libjs-sprintf-js
  libjs-typedarray-to-buffer libllvm17t64 liblttng-ust-common1t64 liblttng-ust-ctl5t64 liblttng-ust1t64
  libmd4c0 libnotify-bin libpcre2-16-0 libqt5core5t64 libqt5dbus5t64 libqt5gui5t64 libqt5network5t64
  libqt5qml5 libqt5qmlmodels5 libqt5quick5 libqt5svg5 libqt5waylandclient5 libqt5waylandcompositor5
  libqt5widgets5t64 libqt5x11extras5 libre2-10 libssl-dev libuv1-dev libxcb-damage0 libxcb-xinerama0
  libxcb-xinput0 mesa-utils-bin node-abbrev node-ampproject-remapping node-ansi-regex node-ansi-styles
  node-aproba node-are-we-there-yet node-arrify node-async node-async-each node-auto-bind
  node-babel-plugin-add-module-exports node-babel7-runtime node-balanced-match node-base64-js
  node-binary-extensions node-brace-expansion node-busboy node-camelcase node-caniuse-lite node-chownr
  node-chrome-trace-event node-ci-info node-cjs-module-lexer node-cli-boxes node-cli-cursor node-clone
  node-collection-visit node-color-convert node-color-name node-colors node-commander node-commondir
  node-concat-stream node-console-control-strings node-convert-source-map node-core-js node-core-js-pure
  node-core-util-is node-data-uri-to-buffer node-decompress-response node-deep-is node-defaults
  node-define-property node-delegates node-depd node-diff node-electron-to-chromium node-encoding
  node-end-of-stream node-err-code node-error-ex node-es-module-lexer node-escape-string-regexp
  node-eslint-utils node-eslint-visitor-keys node-esquery node-estraverse node-esutils node-events
  node-fancy-log node-fast-deep-equal node-fast-levenshtein node-fetch node-find-up node-flatted
  node-foreground-child node-fs-readdir-recursive node-fs-write-stream-atomic node-fs.realpath
  node-function-bind node-get-caller-file node-get-stream node-get-value node-glob node-globals node-got
  node-graceful-fs node-growl node-has-flag node-has-unicode node-has-value node-has-values
  node-hosted-git-info node-iconv-lite node-ieee754 node-iferr node-imurmurhash node-indent-string
  node-inflight node-inherits node-ini node-interpret node-ip node-ip-regex node-is-arrayish
  node-is-binary-path node-is-buffer node-is-descriptor node-is-extglob node-is-path-cwd node-is-plain-obj
  node-is-plain-object node-is-stream node-is-typedarray node-is-windows node-isarray node-isexe
  node-isobject node-js-tokens node-json-buffer node-json-parse-better-errors node-json-schema
  node-json-schema-traverse node-json-stable-stringify node-jsonify node-jsonparse node-kind-of node-levn
  node-loader-runner node-locate-path node-lodash-packages node-lowercase-keys node-lru-cache
  node-map-visit node-memfs node-merge-stream node-mimic-response node-minimatch node-minimist
  node-minipass node-mute-stream node-n3 node-negotiator node-npm-run-path node-object-inspect
  node-object-visit node-once node-optimist node-optionator node-osenv node-p-cancelable node-p-limit
  node-p-locate node-p-map node-pascalcase node-path-dirname node-path-exists node-path-is-absolute
  node-path-is-inside node-path-type node-pify node-pkg-dir node-postcss-value-parser node-prelude-ls
  node-process-nextick-args node-promise-inflight node-promise-retry node-promzard node-prr node-pump
  node-punycode node-quick-lru node-randombytes node-read node-readable-stream node-rechoir
  node-regenerator-runtime node-regenerator-transform node-regexpp node-regjsgen node-repeat-string
  node-require-directory node-require-from-string node-resolve node-resolve-cwd node-resolve-from
  node-restore-cursor node-resumer node-retry node-run-queue node-safe-buffer node-serialize-javascript
  node-set-blocking node-set-immediate-shim node-shebang-command node-shebang-regex node-shell-quote
  node-signal-exit node-slash node-slice-ansi node-source-list-map node-source-map node-spdx-correct
  node-spdx-exceptions node-spdx-expression-parse node-spdx-license-ids node-sprintf-js node-ssri
  node-stack-utils node-string-decoder node-strip-bom node-supports-color node-tapable node-terser
  node-text-table node-through node-time-stamp node-to-fast-properties node-tslib node-type-check
  node-typedarray node-typedarray-to-buffer node-undici node-unicode-canonical-property-names-ecmascript
  node-unicode-match-property-value-ecmascript node-unicode-property-aliases-ecmascript node-unset-value
  node-uri-js node-util-deprecate node-uuid node-v8flags node-validate-npm-package-license node-wcwidth.js
  node-webpack-sources node-wordwrap node-wrappy node-write-file-atomic node-xtend node-y18n node-yallist
  node-yaml nodejs-doc qt5-gtk-platformtheme qttranslations5-l10n qtwayland5 xbitmaps
Use 'sudo apt autoremove' to remove them.
The following NEW packages will be installed:
  ioping
0 upgraded, 1 newly installed, 0 to remove and 78 not upgraded.
Need to get 18.2 kB of archives.
After this operation, 54.3 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble/universe amd64 ioping amd64 1.3-1 [18.2 kB]
Fetched 18.2 kB in 1s (31.1 kB/s)
Selecting previously unselected package ioping.
(Reading database ... 114617 files and directories currently installed.)
Preparing to unpack .../ioping_1.3-1_amd64.deb ...
Unpacking ioping (1.3-1) ...
Setting up ioping (1.3-1) ...
Processing triggers for man-db (2.12.0-4build2) ...

インストール確認

# バージョン確認
ioping --version

# ヘルプ表示
ioping --help

主要オプション一覧

I/O動作オプション

オプション説明
-A, --async非同期I/Oを使用
-C, --cachedキャッシュI/Oを使用(フラッシュなし)
-D, --directダイレクトI/O使用(O_DIRECT)
-G, --read-write読み書きピンポンモード
-L, --linearシーケンシャル操作を使用
-N, --nowaitnowait I/O使用(RWF_NOWAIT)
-H, --hipri高優先度I/O使用(RWF_HIPRI)
-W, --write書き込みI/Oを使用
-Y, --sync同期I/O使用(O_SYNC)
-y, --dsyncデータ同期I/O使用(O_DSYNC)
-R, --rapid3秒間の高速I/Oテスト(-q -i 0 -w 3)
-k, --keep一時ファイル保持・再利用

パラメータオプション

オプション説明
-a, --warmup <count>最初の<count>回のリクエストを無視
-b, --burst <count>遅延なしで<count>回のリクエスト実行
-c, --count <count><count>回のリクエスト後に停止
-e, --entropy <seed>乱数生成器のシード値
-i, --interval <time>リクエスト間隔(デフォルト1s)
-s, --size <size>リクエストサイズ(デフォルト4k)
-S, --work-size <size>作業セットサイズ(デフォルト1m)
-o, --work-offset <size>作業セットオフセット(デフォルト0)
-w, --work-time <time>指定時間経過後に停止
-l, --speed-limit <size>1秒あたりの速度制限
-r, --rate-limit <count>1秒あたりのレート制限
-t, --min-time <time>最小有効リクエスト時間
-T, --max-time <time>最大有効リクエスト時間

出力オプション

オプション説明
-B, --batch最終統計を生フォーマットで出力
-I, --time [format]各リクエストの現在時刻を出力
-J, --jsonJSON形式で出力
-p, --print-count <count><count>リクエストごとに統計出力
-P, --print-interval <time><time>間隔で統計出力
-q, --quiet人間可読な出力を抑制
-h, --helpヘルプメッセージを表示して終了
-v, --versionバージョンを表示して終了

基本的な使い方

シンプルな測定

# 現在のディレクトリでI/Oレイテンシを測定
ioping .
# 出力例
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=1 time=173.5 us (warmup)
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=2 time=304.3 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=3 time=252.2 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=4 time=261.5 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=5 time=185.3 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=6 time=182.7 us
^C
--- . (ext4 /dev/sdc 1006.9 GiB) ioping statistics ---
5 requests completed in 1.19 ms, 20 KiB read, 4.22 k iops, 16.5 MiB/s
generated 6 requests in 5.84 s, 24 KiB, 1 iops, 4.11 KiB/s
min/avg/max/mdev = 182.7 us / 237.2 us / 304.3 us / 46.9 us

指定回数の測定

# 10回測定して終了
ioping -c 10 .
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=1 time=168.2 us (warmup)
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=2 time=294.8 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=3 time=289.7 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=4 time=281.5 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=5 time=259.6 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=6 time=290.4 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=7 time=2.68 ms (slow)
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=8 time=284.8 us (fast)
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=9 time=263.6 us (fast)
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=10 time=264.2 us (fast)

--- . (ext4 /dev/sdc 1006.9 GiB) ioping statistics ---
9 requests completed in 4.91 ms, 36 KiB read, 1.83 k iops, 7.16 MiB/s
generated 10 requests in 9.00 s, 40 KiB, 1 iops, 4.44 KiB/s
min/avg/max/mdev = 259.6 us / 545.8 us / 2.68 ms / 755.9 us

詳細な測定オプション

ブロックサイズの指定

# 1MBでテスト
ioping -s 1M -c 5 .
1 MiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=1 time=696.4 us (warmup)
1 MiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=2 time=733.1 us
1 MiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=3 time=769.4 us
1 MiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=4 time=772.4 us
1 MiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=5 time=767.2 us

--- . (ext4 /dev/sdc 1006.9 GiB) ioping statistics ---
4 requests completed in 3.04 ms, 4 MiB read, 1.31 k iops, 1.28 GiB/s
generated 5 requests in 4.00 s, 5 MiB, 1 iops, 1.25 MiB/s
min/avg/max/mdev = 733.1 us / 760.5 us / 772.4 us / 16.0 us

間隔の指定

# 0.5秒間隔で測定
ioping -i 0.5 -c 5 .
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=1 time=163.7 us (warmup)
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=2 time=278.9 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=3 time=224.2 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=4 time=296.8 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=5 time=255.5 us

--- . (ext4 /dev/sdc 1006.9 GiB) ioping statistics ---
4 requests completed in 1.06 ms, 16 KiB read, 3.79 k iops, 14.8 MiB/s
generated 5 requests in 2.01 s, 20 KiB, 2 iops, 9.97 KiB/s
min/avg/max/mdev = 224.2 us / 263.8 us / 296.8 us / 27.2 us

時間指定での測定

# 10秒間測定
ioping -w 10 .

# 統計のみ表示(-q quiet モード)
ioping -q -w 10 .
--- . (ext4 /dev/sdc 1006.9 GiB) ioping statistics ---
9 requests completed in 2.53 ms, 36 KiB read, 3.56 k iops, 13.9 MiB/s
generated 10 requests in 9.02 s, 40 KiB, 1 iops, 4.43 KiB/s
min/avg/max/mdev = 239.3 us / 280.7 us / 343.6 us / 30.5 us

シーケンシャルアクセス測定

# シーケンシャルアクセスのテスト
ioping -R -s 1M -c 10 .
--- . (ext4 /dev/sdc 1006.9 GiB) ioping statistics ---
9 requests completed in 5.46 ms, 9 MiB read, 1.65 k iops, 1.61 GiB/s
generated 10 requests in 7.19 ms, 10 MiB, 1.39 k iops, 1.36 GiB/s
min/avg/max/mdev = 517.2 us / 606.9 us / 729.9 us / 69.3 us

ランダムアクセスでの負荷テスト

# ランダムアクセス、高負荷テスト
ioping -D -s 4k -w 30 .
# 出力例
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=1 time=225.8 us (warmup)
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=2 time=262.2 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=3 time=300.1 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=4 time=279.2 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=5 time=272.8 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=6 time=305.1 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=7 time=224.9 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=8 time=286.8 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=9 time=276.7 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=10 time=306.1 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=11 time=295.5 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=12 time=292.3 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=13 time=312.7 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=14 time=278.6 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=15 time=305.5 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=16 time=295.3 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=17 time=290.4 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=18 time=294.4 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=19 time=313.6 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=20 time=299.0 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=21 time=281.4 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=22 time=266.7 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=23 time=294.0 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=24 time=319.2 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=25 time=309.6 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=26 time=304.9 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=27 time=308.7 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=28 time=343.9 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=29 time=293.6 us
4 KiB <<< . (ext4 /dev/sdc 1006.9 GiB): request=30 time=289.2 us

--- . (ext4 /dev/sdc 1006.9 GiB) ioping statistics ---
29 requests completed in 8.50 ms, 116 KiB read, 3.41 k iops, 13.3 MiB/s
generated 30 requests in 29.0 s, 120 KiB, 1 iops, 4.13 KiB/s
min/avg/max/mdev = 224.9 us / 293.2 us / 343.9 us / 21.1 us

測定シナリオについて考える

データベースワークロード想定

データベースサーバーでは、小さなランダムアクセスが頻繁に発生する。
iopingでデータベースディレクトリを対象に測定することで、実際のワークロードに近い条件でI/Oレイテンシを評価できる。

# 小さなランダムアクセス(データベース的)
ioping -R -s 8k -w 60 /var/lib/mysql/
8 KiB <<< /var/lib/mysql (ext4 /dev/sda1): request=1 time=125.4 us, random (warmup)
8 KiB <<< /var/lib/mysql (ext4 /dev/sda1): request=2 time=89.7 us, random
8 KiB <<< /var/lib/mysql (ext4 /dev/sda1): request=3 time=95.3 us, random
...
--- /var/lib/mysql (ext4 /dev/sda1) ioping statistics ---
642 requests completed in 60.2 ms, 5.0 MiB read, 10.7 k iops, 85.3 MiB/s
generated 642 requests in 60.0 s, 5.0 MiB, 11 iops, 85.3 KiB/s
min/avg/max/mdev = 78.2 us / 93.8 us / 156.7 us / 8.9 us

データベース測定のオプションについて

  • ブロックサイズ: 8KiBはMySQL InnoDBの標準ページサイズ
  • ランダムアクセス: -Rオプションでランダム読み取り
  • 測定時間: 60秒程度で安定した統計を取得
  • 対象ディレクトリ: 実際のデータファイルが配置されているパス

ログファイル書き込み想定

# シーケンシャル書き込み(ログファイル的)
ioping -W -s 64k -w 30 /var/log/

# 出力例
64 KiB >>> /var/log (ext4 /dev/sda1): request=1 time=245.6 us, sequential write (warmup)
64 KiB >>> /var/log (ext4 /dev/sda1): request=2 time=189.3 us, sequential write
64 KiB >>> /var/log (ext4 /dev/sda1): request=3 time=201.7 us, sequential write

他のツールとの比較

iostat との比較

# iostat(システム全体のI/O統計)
iostat -x 1 5

# ioping(特定パスのレイテンシ)
ioping -w 5 .

fio との比較

# fio(高機能ベンチマーク)
fio --name=random-read --rw=randread --bs=4k --runtime=30 --filename=./testfile

# ioping(シンプルなレイテンシ測定)
ioping -c 30 .
ツール用途特徴
iopingレイテンシ測定シンプル、リアルタイム
iostatシステム全体のI/O統計OS標準、継続監視
fio詳細なベンチマーク高機能、複雑な設定
ddシンプルなスループット測定標準コマンド、基本的

参考

おわりに

今回は、iopingを使ったI/Oレイテンシの測定について学んだ。

特に、データベースサーバーやファイルサーバーでパフォーマンス問題が発生した際、iopingで素早くI/Oレイテンシを確認することで、ストレージがボトルネックかどうかを判断できる。

他のツールとも比較しつつ、iopingも使ってみようかな。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。