- ブラウザURL入力
- DNS名前→IP
- ルータ経路選択
- ロードバランサ振り分け
- Nginx受け口
- アプリ処理今ここ
- DB保存
前回までは数字の読み方と観測器の性質を見ました。今回は数字が読めた後の話です。直す場所を選んだ時点で、得られる速さの上限が決まっています。
まず結論
直列につながった経路では、全体の時間は各段の足し算です。だから効くのは最大の項だけで、小さい項をどれだけ削っても全体はほとんど動きません。
最大の項を削ると、次に大きい項が最大になります。「直したのに思ったほど速くならない」は、失敗ではなく足し算の構造です。
2つの処理が順番に走る経路で、前半が全体の約8割、後半が約2割を占めています。前半を2倍速くしたら、全体は何倍になるでしょうか。
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
順番に走るなら、全体は足し算
段1・段2・段3が順番に走り、前が終わらないと次が始まらないとします。全体の所要時間は各段の和です。それ以上でも以下でもありません。
和のうち 0.2 を占める項をゼロにしても、和は 0.2 しか減りません。どれだけ努力しても 0.2 以上は減らせないのです。一方 0.8 の項なら最大 0.8 減らせます。効くのは最大の項だけとはこの意味です。
もう一つ。最大の項を削ると残った項が相対的に大きくなり、次に測ると別の段が最大の項です。新しい問題ではなく、順位が入れ替わっただけです。
- 順位が入れ替わるだけで、和は毎回小さくなっている
- 「また別のところが遅い」は進んでいる証拠
80対20の2段で計ってみる
本教材の測定環境(Docker Desktop の Linux VM、aarch64、カーネル 6.10.14-linuxkit、CPU 2.0 相当に制限、Python 3.11.2)で、段Aと段Bが順に走る処理を作りました。仕事量の比は A : B = 4 : 1、各条件12回試行の最小値です。
change A(units) B(units) total(ms) speedupbaseline 1200000 300000 17.87 1.00xA made 2x faster (the bottleneck) 600000 300000 10.70 1.67xA made 4x faster 300000 300000 7.06 2.53xA made 10x faster 120000 300000 4.93 3.63xA made INFINITELY fast (A removed) 1 300000 3.56 5.02x--- now instead: B made 2x faster 1200000 150000 16.08 1.11xB made 10x faster 1200000 30000 14.56 1.23xB made INFINITELY fast (B removed) 1200000 1 14.07 1.27x
段Aを「2倍速く」しても、全体は 1.67 倍。 B が残るからです。
段Aを10倍にしても 3.63 倍、実質的に取り除いても 5.02 倍が上限。 右端の倍率は丸める前の値から出しているので、表示の ms 同士を割ると末尾がずれます。「INFINITELY fast」は units を1にしただけでゼロではなく、3.56 ms には呼び出しと計時の費用が残ります。上限が5倍なのは残る B が約2割だから。1 ÷ 0.2 = 5 と一致します。
段Bは取り除いても 1.27 倍。 どれだけ頑張ってもここより上に行けません。上限は努力の量ではなく、選んだ場所で決まります。
全体の約8割を占める段を、実質的に取り除けたとします。全体は何倍まで速くなりますか。
法則の検証ではなく、足し算の帰結
上の結果を**「アムダールの法則を実証した」とは書きません。** 理由は2つです。
1つは、この関係の原論文(1967年の会議録)を本教材では入手できなかったためです。学術データベースは403を返し、大学のミラーとされる2つの URL は .pdf に HTTP 200 を返しながら、中身は認証のログイン画面の HTML でした。200 は本文の存在を意味しません。 読めていないものを「〜が述べている」とは書けません。
もう1つは、これが検証を要する法則ではなく足し算の性質だからです。段が順に走るなら合計は和で、残る項は消えません。名前を知らなくても導けます。身につけてほしいのは名前ではなく、部分の倍率と全体の倍率が一致しない理由です。
最大の項が入れ替わるのを3手で見る
同じ処理で「最大の項を測り、それを6分の1にする」を繰り返しました。
# Start from baseline. Fix A (the biggest). Then measure which stage is biggest.step 0: A= 14.33 ms B= 3.52 ms total= 17.89 ms -> largest term is Astep 1: A= 2.34 ms B= 3.56 ms total= 5.89 ms -> largest term is Bstep 2: A= 2.33 ms B= 0.53 ms total= 2.92 ms -> largest term is A
step 0 では A が最大です。A を6分の1にすると(step 1)、B は何も触っていないのに B が最大になります。B も6分の1にすると(step 2)、また A に戻ります。
step 1 で B が最大になったのは、前回の判定が誤りだったからではありません。 A を直したから B が最大になったのです。判定は正しく、対象が変わりました。
一方で合計は毎回減っています。17.89 → 5.89 → 2.92 ms。「また別のところが遅い」と「改善が効いていない」は別の状態で、ここでは前者だけが起きています。
最大の段を直したところ、次の測定では別の段が最大になっていました。これはどう解釈すべきですか。
直列経路の小さい段を直したとき
全体の2割の段を改善しても、残る8割が消えないので上限があります。本教材の測定環境では取り除いても 1.27 倍でした。効かなかったのではなく、効いてもそこまでの場所だったということです。
直した段 全体に占める割合 実質的に取り除いた場合段A 約8割 5.02倍段B 約2割 1.27倍
DB編『掃除は4つの仕事をしている — そしてディスクは空かない』
行を削除して掃除を走らせても、ディスク使用率は下がりません。公式が "extra space is not returned to the operating system (in most cases)" と書いており、成功時にも起きます。見る指標は、下がったかではなく増え続けていないかです。
見る指標 下がらないとき 判定ディスク使用率 設計どおり 失敗の証拠にならない使用量の増え方 平らなら正常 回収が効いているか
直列経路の改善と、データベースの掃除。層は違いますが、「効かなかった」の読み方に共通する構造は何でしょうか。
どちらも、期待した変化が出ないと「作業が間違っていた」と結論しがちです。その結論が成り立たない理由を考えてみてください。
この章のまとめ
- 段が順に走る経路では、全体の時間は各段の和。効くのは最大の項だけ。
- 倍率の上限は、選んだ場所が占める割合で先に決まる。 1 ÷ 残りの割合 で着手前に計算する。
- 本教材の測定環境(Docker Desktop の Linux VM、12回試行の最小値)で、約8割の段は取り除いて 5.02 倍が上限、約2割の段は取り除いても 1.27 倍。読んでよいのは倍率と順序だけ。
- 最大の項を削ると、残った項が最大になる。 同じ環境で A → B → A と3手で入れ替わった。前回の判定が誤りだったのではなく、直したことの帰結。
- これは足し算の帰結であって法則の検証ではない。原論文を入手できていないため通称に帰属させない。
- 「直したのに速くならない」と「直し方が間違っていた」は別の状態。上限を先に計算すれば取り違えずに済む。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
直列経路で「最大の項だけが効く」と言えるのは、なぜですか。
用語集(4語)
- 直列経路
- 複数の段が順番に走り、前が終わらないと次が始まらないつながり方。全体の所要時間は各段の和。
- 最大の項
- 直列経路の和のうち最も大きい段。本教材の「ボトルネック」はこの意味。
- 倍率の上限
- その段を取り除いても届かない、全体の倍率の限界。1 ÷ (残りの割合) で求まる。
- アムダールの法則と呼ばれている関係
- 直列部分の割合が改善の上限を決めるという関係の通称。本教材は原論文を入手できていないため、この名前に帰属させない。