Skip to content
Published on

Linux パフォーマンスエンジニアリング完全ガイド 2025:プロファイリング、システムチューニング、eBPF、ボトルネック分析

Authors

目次

1. なぜLinuxパフォーマンスエンジニアリングなのか

プロダクション環境(かんきょう)で発生する障害(しょうがい)の相当数(そうとうすう)はパフォーマンス問題に起因(きいん)します。CPU使用率(しようりつ)の急上昇(きゅうじょうしょう)、メモリリーク、ディスクI/Oボトルネック、ネットワーク遅延(ちえん)--これらすべてを体系的(たいけいてき)に分析(ぶんせき)し解決(かいけつ)できる能力がLinuxパフォーマンスエンジニアリングです。

このガイドで扱う主要トピック:

  • パフォーマンス分析方法論(USE、RED、TSA)
  • CPU分析(perf、mpstat、pidstat、Flame Graph)
  • メモリ分析(vmstat、/proc/meminfo、slab、OOM Killer)
  • ディスクI/O(iostat、blktrace、I/Oスケジューラ、fio)
  • ネットワーク性能(sar、ss、iperf3、TCPチューニング)
  • eBPF徹底解説(アーキテクチャ、BCC、bpftrace、libbpf CO-RE)
  • Flame Graph(CPU、off-CPU、メモリ、I/O)
  • sysctlチューニングとcgroups v2
  • NUMA、Huge Pages、プロセススケジューリング
  • プロダクションチューニングチェックリスト(20以上の項目)

2. パフォーマンス分析方法論

2.1 USE方法論(Utilization, Saturation, Errors)

Brendan Greggが提唱(ていしょう)した体系的パフォーマンス分析フレームワークです。

すべてのリソースに対して3つを確認:

+-------------------+--------------------------------------------+
| リソース            | U (利用率)    | S (飽和度)    | E (エラー)  |
+-------------------+-------------+--------------+-------------+
| CPU               | mpstat      | runq latency | perf/dmesg  |
| メモリ             | free        | vmstat si/so | dmesg OOM   |
| ネットワークIF     | sar -n DEV  | ifconfig     | ifconfig    |
|                   |             | (オーバーラン) | (エラー)     |
| ストレージI/O      | iostat      | iostat avgqu | iostat(エラー)|
| ストレージ容量      | df -h       | (なし)       | stale mounts|
| ファイルディスクリプタ| lsof        | (なし)       | "Too many   |
|                   |             |              |  open files"|
+-------------------+-------------+--------------+-------------+

2.2 RED方法論(Rate, Errors, Duration)

マイクロサービスに適した方法論です。

サービス観点で3つを測定:

Rate:     秒あたりリクエスト数 (requests/sec)
Errors:   失敗リクエスト比率 (error rate)
Duration: リクエスト処理時間分布 (latency P50/P95/P99)

2.3 TSA方法論(Thread State Analysis)

スレッド状態分類:

On-CPU:      実行中(CPUを使用している)
Runnable:    実行待機(CPUを待っている)
Sleeping:    I/O待機、タイマー、ロック待機など
Idle:        やることがない

分析ツール:
- perf record + Flame Graph(On-CPU分析)
- offcputime(Off-CPU分析)
- bpftrace(詳細スレッド分析)

3. Linuxパフォーマンスツール概要

3.1 Brendan GreggのLinuxパフォーマンスツールマップ

                        Applications
                     /      |      \
                   /        |        \
             System Libs  Runtime   Compiler
                  |         |          |
                  v         v          v
            +-----------------------------------------+
            |          System Call Interface           |
            +-----------------------------------------+
            |    VFS    | Sockets | Scheduler | VM    |
            +-----------+---------+-----------+-------+
            | File Sys  | TCP/UDP | (sched)   | (mm)  |
            +-----------+---------+-----------+-------+
            | Volume Mgr| IP      |           |       |
            +-----------+---------+-----------+-------+
            | Block Dev | Ethernet|           |       |
            +-----------+---------+-----------+-------+
            |  Device Drivers                         |
            +-----------------------------------------+

観測ツール:
  App:    strace, ltrace, gdb
  Sched:  perf, mpstat, pidstat, runqlat
  Memory: vmstat, slabtop, free, sar
  FS:     opensnoop, ext4slower, fileslower
  Disk:   iostat, biolatency, biotop
  Net:    sar, ss, tcpdump, nicstat
  All:    eBPF (bpftrace, BCC tools)

4. CPU分析

4.1 perf stat(ハードウェアカウンター)

