System Monitoring and Performance Tuning

Linux システムモニタリングとパフォーマンスチューニング 包括ガイド

目次

  1. はじめに
  2. モニタリングツール概要
  3. /proc ファイルシステムによるモニタリング
  4. パフォーマンスメトリクス
  5. ストレステスト
  6. プロファイリング
  7. チューニング方法論
  8. CPU チューニング
  9. メモリチューニング
  10. ディスク I/O チューニング
  11. ネットワークチューニング
  12. モニタリングスタック概要
  13. トラブルシューティング
  14. ベストプラクティス
  15. 参考資料

1. はじめに

Linux システムの安定運用において、モニタリングとパフォーマンスチューニングは不可欠なスキルである。本記事では、基本的なモニタリングツールの使い方からカーネルパラメータの調整、さらにはエンタープライズレベルのモニタリングスタック構築まで、体系的に解説する。

パフォーマンスチューニングの基本原則は以下の通りである。

  1. 計測してから最適化する -- 推測に基づく最適化は逆効果になることが多い
  2. ボトルネックを特定する -- CPU、メモリ、ディスク I/O、ネットワークのいずれかが律速になっている
  3. 一度に一つの変更を行う -- 複数同時変更は効果の判断を困難にする
  4. ベースラインを確立する -- 正常時のメトリクスを把握しておく

2. モニタリングツール概要

モニタリングツール比較表

ツールカテゴリリアルタイム履歴CPUメモリディスクネットワーク
topプロセスYesNoYesYesNoNo
htopプロセスYesNoYesYesNoNo
vmstatシステム全体YesNoYesYesYesNo
iostatディスクYesNoYesNoYesNo
mpstatCPUYesNoYesNoNoNo
sar総合YesYesYesYesYesYes
pidstatプロセス別YesNoYesYesYesNo
freeメモリ瞬間値NoNoYesNoNo
uptime負荷瞬間値NoYesNoNoNo

2.1 top / htop

top の基本操作

# 基本起動
$ top

# バッチモードで出力(スクリプトに便利)
$ top -b -n 1

# 特定ユーザのプロセスのみ
$ top -u apache

# 特定PIDのみ監視
$ top -p 1234,5678

top 出力例:

top - 14:32:01 up 45 days,  3:21,  2 users,  load average: 1.52, 1.38, 1.25
Tasks: 287 total,   2 running, 284 sleeping,   0 stopped,   1 zombie
%Cpu(s): 12.5 us,  3.2 sy,  0.0 ni, 82.1 id,  1.8 wa,  0.0 hi,  0.4 si,  0.0 st
MiB Mem :  15921.4 total,   1234.5 free,   8456.2 used,   6230.7 buff/cache
MiB Swap:   8192.0 total,   7856.3 free,    335.7 used.   6789.1 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
   3421 mysql     20   0 2456.3m 1.2g  12340 S  15.2   7.8  234:56.78 mysqld
   8765 www-data  20   0  456.2m 234.5m  8901 S   8.3   1.5   45:12.34 apache2
   1234 root      20   0  123.4m  56.7m  3456 R   3.1   0.4   12:34.56 monitoring

top 出力の読み方:

フィールド説明
usユーザ空間のCPU使用率
syカーネル空間のCPU使用率
ninice値変更プロセスのCPU使用率
idアイドル率
waI/O待ち率(高いとディスクボトルネック)
hiハードウェア割り込み
siソフトウェア割り込み
st仮想マシンからスチールされた時間

htop のインストールと高度な機能

# インストール
$ sudo dnf install htop     # RHEL/CentOS/Fedora
$ sudo apt install htop     # Debian/Ubuntu

# ツリー表示で起動
$ htop -t

# 特定ユーザのプロセスのみ
$ htop -u apache

htop は top と比較して以下の利点がある。

  • カラフルなビジュアル表示(CPU/メモリバー)
  • マウス操作対応
  • プロセスツリー表示
  • 水平・垂直スクロール
  • GUI不要でプロセスのkill、reniceが可能

2.2 vmstat

# 2秒間隔で5回表示
$ vmstat 2 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0 335712 1264512 234560 6396148   0    1    12    45  456  890 12  3 83  2  0
 1  0 335712 1262340 234568 6396224   0    0     4    68  512  923 10  2 86  2  0
 3  1 335712 1258176 234576 6396312   0    0     8   124  678 1102 18  4 74  4  0
 1  0 335712 1260480 234584 6396380   0    0     0    52  445  867  8  2 89  1  0
 2  0 335712 1259648 234592 6396448   0    0    12    36  498  912 11  3 84  2  0

vmstat 各フィールドの解説:

カテゴリフィールド説明警告の目安
procsr実行待ちプロセス数CPU数以上で高負荷
procsbI/O待ちブロックプロセス数常時 > 0 でI/Oボトルネック
memoryswpd使用中スワップ量(KB)増加傾向に注意
memoryfree空きメモリ(KB)--
memorybuffバッファキャッシュ(KB)--
memorycacheページキャッシュ(KB)--
swapsiスワップイン(KB/s)> 0 でメモリ不足兆候
swapsoスワップアウト(KB/s)> 0 でメモリ不足兆候
iobiブロックデバイス読み込み(blocks/s)--
ioboブロックデバイス書き込み(blocks/s)--
systemin割り込み数/秒--
systemcsコンテキストスイッチ数/秒極端に高い値に注意

