詳解システム・パフォーマンス - 4. 可観測性ツール
この章での目標
静的パフォーマンスチューニングツールとクライシスツールを見分けられるように
ツールのタイプとオーバーヘッドを理解する
カウンタ、プロファイリング、トレーシング
可観測データのソースについて学ぶ
/proc, /sys, トレースポイント, kprobe, uprobe, USTD, PMC
統計量のアーカイブを作る sar(1) の設定方法を学ぶ
この章では例として Linux Ubuntu を使う
ebiken.icon ここからは細かいツールの使い方が多く出てくるが、今回の輪読会では概要を理解して知識のインデックスを持っておくことが目的のため、概要の詳解に留める
取り上げるツール
https://scrapbox.io/files/6620dc801197d10024c09bef.png
大半はこれ以降の章(CPU、メモリ、ディスクなどの特定のデバイス) で取り上げる
他に perf, Ftrace, BCC, bpftrace なども取り上げる
静的パフォーマンスツール
https://scrapbox.io/files/6620dc7ef1b07000255e4392.png
アクティブなワークロードではなく、休止状態のシステムの属性を解析する
(2章の静的パフォーマンスチューニングで紹介した)
構成やコンポーネントの問題をチェックするときはこれらを使おう
クライシスツール
本番システムで重大なパフォーマンス障害が起き、デバッグのために様々なパフォーマンスツールが必要になっても、それらがインストールされていないということがある
障害を起こしているとインストールにずっと長い時間がかかることも
そのためクライシスツールとして推奨されているインストールパッケージがまとめて提供されている
Ubuntu/Debian でのパッケージ名と提供コマンド
https://scrapbox.io/files/6620dc7aadca8d0025d3abf2.png
Netflix ではこれらが確実に本番システムにインストールされているようにするOSパフォーマンスチームがいる
コンテナ環境では、システムへのフルアクセスを持ち(名前空間の共有など)、すべてのツールがインストールされている特権的なデバッグコンテナを作ると良い場合がある
必要なときにこのコンテナイメージをホストにインストールし、デプロイする
パッケージを追加しただけでは不十分なこともある
トレーシングツールは、一般に CONFIG_FTRACE や CONFIG_BPF などのカーネルCONFIGオプションを有効にする必要がある
プロファイリングツールは、スタックウォーキングをサポートするソフトウェアを構成する必要がある
そのために libc, libpthread などでフレームポインタがコンパイルされたバージョンを使う or debuginfo ツールをインストールして DWARF スタックウォーキングをサポートする
個々のパフォーマンスツールが動作するかどうかチェックしておく必要がある
ツールタイプ
https://scrapbox.io/files/6620dc7691f1370025d0117a.png
提供する可観測性 がシステム全体/プロセス単位か
カウンタベース か イベントベース か
e.g.
top(1) はシステム全体の集計情報を持っている
全体のイベントルールは特定のプロセスだけを対象にするようにフィルターできることが多い (-p PID)
イベントベースにはプロファイラとトレースが含まれる
固定カウンタ
カーネルはシステム統計の提供のため様々なカウンタ(イベントが発生するとインクリメントされる)を持っている
イベント数、イベント処理にかかった時間の合計の2つの累積値を持つ
デフォルトで有効。カーネルによって継続的にメンテナンスされており、追加コストもユーザー空間からの値の読み出しのみなので無視して良い
e.g.
受診したネットワークパケット
実行したディスクI/O
発生した割り込み
システム全体
カーネルカウンタを使ってシステム全体のアクティビティを解析する
e.g.
vmstat(8): メモリ
mpstat(1): CPU
iostat(1): ディスクI/O
nstat(8): TCP/IP
sar(1): 様々な統計量
一般に root 以外のユーザーが見れる
それらの統計量は一般にモニタリングソフトウェアでグラフ化される
インターバルと個数を指定するという慣習がある
e.g. vmstat(8) に1秒で3この出力を返すように指示
code:sh
$ vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 1446428 662012 142100 5644676 1 4 28 152 33 1 29 8 63 0 0
4 0 1446428 665988 142116 5642272 0 0 0 284 4957 4969 51 0 48 0 0
4 0 1446428 685116 142116 5623676 0 0 0 0 4488 5507 52 0 48 0 0
プロセスごと
/proc ファイルシステムから統計量を読み出している
e.g.
ps(1): プロセス
top(1): CPU
pmap(1): プロセスのメモリセグメント
プロファイリング
ターゲットの挙動のサンプル、スナップショットを集めて特徴を表す
ツールをプロファイラ(profiler)と呼ぶ
固定カウンタとは異なりCPUやストレージのオーバーヘッドがかかるため、一般に必要なときに限り有効にされる
オーバーヘッドはイベントの発生頻度による
システム全体
perf(1): Linux の標準プロファイラ
profile(8): BPFベースのCPUプロファイラ
Intel VTune Amplifier XE: Linux/Windows 向けプロファイラ
プロセスごと
gprof(1): コンパイラが追加したプロファイリング情報
cachegrid: ハードウェアキャッシュ
Java Flight Recorder (JFR): Java のプロファイラ
トレーシング
イベントを全てインストルメンテーションし、あとから詳細情報を見たり集計を生成する
ツールをトレーサー(tracer)と呼ぶ
サンプルを記録するプロファイリングだけでなくイベントの収集、調査を目的
プロファイリングよりもオーバーヘッドが高くなる
ロギング(logging) も、デフォルトで有効な頻度の低いトレーシングと捉えることができる
システム全体
tcpdump(8): ネットワークパケット
biosnoop(8): ブロックI/O
execsnoop(8): プロセス
perf(1): Linux の標準プロファイラ
perf trace: システムコールをトレースするperf のサブコマンド
Ftrace: Linux の組み込み
BCC: BPF ベース
bpftrace: BPFベースのトレーサーとツールキット
BCC, bpftrace を使って作られたトレーシングツールは、biosnoop, execsnoop も含め100種以上
プロセスごと
strace(1): システムコール
gdb(1): ソースレベルのデバッガ
デバッガはイベントごとの解析ができるがターゲットの実行を停止/開始させるひつようがあるため、オーバーヘッドがかなり大きい
モニタリング
sar(1)
単一OSホストのモニタリングで古くから使われている
cron によってスケジューリングされた時刻に実行されるエージェントが、システム全体のカウンタの状態を記録していく
e.g.
code:sh
$ sar
Linux 4.15.0-66-generic (bgregg) 12/21/2019 _x86_64_ (8 CPU)
12:00:01 AM CPU %user %nice %system %iowait %steal %idle
12:05:01 AM all 3.34 0.00 0.95 0.04 0.00 95.66
12:10:01 AM all 2.93 0.00 0.87 0.04 0.00 96.16
12:15:01 AM all 3.05 0.00 1.38 0.18 0.00 95.40
12:20:01 AM all 3.02 0.00 0.88 0.03 0.00 96.06
Average: all 0.00 0.00 0.00 0.00 0.00 0.00
SNMP
Simple Network Management Protocol
ネットワークのモニタリングに古くから使われてきた
いまはカスタムエージェントベースのものにほとんど切り替わった
エージェント
最近のモニタリングソフトウェアは、各システムでエージェント (agent, exporter, plugin とも) を動かす
カウンタだけでは入手できないアプリケーションの指標を提供できる
Performance Co-Pilot (PCP)
PMDA (Performance Metric Domain Agents) と呼ばれる数十種類のエージェント
Prometheus
DB、ハードウェア、メッセージング、ストレージ、HTTP、API、ロギングなど数十種のエクスポーター
collectd
数十種のプラグイン
サンプルのモニタリングアーキテクチャ
https://scrapbox.io/files/6620dc71cf4dd70023566468.png
モニタリングデータベースサーバーには Graphite Carbon、モニタリングWebサーバー/ダッシュボードには Grafana など
製品の種類は多く、ターゲットごとに数百種エージェントがある
一部の製品はシステムツール(vmstat, iostat など)を実行して指標を読み出し、パースしていたりするが、効率が悪い。良い製品は、ライブラリやカーネルインターフェースで指標を直接呼び出す
情報ソース
https://scrapbox.io/files/6620dc6962d5b90024ebdd02.png
各トレーシングツールが対象としているもの
https://scrapbox.io/files/6620dc6b339e280025b61f4b.png
/proc
カーネル統計に対するファイルシステム i/f
システム全体 or プロセスIDに基づく名前がつけられたディレクトリ、各プロセスの統計量が格納される
カーネルによって動的に作成され、ストレージデバイスは紐づかない(= インメモリ)
ファイルシステム i/f になっているので、cd, cat(1), grep(1), awk(1) などで調べることも可能
e.g. プロセスごと
code:sh
$ ls -F /proc/18733
arch_status environ mountinfo personality statm
attr/ exe@ mounts projid_map status
autogroup fd/ mountstats root@ syscall
auxv fdinfo/ net/ sched task/
cgroup gid_map ns/ schedstat timers
clear_refs io numa_maps sessionid timerslack_ns
cmdline limits oom_adj setgroups uid_map
comm loginuid oom_score smaps wchan
coredump_filter map_files/ oom_score_adj smaps_rollup
cpuset maps pagemap stack
cwd@ mem patch_state stat
e.g. システム全体
code:sh
acpi/ dma kallsyms mdstat schedstat thread-self@
buddyinfo driver/ kcore meminfo scsi/ timer_list
bus/ execdomains keys misc self@ tty/
cgroups fb key-users modules slabinfo uptime
cmdline filesystems kmsg mounts@ softirqs version
consoles fs/ kpagecgroup mtrr stat vmallocinfo
cpuinfo interrupts kpagecount net@ swaps vmstat
crypto iomem kpageflags pagetypeinfo sys/ zoneinfo
devices ioports loadavg partitions sysrq-trigger
diskstats irq/ locks sched_debug sysvipc/
e.g. ファイルの内容
code:sh
$ cat /proc/meminfo
MemTotal: 15923672 kB
MemFree: 10919912 kB
MemAvailable: 15407564 kB
Buffers: 94536 kB
Cached: 2512040 kB
SwapCached: 0 kB
Active: 1671088 kB
$ grep Mem /proc/meminfo
MemTotal: 15923672 kB
MemFree: 10918292 kB
MemAvailable: 15405968 kB
内容は proc(5) のman ページとカーネルのドキュメントにドキュメントが書いてある
/sys
/sys にマウントされる sysfs ファイルシステムを提供している
もともとデバイスドライバの統計量を提供するために設計されたもので、任意の統計タイプを含むように拡張された
e.g. 一部の例
code:sh
$ find /sys/devices/system/cpu/cpu0 -type f
/sys/devices/system/cpu/cpu0/uevent
/sys/devices/system/cpu/cpu0/hotplug/target
/sys/devices/system/cpu/cpu0/hotplug/state
/sys/devices/system/cpu/cpu0/hotplug/fail
/sys/devices/system/cpu/cpu0/crash_notes_size
/sys/devices/system/cpu/cpu0/power/runtime_active_time
/sys/devices/system/cpu/cpu0/power/runtime_active_kids
/sys/devices/system/cpu/cpu0/power/pm_qos_resume_latency_us
/sys/devices/system/cpu/cpu0/power/runtime_usage
/sys/devices/system/cpu/cpu0/topology/die_id
/sys/devices/system/cpu/cpu0/topology/physical_package_id
/sys/devices/system/cpu/cpu0/topology/core_cpus_list
/sys/devices/system/cpu/cpu0/topology/die_cpus_list
/sys/devices/system/cpu/cpu0/topology/core_siblings
遅延アカウンティング
CONFIG_TASK_DELAY_ACCT オプションを指定すると、以下の項目についてタスクごとの時間を管理する
スケジューラレイテンシ
ブロックI/O
スワッピング
メモリの回収
netlink
カーネル情報を取得するための特殊なソケットアドレスファミリ (AF_NETLINK)
ip(8), ss(8), routel(8) などが利用している
トレースポイント
Linux カーネルの静的インストルメンテーションのためのイベントソース
カーネルコードの論理的な一にハードコードされている
e.g. システムコール、スケジューライベント、ファイルシステムオペレーション、ディスクI/Oなど
利用できるトレースポイントは perf list で調べられる
code:sh
$ perf list tracepoint
List of pre-defined events (to be used in -e):
skb:consume_skb [Tracepoint event”
トレースポイントは、実際はカーネルソースコードに記述されたトレーシング関数である
例えば trace_sched_wakeup() というトレースポイントがあり、kernel/sched/core.c にこの関数の呼び出しが含まれている
オーバーヘッド
各イベントにわずかなCPUオーバーヘッドがあり、イベントの後処理のためのCPUオーバーヘッドとイベントの記録のためのファイルシステムオーバーヘッドも発生ことがある
発生頻度とCPUの数によって、本番への影響が大きくなるかどうか決まる
今日の一般的なシステムでは毎秒1万イベントほどのオーバーヘッドまでは無視でき、計測可能なレベルになってくるのは10万イベントを超えたくらい。ディスクイベントは少ないが、スケジューライベントは毎秒10満開を軽く超えることがある
カーネルにトレースポイントを追加するときには理解しておくこと
kprobe
kernel probe
動的インストルメンテーションをするトレーサーのための Linux カーネルイベントソースで、あらゆるカーネル関数、命令をトレースできる
カーネルのバージョンによって変更される可能性のある関数/引数を表に出すため、不安定なAPIと考えられている
内部動作の標準的な方法は、実行中のカーネルコードの命令テキストを書き換えて必要な命令を挿入するというもの
本番稼働しているカーネルの動作について、ほぼ無限の情報を引き出すための最後の手段なので重要。他のツールでは見えないパフォーマンス上の問題を観察、観測するために欠かせない
e.g. do_nanosleep() をインストルメンテーションし、on-CPUのプロセスを表示する
code:sh
$ bpftrace -e 'kprobe:do_nanosleep { printf("sleep by: %s\n", comm); }'
Attaching 1 probe...
sleep by: mysqld
sleep by: mysqld
sleep by: sleep
^C
$
bpftrace プログラムが実行し始めたときに作られ、強制終了されたときに削除される
e.g. 引数のトレース
code:sh
$ bpftrace -e 'kprobe:do_nanosleep { printf("mode: %d\n", arg1); }'
Attaching 1 probe...
mode: 1
mode: 1
mode: 1
リターンと戻り値は kretprobe でトレースできる
uprobe
user-space probe
ユーザー空間を対象とする動的インストルメンテーション
e.g. 引数のトレース
code:sh
$ bpftrace -e 'uprobe:/bin/bash:decode_prompt_string { printf("%s\n", str(arg0)); }'
Attaching 1 probe...
uretprobe を利用すると、戻り値のトレースもできる
USDT
User-level Statically-Defined Tracing
トレースポイントのユーザー空間ver
ハードウェアカウンタ (PMC)
プロセッサなどのデバイスはアクティビティの計測のためにハードウェアカウンタをサポートしている
PMC (Performance Monitoring Counter) と呼ばれているが、CPC(CPU Performance Counter), PIC(Performance Instrumentation Counter), PMUイベント(Performance Monitoring Unit event) とも呼ばれる
CPU命令の処理効率、CPUキャッシュヒット率、メモリとデバイスバスの使用状況などが取得でき、パフォーマンス分析では欠かせないリソース
https://scrapbox.io/files/6620dc61b595fb0025792a6b.png
e.g. perf stat を実行するとデフォルトで architectural PMC をインストルメンテーションする
code:sh
$ perf stat gzip words
Performance counter stats for 'gzip words':
156.927428 task-clock (msec) # 0.987 CPUs utilized
1 context-switches # 0.006 K/sec
0 cpu-migrations # 0.000 K/sec
131 page-faults # 0.835 K/sec
209,911,358 cycles # 1.338 GHz
288,321,441 instructions # 1.37 insn per cycle
66,240,624 branches # 422.110 M/sec
1,382,627 branch-misses # 2.09% of all branches
0.159065542 seconds time elapsed
その他の情報ソース
MSR(model-specific register): CPUのクロックレートや使用率、温度、消費電力など
ptrace(2): プロセスのトレーシングを制御
関数プロファイリング
ネットワークスニッフィング(libpcap): ネットワークデバイスからパケットをキャプチャするためのいんたーふぇーす
netfilter conntrack: ネットワークのフローログ
プロセスアカウンティング: プロセスの実行時間に基づいて利用料を請求するために使われていた
ソフトウェアイベント
sar(1)
重要なモニタリングツールの一つ
できること
https://scrapbox.io/files/6620dc5b18e1160026455741.png
(導入、使い方の説明がメインだったので省略)
具体的な使い方は 6章~10章、付録Cを参照
トレーシングツール
主要なトレーシングツール
perf(1)
Linux 公式プロファイラ。PMC分析に優れている
Ftrace
Linux 公式トレーサー。カーネルのコードパスに適している
BPF (BCC, bpftrace)
eBPF のうち主役級の高度なトレーシングツール
SystemTap
様々なターゲットをトレースするためのライブラリを多数そろえている
LTTng
ブラックボックス記録に最適化されたトレーサー
ツールに対する観察
ツールとその基礎になる統計量はソフトウェアによって実装されており、バグの可能性も当然ある。ドキュメントにも間違いがある可能性がある。新しく触れる統計には健全な懐疑主義をもって挑み、その本当の意味は何か、本当に正しいのかどうか問うべき
ツールと計測値が間違っている
man ページが正しくない
指標が不完全
指標のデザインに問題があり紛らわしい
指標収集コードのバグ
指標の処理のバグ
結果がわかっているワークロードを利用して正しいかどうかチェックするのも良い
現実的には自分が使うすべてのパフォーマンス計測値をダブルチェックする時間はない。異常な結果が出たとき、会社にとって死活的に重要な結果が出たときだけだろう。ただしダブルチェックをしていない、ツールが正しいと考えていた、と意識することには意味がある