# プロセスのCPUカウンター測定
perf stat -p PID sleep 10

# 出力例:
#  Performance counter stats for process id '12345':
#
#       10,234.56 msec task-clock           # 1.023 CPUs utilized
#           2,345      context-switches     # 229.12 /sec
#              12      cpu-migrations       # 1.17 /sec
#          45,678      page-faults          # 4.46K /sec
#  12,345,678,901      cycles               # 1.206 GHz
#   9,876,543,210      instructions         # 0.80 insn/cycle
#   1,234,567,890      branches             # 120.63M /sec
#      12,345,678      branch-misses        # 1.00% of all branches

# IPC (Instructions Per Cycle) が核心指標
# IPC < 1.0: メモリバウンドの可能性
# IPC > 1.0: コンピュートバウンド

4.2 perf record + perf report

# CPUプロファイル記録(30秒)
perf record -g -p PID sleep 30

# またはシステム全体
perf record -g -a sleep 30

# プロファイル分析
perf report --stdio

# 出力例:
# Overhead  Command  Shared Object      Symbol
#   23.45%  nginx    libc.so.6          [.] __memcpy_avx2
#   15.67%  nginx    nginx              [.] ngx_http_parse_request_line
#   12.34%  nginx    [kernel.vmlinux]   [k] copy_user_enhanced_fast_string
#    8.90%  nginx    libssl.so.3        [.] EVP_EncryptUpdate

4.3 Flame Graph生成

# 1. perfデータ収集
perf record -F 99 -g -a sleep 30

# 2. Flame Graph生成
perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > cpu.svg

# またはワンライナー:
perf record -F 99 -g -a -- sleep 30 && \
perf script | \
  stackcollapse-perf.pl | \
  flamegraph.pl > flamegraph.svg

Flame Graphの読み方:

+-----------------------------------------------------------+
|                    main()                                  |
+-------------------+---------------------------------------+
|  process_request()|            handle_connection()         |
+--------+----------+------------------+--------------------+
| parse()|  route() |  read_file()     |  send_response()   |
+--------+----+-----+------+-----------+----------+---------+
         |sort|      |read()|          |write()   |encrypt()|
         +----+      +------+          +----------+---------+

- X: CPU時間の割合(左→右の順序は無意味)
- Y: 呼び出しスタックの深さ(下→上が呼び出し方向)
-: その関数が占めるCPU時間
- 広い「プラトー」を見つけたら最適化対象!

4.4 mpstat, pidstat

# CPU別使用率
mpstat -P ALL 1

# 出力例:
# CPU  %usr  %nice  %sys  %iowait  %irq  %soft  %steal  %idle
# all  25.3   0.0   5.2     2.1    0.0    0.5     0.0   66.9
#   0  45.6   0.0   8.3     0.0    0.0    1.2     0.0   44.9  <- ホットCPU
#   1  12.3   0.0   3.1     4.2    0.0    0.1     0.0   80.3
#   2  35.7   0.0   6.8     0.0    0.0    0.8     0.0   56.7
#   3   7.5   0.0   2.5     4.1    0.0    0.0     0.0   85.9

# プロセス別CPU使用率
pidstat -p ALL 1

# スレッド別CPU使用率
pidstat -t -p PID 1

5. メモリ分析

5.1 vmstat

# 1秒間隔でメモリ/CPU統計
vmstat 1

# 出力の解釈:
# procs  --------memory--------  ---swap--  -----io----  -system-- ------cpu-----
#  r  b  swpd    free   buff  cache  si   so    bi    bo   in    cs  us sy id wa
#  2  0     0  524288  65536 2097152  0    0     4    12  156   312  15  5 78  2
#  5  1     0  491520  65536 2097152  0    0     0   256  892  1543  45 12 38  5

# 核心指標:
# r: 実行キュー待機プロセス(r > CPU数なら飽和)
# b: 割り込み不可能スリープ(通常I/O待機)
# si/so: スワップイン/アウト(0でなければメモリ不足)
# wa: I/O待機(高ければディスクボトルネック)

5.2 /proc/meminfo 詳細

cat /proc/meminfo

# 核心項目:
# MemTotal:       16384000 kB   全物理メモリ
# MemFree:         1024000 kB   完全未使用メモリ
# MemAvailable:    8192000 kB   実際に使用可能なメモリ(キャッシュ回収含む)
# Buffers:          524288 kB   ブロックデバイスI/Oバッファ
# Cached:          6553600 kB   ページキャッシュ
# SwapCached:            0 kB   スワップから再読み込みされたキャッシュ
# Active:          4096000 kB   最近アクセスされたメモリ
# Inactive:        3072000 kB   古いメモリ(回収候補)
# Slab:             512000 kB   カーネルデータ構造キャッシュ
# SReclaimable:     384000 kB   回収可能なスラブ
# SUnreclaim:       128000 kB   回収不可能なスラブ