2.3 iostat

# パッケージインストール
$ sudo dnf install sysstat

# 拡張情報を2秒間隔で表示
$ iostat -xz 2
Linux 5.15.0 (server01)    04/10/2026     _x86_64_

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          12.45    0.00    3.21    1.82    0.00   82.52

Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz  aqu-sz  %util
sda              8.52    245.67     0.34   3.84    1.23    28.84   12.34    456.78     2.56  17.19    2.45    37.01    0.00      0.00     0.00   0.00    0.00     0.00    0.05   2.34
nvme0n1         45.67   2345.89     1.23   2.62    0.15   51.37   78.90   4567.12     5.67   6.70    0.23    57.89    0.00      0.00     0.00   0.00    0.00     0.00    0.02   5.67

重要な iostat メトリクス:

メトリクス説明注目ポイント
r/s, w/s秒間読み書きリクエスト数IOPS の指標
rkB/s, wkB/s秒間読み書きスループット帯域幅の指標
r_await, w_await平均レイテンシ(ms)SSD: < 1ms, HDD: < 10ms が目安
aqu-sz平均キュー長高いとデバイスが飽和
%utilデバイス使用率> 80% で飽和の可能性

2.4 mpstat

# 全CPU個別表示、2秒間隔
$ mpstat -P ALL 2
Linux 5.15.0 (server01)    04/10/2026     _x86_64_

02:32:01 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
02:32:03 PM  all   12.50    0.00    3.20    1.80    0.10    0.40    0.00    0.00    0.00   82.00
02:32:03 PM    0   25.00    0.00    5.00    0.50    0.50    1.00    0.00    0.00    0.00   68.00
02:32:03 PM    1   10.00    0.00    2.50    3.00    0.00    0.50    0.00    0.00    0.00   84.00
02:32:03 PM    2    8.50    0.00    3.00    1.50    0.00    0.00    0.00    0.00    0.00   87.00
02:32:03 PM    3   15.00    0.00    2.00    2.00    0.00    0.50    0.00    0.00    0.00   80.50

特定のCPUだけ異常に高い場合、IRQの偏りやプロセスのCPUアフィニティ設定を確認する。

2.5 sar

sar (System Activity Reporter) は履歴データを持つ唯一の標準ツールである。

# CPU使用率の履歴(当日)
$ sar -u

# メモリ使用率
$ sar -r

# ディスクI/O
$ sar -d

# ネットワーク統計
$ sar -n DEV

# 特定日のデータ(/var/log/sa/saDD形式)
$ sar -u -f /var/log/sa/sa09

# 時間範囲指定
$ sar -u -s 09:00:00 -e 17:00:00

sar データ収集の設定 (/etc/cron.d/sysstat):

# 10分間隔でデータ収集(デフォルト)
*/10 * * * * root /usr/lib64/sa/sa1 1 1

# 日次サマリ生成
53 23 * * * root /usr/lib64/sa/sa2 -A

sar データの保存期間設定 (/etc/sysconfig/sysstat):

# データ保存日数(デフォルト28日)
HISTORY=28

# 圧縮を有効にする
COMPRESSAFTER=10

# データディレクトリ
SA_DIR=/var/log/sa

2.6 pidstat

# プロセス別CPU使用率(2秒間隔)
$ pidstat -u 2
Linux 5.15.0 (server01)    04/10/2026     _x86_64_

02:35:01 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
02:35:03 PM  1000      3421   12.50    2.50    0.00    0.50   15.00     0  mysqld
02:35:03 PM    33      8765    6.00    2.00    0.00    0.00    8.00     1  apache2
02:35:03 PM     0      1234    2.50    0.50    0.00    0.00    3.00     2  monitoring

# プロセス別メモリ使用率
$ pidstat -r 2

# プロセス別ディスクI/O
$ pidstat -d 2

# 特定PIDの全メトリクス
$ pidstat -u -r -d -p 3421 2

# スレッド単位で表示
$ pidstat -t -p 3421 2

2.7 free / uptime

# メモリ表示(人間が読みやすい形式)
$ free -h
               total        used        free      shared  buff/cache   available
Mem:            15Gi       8.0Gi       1.2Gi       256Mi       6.1Gi       6.6Gi
Swap:          8.0Gi       327Mi       7.7Gi

# 10秒間隔で更新
$ free -h -s 10

# 合計行を表示
$ free -h -t

free 出力の解釈:

  • available が最も重要 -- 新しいプロセスが実際に使えるメモリ量
  • buff/cache はカーネルがファイルキャッシュとして使用しているが、必要に応じて解放される
  • availabletotal の 10% 未満なら注意が必要
# uptime / ロードアベレージ
$ uptime
 14:32:01 up 45 days,  3:21,  2 users,  load average: 1.52, 1.38, 1.25

ロードアベレージの解釈:

1分5分15分解釈
1.521.381.25徐々に増加傾向
目安------CPU数以下が正常(4コアなら4.0以下)
低下傾向0.801.202.50問題が解消に向かっている
急上昇8.002.001.00突発的な負荷増

3. /proc ファイルシステムによるモニタリング

/proc はカーネルが公開する仮想ファイルシステムであり、全てのモニタリングツールの情報源である。

主要なファイル

