目次
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. 参考資料
- Systems Performance, 2nd Edition - Brendan Gregg(パフォーマンスエンジニアリングのバイブル)
- BPF Performance Tools - Brendan Gregg(eBPFツール完全ガイド)
- Brendan Gregg's Website - https://www.brendangregg.com/ (豊富な無料資料)
- Linux Perf Wiki - https://perf.wiki.kernel.org/
- Flame Graphs - https://www.brendangregg.com/flamegraphs.html
- BCC Tools - https://github.com/iovisor/bcc
- bpftrace - https://github.com/bpftrace/bpftrace
- io_uring - https://kernel.dk/io_uring.pdf
- Linux kernel documentation: cgroups v2 - https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
- NUMA documentation - https://www.kernel.org/doc/html/latest/admin-guide/mm/numa_memory_policy.html
- Red Hat Performance Tuning Guide - https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/monitoring_and_managing_system_status_and_performance/
- Netflix Tech Blog - Linux Performance - https://netflixtechblog.com/
- Facebook/Meta Engineering Blog - BPF - https://engineering.fb.com/
- sysctl documentation - https://www.kernel.org/doc/html/latest/admin-guide/sysctl/
현재 단락 (1/398)
プロダクション環境(かんきょう)で発生する障害(しょうがい)の相当数(そうとうすう)はパフォーマンス問題に起因(きいん)します。CPU使用率(しようりつ)の急上昇(きゅうじょうしょう)、メモリリーク、...