5.3 ページキャッシュとOOM Killer

# ページキャッシュ状態
free -h
#               total   used   free   shared  buff/cache  available
# Mem:           16G    4.2G   1.0G    256M      10.8G      11.2G
# Swap:           4G      0B    4G

# キャッシュクリア(プロダクションでは注意)
# echo 1 > /proc/sys/vm/drop_caches  # ページキャッシュのみ
# echo 2 > /proc/sys/vm/drop_caches  # dentries + inodes
# echo 3 > /proc/sys/vm/drop_caches  # すべて

# OOM Killerログ確認
dmesg | grep -i "oom\|out of memory\|killed process"

# プロセス別OOMスコア確認
cat /proc/PID/oom_score

# OOMスコア調整(-1000〜1000)
echo -500 > /proc/PID/oom_score_adj  # OOMから保護
echo 1000 > /proc/PID/oom_score_adj  # OOM優先対象

5.4 slabtop

# カーネルスラブキャッシュ監視
slabtop -s c  # キャッシュサイズ順ソート

# 出力例:
#  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME
# 65536  62000  94%    0.19K   3277       20     13108K dentry
# 32768  30000  91%    0.50K   4096        8     16384K inode_cache
# 16384  15000  91%    1.00K   4096        4     16384K ext4_inode_cache

6. ディスクI/O分析

6.1 iostat

# ディスクI/O統計(拡張モード、1秒間隔)
iostat -xz 1

# 出力の解釈:
# Device  r/s    w/s    rkB/s  wkB/s  rrqm/s  wrqm/s  await r_await w_await  svctm  %util
# sda    150.0  200.0  6000   8000    10.0    50.0    2.50   1.80    3.00    0.85   29.8
# nvme0  500.0  800.0 50000  80000     0.0     0.0    0.25   0.20    0.28    0.08   10.4

# 核心指標:
# await: 平均I/O待機時間 (ms) - 高い=ディスクボトルネック
# %util: デバイス利用率 - 100%に近い=飽和
# r_await, w_await: 読み書き別待機時間
# rrqm/wrqm: マージされたリクエスト数(高い=シーケンシャルI/O)

6.2 I/Oスケジューラ

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

# スケジューラ変更
echo "bfq" > /sys/block/sda/queue/scheduler
I/Oスケジューラ比較:

+-------------+----------------+-----------------------------------+
| スケジューラ  | 適した環境      | 特徴                               |
+-------------+----------------+-----------------------------------+
| none        | NVMe SSD       | スケジューリングなし(HWに委任)     |
| mq-deadline | SSD/HDD汎用   | リクエスト期限保証、DBに適合         |
| bfq         | デスクトップ    | I/O公平性、対話型ワークロードに適合  |
| kyber       | 高性能SSD     | 低遅延目標、読み書きキュー分離       |
+-------------+----------------+-----------------------------------+

6.3 fioベンチマーキング

# シーケンシャル読み取りベンチマーク
fio --name=seqread --rw=read --bs=1M --size=4G \
    --numjobs=1 --runtime=60 --direct=1

# ランダム読み取り(IOPS測定)
fio --name=randread --rw=randread --bs=4k --size=4G \
    --numjobs=8 --runtime=60 --direct=1 --iodepth=32

# 混合ワークロード(DBシミュレーション)
fio --name=mixed --rw=randrw --rwmixread=70 \
    --bs=8k --size=4G --numjobs=4 --runtime=60 \
    --direct=1 --iodepth=16

# 結果の解釈:
# read:  IOPS=125000, BW=488MiB/s, lat avg=0.25ms, p99=0.50ms
# write: IOPS=53571, BW=209MiB/s, lat avg=0.45ms, p99=1.20ms

7. ネットワーク性能分析

7.1 sar

# ネットワークインターフェース統計
sar -n DEV 1

# TCP統計
sar -n TCP 1

# 出力例:
# IFACE   rxpck/s  txpck/s  rxkB/s  txkB/s  rxcmp/s txcmp/s rxmcst/s %ifutil
# eth0    15000    12000    8500    6200      0.0     0.0     5.0     6.8

# TCPエラー統計
sar -n ETCP 1

7.2 ssとTCPチューニング

# TCP接続状態サマリー
ss -s