# CPU情報
$ cat /proc/cpuinfo | grep "model name" | head -1
model name      : Intel(R) Xeon(R) Gold 6248 CPU @ 2.50GHz

# CPU使用率の生データ
$ cat /proc/stat | head -2
cpu  1234567 890 345678 9012345 67890 1234 5678 0 0 0
cpu0 308641 222 86419 2253086 16972 308 1419 0 0 0

# メモリ情報
$ cat /proc/meminfo | head -10
MemTotal:       16303564 kB
MemFree:         1264512 kB
MemAvailable:    6953924 kB
Buffers:          234560 kB
Cached:          6161588 kB
SwapCached:        12340 kB
Active:          8456320 kB
Inactive:        5234680 kB
Active(anon):    6123456 kB
Inactive(anon):  1234567 kB

# ディスクI/O統計
$ cat /proc/diskstats | grep -E "sda |nvme0n1 "

# ネットワーク統計
$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  eth0: 12345678901 9876543    0    0    0     0          0    123456 9876543210 8765432    0    0    0     0       0          0

# 特定プロセスの情報(PID 3421)
$ cat /proc/3421/status | head -15
Name:   mysqld
Umask:  0077
State:  S (sleeping)
Tgid:   3421
Ngid:   0
Pid:    3421
PPid:   1
TracerPid:      0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
FDSize: 256
Groups: 1000
VmPeak:  2516124 kB
VmSize:  2516124 kB
VmRSS:   1258291 kB

# プロセスのファイルディスクリプタ数
$ ls /proc/3421/fd | wc -l
156

# プロセスのメモリマップ
$ cat /proc/3421/maps | head -5

# システム全体のファイルディスクリプタ使用状況
$ cat /proc/sys/fs/file-nr
4832    0       9223372036854775807
# (割当済み  空き  最大値)

/proc を使ったカスタムモニタリングスクリプト

#!/bin/bash
# /proc からCPU使用率を計算するスクリプト

get_cpu_usage() {
    local cpu_line1 cpu_line2
    local user1 nice1 system1 idle1 iowait1
    local user2 nice2 system2 idle2 iowait2

    cpu_line1=$(head -1 /proc/stat)
    sleep 1
    cpu_line2=$(head -1 /proc/stat)

    read -r _ user1 nice1 system1 idle1 iowait1 _ <<< "$cpu_line1"
    read -r _ user2 nice2 system2 idle2 iowait2 _ <<< "$cpu_line2"

    local total1=$((user1 + nice1 + system1 + idle1 + iowait1))
    local total2=$((user2 + nice2 + system2 + idle2 + iowait2))
    local total_diff=$((total2 - total1))
    local idle_diff=$((idle2 - idle1))

    if [ $total_diff -gt 0 ]; then
        local usage=$(( (total_diff - idle_diff) * 100 / total_diff ))
        echo "CPU Usage: ${usage}%"
    fi
}

get_cpu_usage

4. パフォーマンスメトリクス

4.1 CPU メトリクス

# CPU使用率の包括的確認
$ mpstat -P ALL 1 1

# コンテキストスイッチ数
$ vmstat 1 | awk 'NR>2{print "CS:", $12}'

# 実行キュー長
$ vmstat 1 | awk 'NR>2{print "Run Queue:", $1}'

# CPU別割り込み数
$ cat /proc/interrupts | head -5
            CPU0       CPU1       CPU2       CPU3
   0:         48          0          0          0  IR-IO-APIC   2-edge      timer
   1:          0          3          0          0  IR-IO-APIC   1-edge      i8042
   8:          0          0          1          0  IR-IO-APIC   8-edge      rtc0
   9:          0          0          0          3  IR-IO-APIC   9-fasteoi   acpi

4.2 メモリメトリクス

# 詳細なメモリ使用状況
$ cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapTotal|SwapFree|Dirty|Writeback|Slab"
MemTotal:       16303564 kB
MemFree:         1264512 kB
MemAvailable:    6953924 kB
Buffers:          234560 kB
Cached:          6161588 kB
SwapTotal:       8388608 kB
SwapFree:        8047452 kB
Dirty:              4520 kB
Writeback:             0 kB
Slab:             456780 kB

# ページフォルト確認
$ sar -B 1 3
02:40:01 PM  pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s pgsteal/s
02:40:02 PM     12.00    456.00   8901.00      0.00   5678.00      0.00      0.00      0.00

# NUMA メモリ統計
$ numastat
                           node0           node1
numa_hit              1234567890      1234567890
numa_miss                   1234            5678
numa_foreign                5678            1234
interleave_hit             12345           12345
local_node            1234567890      1234567890
other_node                  1234            5678

4.3 ディスク I/O メトリクス

# ディスクレイテンシ確認
$ iostat -xz 1
# r_await, w_await を確認

# I/Oスケジューラキューの状態
$ cat /sys/block/sda/queue/nr_requests
128

# ディスク使用率の推移
$ sar -d 1 5

# ファイルシステムの状態
$ df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/sda1      xfs        50G   35G   16G  69% /
/dev/nvme0n1p1 ext4      200G  120G   71G  63% /data
tmpfs          tmpfs     7.8G  256M  7.6G   4% /dev/shm

4.4 ネットワークメトリクス

# ネットワークインターフェース統計
$ sar -n DEV 1 3
02:45:01 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
02:45:02 PM      eth0   8901.00   7654.00   4567.89   3456.78      0.00      0.00      1.00      3.65

# TCP接続統計
$ ss -s
Total: 1234
TCP:   567 (estab 345, closed 89, orphaned 12, timewait 67)

Transport Total     IP        IPv6
RAW       2         1         1
UDP       23        15        8
TCP       478       312       166
INET      503       328       175
FRAG      0         0         0

# ネットワークエラー統計
$ netstat -s | grep -i error
    123 packets received with checksum errors
    0 packet receive errors
    45 send buffer errors

# TCPリトランスミッション
$ sar -n TCP,ETCP 1 3

5. ストレステスト

stress-ng

# インストール
$ sudo dnf install stress-ng

# CPU負荷テスト(4ワーカー、60秒間)
$ stress-ng --cpu 4 --timeout 60s --metrics-brief
stress-ng: info:  [12345] dispatching hogs: 4 cpu
stress-ng: info:  [12345] successful run completed in 60.01s
stress-ng: info:  [12345] stressor       bogo ops real time  usr time  sys time   bogo ops/s
stress-ng: info:  [12345] cpu              123456    60.00s   239.87s     0.13s     2057.60

# メモリ負荷テスト(2GB使用、4ワーカー)
$ stress-ng --vm 4 --vm-bytes 2G --timeout 60s --metrics-brief

# ディスクI/O負荷テスト
$ stress-ng --hdd 2 --hdd-bytes 1G --timeout 60s --metrics-brief

# 混合負荷テスト
$ stress-ng --cpu 2 --vm 2 --vm-bytes 1G --hdd 1 --timeout 120s

# 特定のCPUストレッサ(行列計算)
$ stress-ng --matrix 4 --timeout 30s

# ネットワーク負荷テスト
$ stress-ng --sock 4 --timeout 60s

ストレステスト中のモニタリング例:

# ターミナル1: ストレステスト実行
$ stress-ng --cpu 4 --vm 2 --vm-bytes 1G --timeout 120s

# ターミナル2: リアルタイム監視
$ vmstat 2

# ターミナル3: プロセス別確認
$ pidstat -u -r 2

6. プロファイリング

6.1 perf

perf はカーネル組み込みのプロファイリングツールで、ハードウェアパフォーマンスカウンタにアクセスできる。

# インストール
$ sudo dnf install perf

# システム全体のCPUプロファイリング(10秒間)
$ sudo perf stat -a sleep 10
 Performance counter stats for 'system wide':

         80,234.56 msec cpu-clock                 #    8.023 CPUs utilized
           234,567      context-switches          #   29.236 /sec
             5,678      cpu-migrations            #    0.708 /sec
           123,456      page-faults               #   15.389 /sec
    45,678,901,234      cycles                    #    5.694 GHz
    23,456,789,012      instructions              #    0.51  insn per cycle
     3,456,789,012      branches                  #  430.752 M/sec
        45,678,901      branch-misses             #    1.32% of all branches

      10.001234567 seconds time elapsed

# 特定コマンドのプロファイリング
$ sudo perf stat ./my_application
$ sudo perf stat -e cycles,instructions,cache-misses ./my_application

# CPU時間のサンプリング(フレームグラフ用)
$ sudo perf record -F 99 -a -g -- sleep 30
$ sudo perf report --stdio

# 関数別ホットスポット
$ sudo perf top -F 49

# 特定プロセスのプロファイリング
$ sudo perf record -F 99 -p 3421 -g -- sleep 30
$ sudo perf report

perf report 出力例:

# Overhead  Command  Shared Object       Symbol
# ........  .......  ..................  .............................
    15.23%  mysqld   mysqld              [.] row_search_mvcc
     8.45%  mysqld   libc-2.31.so        [.] __memmove_avx_unaligned
     6.78%  mysqld   mysqld              [.] buf_page_get_gen
     5.12%  mysqld   mysqld              [.] ha_innobase::index_read
     4.56%  mysqld   [kernel.kallsyms]   [k] copy_user_enhanced_fast_string

6.2 strace / ltrace

# システムコールのトレース
$ strace -c ls /tmp
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 25.23    0.000456          22        20           getdents64
 18.45    0.000334          16        20        10 openat
 12.78    0.000231          11        20           fstat
 10.56    0.000191           9        20           close
  8.34    0.000151          15        10           mmap
  6.12    0.000111          11        10           mprotect
  5.67    0.000103          10        10           read
  4.56    0.000082          82         1           execve
  3.45    0.000062          31         2           write
  2.34    0.000042          21         2           brk
  2.50    0.000045           9         5           rt_sigaction
------ ----------- ----------- --------- --------- ----------------
100.00    0.001808                   120        10 total

# 特定のシステムコールだけトレース
$ strace -e trace=open,read,write -p 3421

# タイムスタンプ付きで出力
$ strace -tt -p 3421

# ファイルI/Oに関するシステムコールのみ
$ strace -e trace=file -p 3421

# ネットワーク関連のシステムコールのみ
$ strace -e trace=network -p 3421

# ライブラリコールのトレース
$ ltrace -c ./my_application
% time     seconds  usecs/call     calls      function
------ ----------- ----------- --------- --------------------
 45.23    0.012345        1234        10 malloc
 25.67    0.007890         789        10 free
 15.45    0.004567         456        10 strlen
 13.65    0.003456         345        10 strcmp