# 受信キュー/送信キュー確認(ボトルネック診断)
ss -tnp | awk '{print $2, $3, $5}'

# 輻輳制御とRTT情報
ss -ti

# TCPメモリ使用状況
ss -tm

7.3 iperf3ベンチマーキング

# サーバー側
iperf3 -s

# クライアント側(TCP帯域幅測定)
iperf3 -c SERVER_IP -t 30 -P 4

# UDP帯域幅測定
iperf3 -c SERVER_IP -u -b 10G -t 30

# 双方向テスト
iperf3 -c SERVER_IP -t 30 --bidir

# MTU最適化(ジャンボフレーム)
# 標準: 1500バイト
# ジャンボ: 9000バイト(データセンター内部)
ip link set eth0 mtu 9000

8. eBPF徹底解説

8.1 eBPFアーキテクチャ

User Space                    Kernel Space
+--------------------+        +---------------------------+
|                    |        |                           |
| BCC / bpftrace /   | load   |      eBPF Virtual Machine |
| libbpf プログラム   |------->|      (JIT compiled)       |
|                    |        |                           |
| Maps (データ共有)   |<------>|  Hooks:                   |
|                    |  read/ |  - kprobes (関数エントリ)  |
| 結果出力            |  write |  - tracepoints (静的追跡) |
| (stdout, perf      |        |  - XDP (ネットワーク)     |
|  buffer, ringbuf)  |        |  - LSM (セキュリティ)     |
+--------------------+        |  - cgroup (リソース制御)    |
                              +---------------------------+

eBPF検証器 (Verifier):
- 無限ループ防止
- 範囲外メモリアクセス防止
- カーネル安定性保証

8.2 BCCツール

# === CPU関連 ===
# 新プロセス実行追跡
execsnoop

# 実行キュー待機時間ヒストグラム
runqlat       # CPUスケジューラ遅延分析

# === メモリ関連 ===
# ページフォルト追跡
drsnoop       # ダイレクトリクレイム追跡

# メモリ割り当て追跡
memleak       # メモリリーク検出

# === ディスクI/O ===
# ブロックI/Oレイテンシヒストグラム
biolatency    # I/O待機時間分布

# ブロックI/O上位プロセス
biotop        # I/Oが多いプロセスをリアルタイム確認

# === ファイルシステム ===
# 遅いファイルシステム操作
ext4slower 1  # 1ms以上かかるext4操作

# ファイルオープン追跡
opensnoop     # どのプロセスがどのファイルを開くか

# === ネットワーク ===
# TCP接続追跡
tcpconnect    # 新TCP接続
tcpaccept     # 受信TCP接続
tcpretrans    # TCP再送

8.3 bpftraceワンライナー

# システムコール別カウント
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'

# read()返却サイズヒストグラム
bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret > 0/ {
  @bytes = hist(args->ret);
}'

# プロセス別ブロックI/Oサイズ
bpftrace -e 'tracepoint:block:block_rq_issue {
  @[comm] = hist(args->bytes);
}'

# CPUスケジューラスイッチ追跡
bpftrace -e 'tracepoint:sched:sched_switch {
  @[args->next_comm] = count();
}'

# TCP再送追跡
bpftrace -e 'tracepoint:tcp:tcp_retransmit_skb {
  @[comm, args->daddr, args->dport] = count();
}'

# VFS読み取りレイテンシ
bpftrace -e '
kprobe:vfs_read { @start[tid] = nsecs; }
kretprobe:vfs_read /@start[tid]/ {
  @ns = hist(nsecs - @start[tid]);
  delete(@start[tid]);
}'

8.4 libbpf CO-RE(Compile Once - Run Everywhere)

// シンプルなCO-RE eBPFプログラム構造
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

struct event {
    u32 pid;
    u64 duration_ns;
    char comm[16];
};

struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024);
} events SEC(".maps");

SEC("kprobe/do_sys_openat2")
int BPF_KPROBE(trace_openat2, int dfd, const char *filename)
{
    struct event *e;
    e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
    if (!e) return 0;
    
    e->pid = bpf_get_current_pid_tgid() >> 32;
    bpf_get_current_comm(&e->comm, sizeof(e->comm));
    
    bpf_ringbuf_submit(e, 0);
    return 0;
}

char LICENSE[] SEC("license") = "GPL";

9. Flame Graph徹底解説

9.1 CPU Flame Graph

# perfでCPUプロファイル収集
perf record -F 99 -g -a sleep 30

# Flame Graph生成
perf script | \
  stackcollapse-perf.pl | \
  flamegraph.pl --title "CPU Flame Graph" > cpu_flame.svg