------ ----------- ----------- --------- --------------------
100.00    0.028258                    40 total

7. チューニング方法論

USE メソッド (Utilization, Saturation, Errors)

Brendan Gregg が提唱する体系的なパフォーマンス分析手法。

リソース使用率 (U)飽和度 (S)エラー (E)
CPUmpstat -P ALLvmstat の r列perf stat
メモリfree -m, vmstatvmstat の si/so列`dmesg
ディスクI/Oiostat -xz の %utiliostat の aqu-sz/sys/devices/.../ioerr_cnt
ネットワークsar -n DEVss -ntp のRecv-Qnetstat -s のerrors

RED メソッド (Rate, Errors, Duration)

マイクロサービスに適した手法。

  • Rate (リクエスト率): 秒間処理リクエスト数
  • Errors (エラー率): 失敗したリクエストの割合
  • Duration (応答時間): リクエスト処理にかかる時間

チューニングの手順

1. ベースライン計測
   ↓
2. ワークロード特性の把握
   ↓
3. ボトルネックの特定(USE メソッド)
   ↓
4. 仮説の立案
   ↓
5. 変更の実施(一度に一つ)
   ↓
6. 効果の計測
   ↓
7. 結果の評価 → 不十分なら 3 に戻る
   ↓
8. 文書化

8. CPU チューニング

8.1 nice / renice

プロセスの優先度を制御する。nice値は -20(最高優先度)から 19(最低優先度)の範囲。

# nice値を指定してプロセス起動(低優先度でバックアップ)
$ nice -n 10 tar czf /backup/data.tar.gz /data

# 実行中プロセスの優先度変更
$ renice -n 5 -p 3421
3421 (process ID) old priority 0, new priority 5

# ユーザの全プロセスの優先度変更
$ renice -n 10 -u www-data

# 現在のnice値確認
$ ps -eo pid,ni,comm | head -10
    PID  NI COMMAND
      1   0 systemd
      2   0 kthreadd
   3421   0 mysqld
   8765   5 backup_script

8.2 taskset (CPU アフィニティ)

# プロセスのCPUアフィニティ確認
$ taskset -p 3421
pid 3421's current affinity mask: f
# f = 1111 (バイナリ) = CPU 0,1,2,3

# CPU 0,1 だけに制限して起動
$ taskset -c 0,1 ./my_application

# 実行中プロセスのアフィニティ変更
$ taskset -p -c 2,3 3421
pid 3421's current affinity list: 0-3
pid 3421's new affinity list: 2,3

# CPUマスクで指定(ビットマスク)
$ taskset -p 0x0c 3421   # CPU 2,3 (0b1100 = 0x0c)

CPU アフィニティの用途:

  • キャッシュ効率の向上(L1/L2キャッシュの有効活用)
  • NUMA環境でのローカルメモリアクセス最適化
  • リアルタイム処理用CPUの隔離
  • ネットワーク処理とアプリケーション処理のCPU分離

8.3 cgroups によるリソース制御

cgroups v2 (systemd 統合)

# cgroups v2 が有効か確認
$ mount | grep cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)

# systemd によるCPU制限
$ sudo systemctl set-property httpd.service CPUQuota=200%
# 200% = 2コア分

# systemd によるメモリ制限
$ sudo systemctl set-property httpd.service MemoryMax=2G

# スライス(グループ)の作成
$ sudo systemctl set-property user-1000.slice CPUQuota=400%
$ sudo systemctl set-property user-1000.slice MemoryMax=8G

drop-in ファイルで永続設定:

# /etc/systemd/system/httpd.service.d/resources.conf
[Service]
CPUQuota=200%
MemoryMax=2G
MemoryHigh=1800M
IOWeight=100

cgroups v2 手動設定

# cgroup 作成
$ sudo mkdir /sys/fs/cgroup/myapp

# CPU制限(100000 usec 中 50000 usec = 50%)
$ echo "50000 100000" | sudo tee /sys/fs/cgroup/myapp/cpu.max

# メモリ制限(1GB)
$ echo "1073741824" | sudo tee /sys/fs/cgroup/myapp/memory.max

# プロセスを cgroup に追加
$ echo 3421 | sudo tee /sys/fs/cgroup/myapp/cgroup.procs

# 現在のリソース使用状況確認
$ cat /sys/fs/cgroup/myapp/cpu.stat
usage_usec 1234567890
user_usec 987654321
system_usec 246913569
nr_periods 12345
nr_throttled 678
throttled_usec 901234

$ cat /sys/fs/cgroup/myapp/memory.current
536870912

9. メモリチューニング

9.1 swappiness

swappiness はカーネルがスワップを使用する積極性を制御するパラメータ。

# 現在の値確認
$ cat /proc/sys/vm/swappiness
60

# 一時的な変更
$ sudo sysctl vm.swappiness=10

# 永続的な変更
$ echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.d/99-tuning.conf
$ sudo sysctl -p /etc/sysctl.d/99-tuning.conf

swappiness 推奨値:

環境推奨値理由
データベースサーバ1-10メモリ内データへの高速アクセスが重要
Webサーバ10-30バランスの良い設定
デスクトップ60 (デフォルト)一般用途に適切
ファイルサーバ30-50キャッシュ活用とスワップのバランス

9.2 Huge Pages

通常のページサイズ(4KB)より大きなページ(2MB, 1GB)を使用することで、TLBミスを削減しパフォーマンスを向上させる。

# 現在の設定確認
$ cat /proc/meminfo | grep -i huge
AnonHugePages:    245760 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB

# Huge Pages の設定(1024 x 2MB = 2GB)
$ echo 1024 | sudo tee /proc/sys/vm/nr_hugepages

# 永続設定
$ cat >> /etc/sysctl.d/99-hugepages.conf << 'EOF'
vm.nr_hugepages = 1024
vm.hugetlb_shm_group = 1000
EOF

# Transparent Huge Pages (THP) の状態確認
$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never

# THP を無効にする(データベースワークロードで推奨)
$ echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
$ echo never | sudo tee /sys/kernel/mm/transparent_hugepage/defrag

THP 無効化の永続設定 (GRUB):

# /etc/default/grub
GRUB_CMDLINE_LINUX="... transparent_hugepage=never"

# GRUB設定更新
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg

9.3 OOM Killer

メモリ枯渇時にカーネルが自動的にプロセスを停止する機能。

# OOM スコアの確認
$ cat /proc/3421/oom_score
150

# OOM スコア調整(-1000 から 1000)
# -1000 = OOM Killer から完全に除外
#  1000 = 最優先で kill される
$ echo -1000 | sudo tee /proc/3421/oom_score_adj   # 保護
$ echo 500 | sudo tee /proc/8765/oom_score_adj      # 優先的にkill

# OOM Killer の動作ログ確認
$ dmesg | grep -i "oom\|out of memory"
[12345.678901] Out of memory: Killed process 9876 (java) total-vm:4567890kB, anon-rss:3456789kB

# systemd サービスでの OOM 設定
# /etc/systemd/system/critical-app.service
[Service]
OOMScoreAdjust=-900

メモリ関連の追加チューニング:

# vm.overcommit の設定
# 0: ヒューリスティック(デフォルト)
# 1: 常にオーバーコミット許可
# 2: オーバーコミット禁止
$ echo 2 | sudo tee /proc/sys/vm/overcommit_memory

# オーバーコミット比率(overcommit_memory=2の場合)
# 物理メモリの80% + スワップ
$ echo 80 | sudo tee /proc/sys/vm/overcommit_ratio

# ダーティページの制御
$ sysctl -w vm.dirty_ratio=15           # 全メモリの15%まで
$ sysctl -w vm.dirty_background_ratio=5 # バックグラウンド書き込み開始
$ sysctl -w vm.dirty_expire_centisecs=3000  # 30秒後に期限切れ

# ページキャッシュのドロップ(デバッグ用)
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
# 1=ページキャッシュ、2=dentryとinode、3=両方

10. ディスク I/O チューニング

10.1 I/O スケジューラ

# 現在のスケジューラ確認
$ cat /sys/block/sda/queue/scheduler
[mq-deadline] kyber bfq none

$ cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq

I/O スケジューラ比較:

スケジューラ特徴適したワークロード
none最小レイテンシ、順序変更なしNVMe SSD、仮想マシン
mq-deadlineデッドライン保証、リードに優先度DB、汎用SSD
bfq公平性重視、帯域配分デスクトップ、複数ユーザ
kyber低レイテンシ、シンプル高速SSD
# スケジューラの変更(一時的)
$ echo "mq-deadline" | sudo tee /sys/block/sda/queue/scheduler

# 永続設定(udevルール)
# /etc/udev/rules.d/60-io-scheduler.rules
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/scheduler}="mq-deadline"
ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"

# udevルール適用
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger

10.2 readahead

# 現在のreadahead値確認(単位: 512バイトセクター)
$ cat /sys/block/sda/queue/read_ahead_kb
128

# readahead を増やす(シーケンシャルリードが多い場合)
$ echo 1024 | sudo tee /sys/block/sda/queue/read_ahead_kb

# blockdev コマンドでも設定可能
$ sudo blockdev --getra /dev/sda
256
$ sudo blockdev --setra 2048 /dev/sda    # 1024KB (2048 * 512 bytes)

10.3 ionice

# I/O優先度クラス
# 1: リアルタイム (0-7, 0が最高)
# 2: ベストエフォート (0-7, 0が最高) [デフォルト]
# 3: アイドル

# バックアップをアイドル優先度で実行
$ ionice -c 3 tar czf /backup/data.tar.gz /data

# ベストエフォート・低優先度で実行
$ ionice -c 2 -n 7 dd if=/dev/sda of=/backup/disk.img bs=1M

# 実行中プロセスのI/O優先度確認
$ ionice -p 3421
best-effort: prio 4

# 実行中プロセスのI/O優先度変更
$ ionice -c 2 -n 0 -p 3421

ディスクI/O 追加チューニング:

# キューの深さ調整
$ echo 256 | sudo tee /sys/block/sda/queue/nr_requests

# ライトバックキャッシュの有効化確認
$ cat /sys/block/sda/queue/write_cache
write back

# ファイルシステムマウントオプション(/etc/fstab)
# noatime: アクセス時間を更新しない(読み取り性能向上)
# nobarrier: バリアを無効化(バッテリーバックアップRAID向け)
/dev/sda1  /data  xfs  defaults,noatime  0 2

# ext4 のジャーナルモード
# data=writeback: 最高速(データ整合性リスクあり)
# data=ordered: バランス(デフォルト)
# data=journal: 最安全(最も遅い)

11. ネットワークチューニング

TCP パラメータチューニング

# /etc/sysctl.d/99-network-tuning.conf

# --- TCP バッファサイズ ---
# 最小、デフォルト、最大(バイト)
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 262144
net.core.wmem_default = 262144

# --- TCP コネクション管理 ---
# SYNバックログキューサイズ
net.ipv4.tcp_max_syn_backlog = 8192

# リッスンバックログ
net.core.somaxconn = 65535

# TIME_WAIT ソケットの再利用
net.ipv4.tcp_tw_reuse = 1

# FIN-WAIT-2 タイムアウト(秒)
net.ipv4.tcp_fin_timeout = 15

# キープアライブ設定
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 5

# --- TCP パフォーマンス ---
# ウィンドウスケーリング
net.ipv4.tcp_window_scaling = 1

# TCP Fast Open
net.ipv4.tcp_fastopen = 3

# 輻輳制御アルゴリズム
net.ipv4.tcp_congestion_control = bbr

# BBR を有効にする前にモジュールロード
# $ sudo modprobe tcp_bbr
# $ echo "tcp_bbr" | sudo tee -a /etc/modules-load.d/bbr.conf

# --- ネットワークキュー ---
net.core.netdev_max_backlog = 5000
net.core.netdev_budget = 600

# --- ポート範囲 ---
net.ipv4.ip_local_port_range = 1024 65535
# 設定適用
$ sudo sysctl --system

# 現在のTCP輻輳制御アルゴリズム確認
$ sysctl net.ipv4.tcp_congestion_control
net.ipv4.tcp_congestion_control = bbr

# 利用可能な輻輳制御アルゴリズム一覧
$ sysctl net.ipv4.tcp_available_congestion_control
net.ipv4.tcp_available_congestion_control = reno cubic bbr

# ネットワーク接続状態の統計
$ ss -s

# 接続状態別カウント
$ ss -ant | awk '{print $1}' | sort | uniq -c | sort -rn
    345 ESTAB
     89 TIME-WAIT
     23 LISTEN
     12 CLOSE-WAIT
      5 SYN-SENT
      2 FIN-WAIT-2

NIC (ネットワークインターフェースカード) チューニング:

# 現在のNIC設定確認
$ ethtool eth0
Settings for eth0:
        Speed: 10000Mb/s
        Duplex: Full
        Auto-negotiation: on
        Link detected: yes

# リングバッファサイズ確認
$ ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums:
RX:     4096
TX:     4096
Current hardware settings:
RX:     256
TX:     256

# リングバッファサイズ増加
$ sudo ethtool -G eth0 rx 4096 tx 4096

# オフロード機能確認
$ ethtool -k eth0 | grep -E "tcp-segmentation|generic-receive"
tcp-segmentation-offload: on
generic-receive-offload: on

# 割り込みコアレッシング調整
$ sudo ethtool -C eth0 rx-usecs 100 tx-usecs 100

12. モニタリングスタック概要

12.1 Prometheus + Grafana

Prometheus 構成

# /etc/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  scrape_timeout: 10s

rule_files:
  - "alert_rules.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - "localhost:9093"

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

  - job_name: "node_exporter"
    static_configs:
      - targets:
          - "server01:9100"
          - "server02:9100"
          - "server03:9100"
    relabel_configs:
      - source_labels: [__address__]
        target_label: instance
        regex: '(.+):9100'
        replacement: '${1}'

  - job_name: "mysqld_exporter"
    static_configs:
      - targets: ["server01:9104"]

Node Exporter のインストール

# ダウンロードとインストール
$ wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
$ tar xzf node_exporter-1.7.0.linux-amd64.tar.gz
$ sudo cp node_exporter-1.7.0.linux-amd64/node_exporter /usr/local/bin/

# systemd サービス作成
$ sudo cat > /etc/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Node Exporter
After=network.target

[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter \
  --collector.systemd \
  --collector.processes \
  --collector.tcpstat \
  --web.listen-address=:9100

[Install]
WantedBy=multi-user.target
EOF

$ sudo systemctl daemon-reload
$ sudo systemctl enable --now node_exporter

アラートルール例

# /etc/prometheus/alert_rules.yml
groups:
  - name: system_alerts
    rules:
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High CPU usage on {{ $labels.instance }}"
          description: "CPU usage is above 80% for 5 minutes (current: {{ $value }}%)"

      - alert: HighMemoryUsage
        expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 90
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High memory usage on {{ $labels.instance }}"

      - alert: DiskSpaceRunningLow
        expr: (1 - node_filesystem_avail_bytes{fstype=~"ext4|xfs"} / node_filesystem_size_bytes) * 100 > 85
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Disk space low on {{ $labels.instance }}:{{ $labels.mountpoint }}"

      - alert: HighDiskIOLatency
        expr: rate(node_disk_read_time_seconds_total[5m]) / rate(node_disk_reads_completed_total[5m]) > 0.01
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High disk I/O latency on {{ $labels.instance }}"

Grafana ダッシュボード

# Grafana インストール (RHEL/CentOS)
$ sudo dnf install -y grafana
$ sudo systemctl enable --now grafana-server

# データソース追加 (API)
$ curl -X POST http://admin:admin@localhost:3000/api/datasources \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Prometheus",
    "type": "prometheus",
    "url": "http://localhost:9090",
    "access": "proxy",
    "isDefault": true
  }'

12.2 Nagios / Zabbix

Nagios 基本設定

# /etc/nagios/nagios.cfg(主要設定)
cfg_dir=/etc/nagios/conf.d

# ホスト定義
# /etc/nagios/conf.d/server01.cfg
define host {
    use             linux-server
    host_name       server01
    alias           Production Web Server 01
    address         192.168.1.101
    max_check_attempts  5
    check_period    24x7
    notification_interval   30
    notification_period     24x7
}

define service {
    use                 generic-service
    host_name           server01
    service_description CPU Load
    check_command       check_nrpe!check_load
    check_interval      5
    retry_interval      1
}

define service {
    use                 generic-service
    host_name           server01
    service_description Memory Usage
    check_command       check_nrpe!check_mem
    check_interval      5
    retry_interval      1
}

define service {
    use                 generic-service
    host_name           server01
    service_description Disk Usage
    check_command       check_nrpe!check_disk
    check_interval      10
    retry_interval      2
}

Zabbix 概要

# Zabbix エージェントインストール
$ sudo dnf install zabbix-agent2

# 設定
# /etc/zabbix/zabbix_agent2.conf
Server=192.168.1.10
ServerActive=192.168.1.10
Hostname=server01

モニタリングスタック比較:

特徴Prometheus + GrafanaNagiosZabbix
データモデル時系列 (Pull型)チェック結果時系列 (Push/Pull)
スケーラビリティ
可視化優秀 (Grafana)基本的良好
アラートAlertManager内蔵内蔵
設定方法YAMLテキスト設定Web GUI
クラウドネイティブ最適非対応部分対応
学習コスト
エコシステム豊富 (Exporter)プラグインテンプレート

13. トラブルシューティング

よくある問題と対処法

CPU使用率が高い場合

# 1. どのプロセスがCPUを消費しているか特定
$ top -o %CPU -b -n 1 | head -15

# 2. そのプロセスの詳細確認
$ pidstat -p <PID> -u 1 5

# 3. strace でシステムコールを確認
$ sudo strace -c -p <PID>

# 4. perf でホットスポットを特定
$ sudo perf top -p <PID>

# 5. 対処: nice値の調整、CPU制限、プロセスの最適化

メモリリークの調査

# 1. メモリ使用量の多いプロセスを特定
$ ps aux --sort=-%mem | head -10

# 2. プロセスのメモリ詳細
$ cat /proc/<PID>/status | grep -E "VmSize|VmRSS|VmSwap"
$ pmap -x <PID> | tail -5

# 3. メモリ使用量の推移を監視
$ pidstat -r -p <PID> 5

# 4. Slab メモリの確認
$ sudo slabtop -s c | head -15

# 5. OOM Killer のログ確認
$ journalctl -k | grep -i "oom\|out of memory"

ディスクI/O遅延の調査

# 1. I/O待ちが発生しているか確認
$ iostat -xz 1 | grep -v "^$"

# 2. I/Oを大量に発生させているプロセスを特定
$ sudo iotop -o

# 3. pidstat でプロセス別I/O確認
$ pidstat -d 1

# 4. 対処: ionice、スケジューラ変更、readahead調整

ネットワーク遅延の調査

# 1. ネットワーク統計確認
$ ss -s

# 2. パケットロス/リトランスミッション確認
$ netstat -s | grep -i "retransmit\|error\|drop"

# 3. TCP接続状態確認
$ ss -ant | awk '{print $1}' | sort | uniq -c | sort -rn

# 4. インターフェースエラー確認
$ ip -s link show eth0

# 5. 対処: バッファ調整、輻輳制御変更、NICチューニング

14. ベストプラクティス

モニタリング

  1. ベースラインを確立する -- 正常時のメトリクスを記録し、異常検知の基準とする
  2. アラートの閾値を段階的に設定する -- Warning と Critical を分ける
  3. ダッシュボードを階層化する -- 概要 → 詳細 → 個別リソースの順
  4. ログとメトリクスを関連付ける -- 問題発生時に素早く原因特定できるようにする
  5. モニタリング自体を監視する -- Prometheus が落ちていないか別の仕組みで検知

パフォーマンスチューニング

  1. 計測ファースト -- 「遅い気がする」ではなく数値で判断する
  2. 一度に一つの変更 -- 効果を正確に測定するため
  3. 変更を文書化する -- 何を、なぜ、どう変更したかを記録
  4. 本番前にテスト -- ステージング環境で効果と副作用を検証
  5. 定期的に見直す -- ワークロードの変化に合わせてチューニングを更新
  6. カーネルデフォルトを尊重する -- 理由なく変更しない。デフォルト値は多くの場合で最適

チューニング推奨値サマリ

# /etc/sysctl.d/99-performance-tuning.conf

# --- メモリ ---
vm.swappiness = 10
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500
vm.overcommit_memory = 0
vm.min_free_kbytes = 65536

# --- ネットワーク ---
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_congestion_control = bbr

# --- ファイルシステム ---
fs.file-max = 2097152
fs.inotify.max_user_watches = 524288

15. 参考資料


最終更新: 2026-04-10
対象OS: RHEL 8/9, Ubuntu 22.04/24.04, 及び systemd ベースの主要Linuxディストリビューション