9.2 Off-CPU Flame Graph

プロセスがCPU上で実行されていない時間(I/O、ロック、スリープなど)を分析します。

# BCC offcputime使用
offcputime -df -p PID 30 | \
  flamegraph.pl --color=io --title "Off-CPU" > offcpu.svg

# bpftraceでoff-CPU分析
bpftrace -e '
tracepoint:sched:sched_switch {
  @start[args->prev_pid] = nsecs;
}
tracepoint:sched:sched_switch /@start[args->next_pid]/ {
  @us[args->next_comm, ustack] =
    hist((nsecs - @start[args->next_pid]) / 1000);
  delete(@start[args->next_pid]);
}'

9.3 Memory Flame Graph

# メモリ割り当て追跡
perf record -e kmem:kmalloc -g -a sleep 10
perf script | stackcollapse-perf.pl | \
  flamegraph.pl --color=mem --title "Memory Allocations" > mem_flame.svg

# またはBCC memleak
memleak -p PID -a 30 | \
  flamegraph.pl --title "Memory Leak" > memleak_flame.svg

10. sysctlチューニング

10.1 VM(仮想メモリ)チューニング

# === スワップ動作 ===
# vm.swappiness: スワップ使用傾向 (0-100)
# 0: スワップ最小化(OOMリスク)
# 10: DBサーバー推奨
# 60: デフォルト
# 100: 積極的スワップ
sysctl -w vm.swappiness=10

# === ダーティページ ===
# 全メモリに対するダーティページ比率(書き込み開始閾値)
sysctl -w vm.dirty_ratio=15

# バックグラウンドフラッシュ開始閾値
sysctl -w vm.dirty_background_ratio=5

# ダーティページ有効期限(センチ秒)
sysctl -w vm.dirty_expire_centisecs=3000

# ダーティページ書き込み周期
sysctl -w vm.dirty_writeback_centisecs=500

# === オーバーコミット ===
# 0: ヒューリスティック(デフォルト)
# 1: 常に許可
# 2: 物理メモリ + スワップ * ratioまで許可
sysctl -w vm.overcommit_memory=0
sysctl -w vm.overcommit_ratio=50

# === 最小空きメモリ ===
sysctl -w vm.min_free_kbytes=65536

10.2 ネットワークチューニング

# === TCPコネクション ===
# 最大接続バックログ
sysctl -w net.core.somaxconn=65535

# SYNバックログ
sysctl -w net.ipv4.tcp_max_syn_backlog=65535

# TCP接続再利用
sysctl -w net.ipv4.tcp_tw_reuse=1

# === TCPバッファ ===
# 受信バッファ (min, default, max)
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"

# 送信バッファ
sysctl -w net.ipv4.tcp_wmem="4096 87380 16777216"

# グローバルネットワークバッファ
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216

# === TCP Keepalive ===
sysctl -w net.ipv4.tcp_keepalive_time=600
sysctl -w net.ipv4.tcp_keepalive_intvl=60
sysctl -w net.ipv4.tcp_keepalive_probes=3

# === 輻輳制御 ===
sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl -w net.core.default_qdisc=fq

# === その他 ===
# FIN-WAIT-2タイムアウト
sysctl -w net.ipv4.tcp_fin_timeout=15

# ポート範囲
sysctl -w net.ipv4.ip_local_port_range="1024 65535"

# SYNクッキー(SYN Flood防御)
sysctl -w net.ipv4.tcp_syncookies=1

10.3 ファイルシステムチューニング

# システム全体のファイルディスクリプタ制限
sysctl -w fs.file-max=2097152

# inotifyウォッチ制限(ファイル監視)
sysctl -w fs.inotify.max_user_watches=524288

# AIO最大リクエスト数
sysctl -w fs.aio-max-nr=1048576

10.4 カーネルスケジューラチューニング

# CFSスケジューラ最小実行時間 (ns)
sysctl -w kernel.sched_min_granularity_ns=1000000

# スケジューリングレイテンシ (ns)
sysctl -w kernel.sched_latency_ns=6000000

# マイグレーションコスト (ns)
sysctl -w kernel.sched_migration_cost_ns=500000

# 自動グループスケジューリング
sysctl -w kernel.sched_autogroup_enabled=1

11. cgroups v2

11.1 cgroups v2 基本

# cgroups v2マウント確認
mount | grep cgroup2
# cgroup2 on /sys/fs/cgroup type cgroup2

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

# プロセス割り当て
echo PID > /sys/fs/cgroup/myapp/cgroup.procs

# 利用可能なコントローラ確認
cat /sys/fs/cgroup/cgroup.controllers
# cpu io memory pids

11.2 CPU制限

# CPU最大使用量制限
# 形式: QUOTA PERIOD(マイクロ秒)
# 100msの周期で50msだけ使用 = CPU 50%
echo "50000 100000" > /sys/fs/cgroup/myapp/cpu.max

# CPU重み (1-10000, デフォルト100)
echo "200" > /sys/fs/cgroup/myapp/cpu.weight

11.3 メモリ制限

# メモリハードリミット
echo "1G" > /sys/fs/cgroup/myapp/memory.max

# メモリソフトリミット(回収優先対象)
echo "512M" > /sys/fs/cgroup/myapp/memory.high

# メモリ最小保証
echo "256M" > /sys/fs/cgroup/myapp/memory.min

# スワップ制限
echo "0" > /sys/fs/cgroup/myapp/memory.swap.max

# 現在のメモリ使用量
cat /sys/fs/cgroup/myapp/memory.current

# メモリ統計
cat /sys/fs/cgroup/myapp/memory.stat

11.4 I/O制限

# デバイス別I/O帯域幅制限
# 形式: MAJOR:MINOR TYPE=LIMIT
# sdaの読み取りを50MB/sに制限
echo "8:0 rbps=52428800" > /sys/fs/cgroup/myapp/io.max

# sdaの書き込みを20MB/sに制限
echo "8:0 wbps=20971520" > /sys/fs/cgroup/myapp/io.max

# IOPS制限
echo "8:0 riops=1000 wiops=500" > /sys/fs/cgroup/myapp/io.max

# I/O重み
echo "default 100" > /sys/fs/cgroup/myapp/io.weight

11.5 Docker/K8sとの統合

# Dockerでcgroups v2リソース制限
# docker run --cpus=2 --memory=4g --memory-swap=4g myapp

# Kubernetes Podリソース設定(cgroups v2とマッピング)
# resources:
#   requests:
#     cpu: "500m"       -> cpu.weight
#     memory: "512Mi"   -> memory.min
#   limits:
#     cpu: "2"          -> cpu.max
#     memory: "4Gi"     -> memory.max

12. NUMA(Non-Uniform Memory Access)

12.1 NUMAトポロジ

# NUMAトポロジ確認
numactl --hardware

# 出力例:
# available: 2 nodes (0-1)
# node 0 cpus: 0 1 2 3 4 5 6 7
# node 0 size: 32768 MB
# node 0 free: 16384 MB
# node 1 cpus: 8 9 10 11 12 13 14 15
# node 1 size: 32768 MB
# node 1 free: 15360 MB
# node distances:
# node   0   1
#   0:  10  21    <- 同一ノード: 10, 別ノード: 21(2.1倍遅い)
#   1:  21  10

# NUMAメモリ統計
numastat -m

# プロセス別NUMAメモリ統計
numastat -p PID

12.2 NUMAメモリバインディング

# 特定のNUMAノードで実行
numactl --cpunodebind=0 --membind=0 ./myapp

# CPUとメモリの両方をノード0にバインド
numactl -N 0 -m 0 ./database_process

# インターリーブモード(両ノードに均等分配)
numactl --interleave=all ./myapp

# 既存プロセスのNUMAポリシー確認
cat /proc/PID/numa_maps

13. Huge Pages

13.1 Transparent Huge Pages (THP)

# THP状態確認
cat /sys/kernel/mm/transparent_hugepage/enabled
# [always] madvise never

# データベースではTHP無効化推奨(メモリ断片化 + レイテンシスパイク)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

13.2 Explicit Huge Pages

# Huge Page割り当て(2MBページ)
sysctl -w vm.nr_hugepages=1024  # 1024 * 2MB = 2GB

# 現在の状態確認
cat /proc/meminfo | grep Huge
# HugePages_Total:    1024
# HugePages_Free:      512
# HugePages_Rsvd:      256
# HugePages_Surp:        0
# Hugepagesize:       2048 kB

# 1GB Huge Pages(ブート時カーネルパラメータ)
# GRUB: hugepagesz=1G hugepages=16

13.3 データベースでの活用

# PostgreSQL: shared_buffersにHuge Pagesを使用
# postgresql.conf:
# huge_pages = try
# shared_buffers = 8GB

# 必要なHuge Pages数の計算:
# shared_buffers / Hugepagesize = 必要ページ数
# 8GB / 2MB = 4096 pages
sysctl -w vm.nr_hugepages=4096

14. プロセススケジューリング

14.1 CFS(Completely Fair Scheduler)

# CFSスケジューラ統計
cat /proc/sched_debug | head -50

# nice値調整(-20〜19、低いほど高い優先度)
nice -n -10 ./critical_process
renice -n -10 -p PID

# プロセスのスケジューリングポリシー確認
chrt -p PID

14.2 リアルタイムスケジューリング

# SCHED_FIFO設定(リアルタイム、優先度1-99)
chrt -f 50 ./realtime_app

# SCHED_RR(ラウンドロビンリアルタイム)
chrt -r 50 ./realtime_app

# SCHED_DEADLINE(デッドラインベース)
chrt -d --sched-runtime 5000000 --sched-deadline 10000000 \
    --sched-period 10000000 0 ./deadline_app

14.3 CPUアフィニティ

# プロセスを特定のCPUにバインド
taskset -c 0,1 ./myapp          # CPU 0, 1でのみ実行
taskset -c 0-3 ./myapp          # CPU 0-3で実行
taskset -pc 0,1 PID             # 既存プロセスに適用

# IRQアフィニティ(割り込み分散)
echo 2 > /proc/irq/IRQ_NUM/smp_affinity  # CPU 1に割り当て

# isolcpus(ブートパラメータ)
# GRUB: isolcpus=4,5,6,7
# CPU 4-7を一般スケジューリングから除外し、特定プロセス専用に使用

15. プロダクションチューニングチェックリスト

+----+------------------------------+-------------------------------+
| #  | 項目                          | 推奨設定                       |
+----+------------------------------+-------------------------------+
| 1  | ファイルディスクリプタ制限      | ulimit -n 1048576             |
|    |                              | fs.file-max = 2097152         |
+----+------------------------------+-------------------------------+
| 2  | TCPバックログ                 | net.core.somaxconn = 65535    |
+----+------------------------------+-------------------------------+
| 3  | TCPバッファ                   | tcp_rmem/wmem最適化            |
+----+------------------------------+-------------------------------+
| 4  | TCP輻輳制御                   | BBRまたは環境に適したアルゴリズム |
+----+------------------------------+-------------------------------+
| 5  | TCP Keepalive                | 600/60/3(アプリに合わせて)     |
+----+------------------------------+-------------------------------+
| 6  | TIME_WAIT管理                | tcp_tw_reuse = 1              |
+----+------------------------------+-------------------------------+
| 7  | FINタイムアウト               | tcp_fin_timeout = 15          |
+----+------------------------------+-------------------------------+
| 8  | SYNクッキー                   | tcp_syncookies = 1            |
+----+------------------------------+-------------------------------+
| 9  | ポート範囲                    | ip_local_port_range 1024-65535|
+----+------------------------------+-------------------------------+
| 10 | スワップ動作                   | vm.swappiness = 10 (DB)       |
+----+------------------------------+-------------------------------+
| 11 | ダーティページ                 | dirty_ratio = 15              |
|    |                              | dirty_background_ratio = 5    |
+----+------------------------------+-------------------------------+
| 12 | I/Oスケジューラ               | NVMe: none, SSD: mq-deadline  |
+----+------------------------------+-------------------------------+
| 13 | THP                          | DBサーバー: 無効化              |
+----+------------------------------+-------------------------------+
| 14 | Huge Pages                   | DB shared_buffers用設定        |
+----+------------------------------+-------------------------------+
| 15 | NUMA                         | DBを単一ノードにバインド         |
+----+------------------------------+-------------------------------+
| 16 | CPUアフィニティ               | 重要プロセスのCPU固定            |
+----+------------------------------+-------------------------------+
| 17 | OOMスコア調整                 | 重要プロセスの保護               |
+----+------------------------------+-------------------------------+
| 18 | cgroups v2                   | リソース隔離と制限               |
+----+------------------------------+-------------------------------+
| 19 | 輻輳制御                      | BBR + fq qdisc                |
+----+------------------------------+-------------------------------+
| 20 | inotifyウォッチ               | max_user_watches = 524288     |
+----+------------------------------+-------------------------------+
| 21 | AIOリクエスト                 | aio-max-nr = 1048576          |
+----+------------------------------+-------------------------------+
| 22 | カーネルログ監視              | dmesg定期確認                  |
+----+------------------------------+-------------------------------+

16. 実践クイズ

クイズ 1: USE方法論

サーバーのCPU使用率(Utilization)が90%だが性能低下がない場合、USE方法論で次に確認すべきことは?

正解:Saturation(飽和度(ほうわど))

CPU使用率が高くても必ずしも問題ではありません。重要なのは飽和度です。実行キュー(run queue)に待機中のプロセスがあるか確認する必要があります。

# 実行キュー長の確認
vmstat 1 | awk '{print $1}'  # r列

# BCC runqlatでスケジューラ遅延を測定
runqlat

飽和度がなければ(rがCPU数以下)、CPUは効率的に使われています。最後にErrorsを確認します。

クイズ 2: Flame Graph解釈

Flame Graphで特定の関数が非常に広い幅を占めるが、その上に子関数が詰まっている場合、この関数自体がボトルネックですか?

正解:いいえ

Flame Graphにおいて関数の幅は、その関数と子関数が占める合計CPU時間です。子関数で埋(う)まっている場合、実際のCPU時間は子関数で消費されています。

真のボトルネックは「プラトー(高原(こうげん))」を探す必要があります。スタックの最上部で広い幅を占める関数が実際にCPUを消費している関数です。

クイズ 3: vm.swappiness

vm.swappinessを0に設定するとスワップが完全に無効化されますか?

正解:いいえ

vm.swappiness=0はスワップを完全に無効化するものではありません。カーネルがメモリ不足(ぶそく)状況でスワップの使用を最小化するよう設定するものです。極端(きょくたん)なメモリ圧迫(あっぱく)時にはスワップが発生する可能性があります。

スワップを完全に無効化するには swapoff -a コマンドを使用する必要があります。ただし、OOM Killerがプロセスを終了するリスクがあるため注意が必要です。

クイズ 4: THPとデータベース

Transparent Huge Pages(THP)がデータベース(PostgreSQL、MySQL、MongoDB)の性能に悪影響を与える理由は?

正解: THPは2MB単位でメモリを割り当てます。データベースは通常8KB(PostgreSQL)または16KB(MySQL)のページ単位で作業します。

問題点:

  • メモリ断片化(だんぺんか): THP割り当てのためにカーネルがメモリを圧縮(compaction)する際にレイテンシスパイクが発生
  • 書き込み増幅: 2MBの一部だけ変更しても全体2MBをコピー(Copy-on-Write)
  • メモリ浪費(ろうひ): 実際の使用量より大きな単位で割り当て
  • 予測(よそく)不可能なレイテンシ: defragプロセスがプロセスを停止させる可能性

代わりに、Explicit Huge Pagesをshared_buffers専用に設定することが推奨されます。

クイズ 5: eBPF vs 従来の追跡ツール

eBPFがstraceよりプロダクション環境で安全な理由は?

正解: straceはptraceシステムコールを使用して対象プロセスのすべてのシステムコールをインターセプトします。これにより、各システムコールに2回のコンテキストスイッチが追加され、パフォーマンスが50-100%以上低下する可能性があります。

eBPFは:

  • カーネル内部で実行: ユーザー空間-カーネル間の遷移を最小化
  • JITコンパイル: ネイティブコードレベルのパフォーマンス
  • 検証器(けんしょうき、Verifier): プログラムがカーネルを損傷(そんしょう)できないことを保証
  • 選択的(せんたくてき)追跡: 必要なイベントのみ追跡可能
  • 最小限のオーバーヘッド: 一般的に5%未満のパフォーマンス影響

そのため、プロダクション環境でも安全に使用できます。


17. 参考資料

  1. Systems Performance, 2nd Edition - Brendan Gregg(パフォーマンスエンジニアリングのバイブル)
  2. BPF Performance Tools - Brendan Gregg(eBPFツール完全ガイド)
  3. Brendan Gregg's Website - https://www.brendangregg.com/ (豊富な無料資料)
  4. Linux Perf Wiki - https://perf.wiki.kernel.org/
  5. Flame Graphs - https://www.brendangregg.com/flamegraphs.html
  6. BCC Tools - https://github.com/iovisor/bcc
  7. bpftrace - https://github.com/bpftrace/bpftrace
  8. io_uring - https://kernel.dk/io_uring.pdf
  9. Linux kernel documentation: cgroups v2 - https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
  10. NUMA documentation - https://www.kernel.org/doc/html/latest/admin-guide/mm/numa_memory_policy.html
  11. Red Hat Performance Tuning Guide - https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/monitoring_and_managing_system_status_and_performance/
  12. Netflix Tech Blog - Linux Performance - https://netflixtechblog.com/
  13. Facebook/Meta Engineering Blog - BPF - https://engineering.fb.com/
  14. sysctl documentation - https://www.kernel.org/doc/html/latest/admin-guide/sysctl/