VOLUME 05 / CHAPTER 02
保存したはずのデータは、どこにあったのか
CPUキャッシュ、ページ、ストレージの書込みを層ごとに区別する。容量、IOPS、帯域、永続化、冗長化の異なる保証から基盤を選ぶ。
出典照合日: · 独自解説
架空事例:青葉機材が帳票と予約記録を保存する。時間、容量、アクセス列は独自の例であり、特定のCPU、SSD、OSの実測ではない。LinuxとPostgreSQLに固有の説明は、その製品の資料へ対応付ける。
同じ「保存済み」に、複数の場所がある
帳票を保存すると、すぐに完了が返る。直後に読み直しても内容は正しい。ところが、電源断の後には一部の記録を取り戻せなかった。
読み直せたことは、少なくともその時点で参照できる場所にデータがあったことを示す。電源が失われても残る場所へ、必要な順序で記録されたことまで、同じ観測だけでは分からない。
アプリケーションのバッファ、OSのキャッシュ、ストレージ装置のキャッシュ、不揮発媒体は、同じものではない。どこに置くと速いかという性能の話と、どこまで届いたら成功と返すかという永続性の話を分ける。原教材第14〜16章の記憶階層と、第18章のコミットが接続する場所である。1
CPUの近くにある記憶と、帳票のキャッシュ
CPUキャッシュは、主記憶のデータや命令へのアクセスを速めるために使われる。一方、検索結果をアプリケーションで保存するキャッシュは、検索処理を再実行しないためのものだ。どちらも再利用を狙うが、保持する単位や、元の情報との整合を保つ仕組みが異なる。
CPUキャッシュをアプリケーションのTTLで管理するわけではない。検索結果のキャッシュを設置しても、CPU内部のキャッシュ配置を直接指定したことにはならない。「キャッシュを増やす」と言うなら、どの層でどの仕事を減らしたいかを決める。1
青葉機材の帳票生成が、同じ機材情報を何度もDBへ取りに行くために遅いなら、処理単位で取得をまとめる案がある。だが、貸出し可否のように途中で変わる情報まで古い値で確約してよいかは別である。省略できる仕事は、その情報が有効である範囲によって決まる。
空きがあっても、同じ場所で押し出し合う
単純なダイレクトマップのキャッシュを想像する。メモリのブロックAとBが、どちらも同じキャッシュ位置へ対応する。A、B、A、Bと交互に参照すると、毎回もう一方を押し出し、ほかの位置が空いていてもミスが続き得る。
セットアソシアティブなら、対応するセット内に複数の格納候補を持つ。二つの候補へAとBを残せる条件なら、最初の読込み以降に再利用できる。ただし、セットの外まで自由に置ける方式ではない。さらに三つ以上の競合があれば、置換の問題は再び現れる。1
容量が足りないこと、配置上の競合、最初のアクセスでまだ存在しないことを区別すると、同じ低ヒット率でも改善の方向が変わる。単にキャッシュ全体の容量だけを見ても、アクセス順序との関係を説明できない。
ミス率を小さく見ても、時間は小さくならない
ヒットまでの所要時間を3ns、ミス時に追加される時間を100ns、ヒット率を95%とする。単純な平均は 3+0.05×100=8ns になる。
ここで100nsが「追加」ではなく「ミス時の総時間」なら、式は 0.95×3+0.05×100 となり、7.85nsである。数字がほとんど同じに見えても、定義が違えば式は変わる。1
小さいミス率でも、ミスに長い時間がかかれば平均へ大きく寄与する。CPUキャッシュと主記憶の差、メモリとストレージの差、アプリケーションキャッシュと外部APIの差では、それぞれ時間の桁が異なる。率だけを改善指標にせず、失敗したときにどれだけ待つかも読む。
ただし、こうした加重平均は単純化した一アクセスのモデルである。実際には処理の重なりや先読みによって、個々の待ち時間がそのまま全体へ加算されるとは限らない。例の計算結果を特定CPUの性能保証へ変えない。
ページフォールトは、すべてディスク読取りではない
仮想メモリのページにアクセスしたとき、必要な対応や内容がそのまま使える状態になく、OSの処理が必要になることがある。この事象を見て、すべてがストレージからの読込みだと考えるのは粗すぎる。
Linuxのgetrusageの説明では、I/Oを必要としないminor faultと、I/Oを必要とするmajor faultを区別している。2 原教材の、ページフォールトに大きな追加時間を与えた数値問題は、その問題が置く条件の下で読む。実測の全フォールト件数へ一律のディスク時間を掛けてはいけない。
また、空きメモリが少ないことと、処理がメモリ不足で止まっていることも同義ではない。どの程度再利用できる領域があり、要求する作業集合に対して足りているかを考える。LinuxのPSIは、CPU・メモリ・I/O資源への競合によって仕事が待たされた時間を観測する仕組みとして説明されている。3
本事例なら、大量帳票を同時に生成したときだけ、活発に使うデータがメモリへ収まらなくなる可能性がある。処理数を増やすことが、かえって読戻しと待ちを増やしていないかを調べる。
容量が大きい装置でも、小さな読書きは遅いことがある
1秒に5120回、それぞれ4KiBを転送すると、合計は20MiB/sになる。同じ回数で一回256KiBなら1280MiB/sである。これは回数と一回の量を掛けた算術であり、同じ装置がどちらも達成できるという意味ではない。
IOPSは一秒当たりのI/O回数、帯域は一秒当たりに運べる量である。同じIOPSでも要求サイズが違えば転送量が変わり、同じ帯域でも小さなI/Oを大量に扱う能力は異なる。容量のTBという数字は、どちらの性能も直接は示さない。1
青葉機材の大きな帳票ファイルを連続して読む処理と、予約レコードを散在する場所から小さく読む処理では、重視する性質が違う。読取り・書込みの比率、ランダムか連続か、同時に出す要求数、耐久化を待つかを揃えて比較する。
待ち要求を多くすれば、装置の並行性を使って完了数を増やせる場合はある。しかし、過剰な待ちは一件の応答を遅くする。高いIOPSだけで、対話操作の時間要件まで満たしたと判断しない。
書込み完了は、どの層の完了か
Linuxカーネルの公開文書は、揮発性の書込みキャッシュを持つ装置が、不揮発媒体へ届く前にI/O完了を返す場合を説明している。OS側は、キャッシュのフラッシュなどを使って必要な永続化を要求する。4
Linuxのfsyncは、ファイルの変更内容や関連メタデータを記憶装置へ同期するためのAPIである。また、ファイル内容の同期だけでディレクトリエントリまで必ず同期されるわけではないこと、エラー結果もあり得ることが文書化されている。5
だから、関数を呼んだだけで成功と扱うのではなく、戻り値やエラーも確認する。逆に、すべての書込みのたびに無条件で同期すれば、必要以上に待ちを増やす場合もある。どの時点で、どの障害に耐える成功を返すかを先に決める。
この説明は、各OSやファイルシステムの違いを一つの手順へ統一するものではない。アプリケーション、ファイルシステム、装置が提供する契約を、その構成で確認するための観点である。
データ本体より先に、回復に必要な記録を残す
予約DBが更新したすべてのデータページを、毎回のコミットで個別に書き切るなら、待ちは大きくなりやすい。WALでは、データページの変更を書き出すより先に、変更を回復するためのログを永続化する。
PostgreSQL 18の公式説明は、この順序によって、データページへまだ反映されていないコミット済み変更を、障害後にログから再実行できることを説明している。6 「本体を全部書いていないから、確定は常に嘘」ということではない。回復に十分な情報を先に残すという設計なのである。
ただし、ログという名前のファイルなら何でもよいわけではない。人が読む操作履歴と、DBMSが必要な順序で耐久化する回復用ログは目的が違う。さらに、同期の設定や装置の保証が変われば、成功後に失い得る範囲も変わる。高速化のために保証を弱めた結果を、同じ耐久性の性能改善として比較しない。
冗長化、接続方式、容量割当てを別々に選ぶ
4TBの同容量ディスクを六台使い、予備・管理領域を無視する単純モデルでは、RAID 5の利用可能容量は20TB、RAID 6は16TB、二台ずつのミラーを束ねるRAID 10は12TBとなる。1
RAID 10では、複数故障へ耐えられるかが、どのミラー組で故障したかによって変わる。同じ組の二台を失えば、その組のデータを失う。二台という数だけを見て、RAID 6の二台故障許容と同じ条件にしない。
これらは冗長化の話である。SANかNASかというアクセス粒度と接続の構成、シンプロビジョニングで実使用に応じて物理容量を割り当てる話は、別の軸になる。NASを選んだからバックアップができたことにはならず、論理容量が余っていても物理容量の枯渇は起こり得る。
青葉機材が守りたいものも分ける。一台の故障中の継続、人の誤削除からの復元、拠点全体を失った場合の回復では、必要な対策が違う。速く書けること、大きく保存できること、後で取り戻せることを、それぞれの条件で確かめる。
知識を答案へ戻す
午前Ⅱ。 キャッシュの層と写像、ミス時の追加時間と総時間、IOPSと帯域、RAIDとバックアップを区別する。容量の式は台数と構成、単位と管理領域の仮定を確認する。
午後Ⅰ。 遅い処理のアクセスパターン、物理容量、耐久化の時点、故障時に残るデータを与件から追う。一般的な「高速SSD」などの名称だけで解決策を決めない。
午後Ⅱ。 保存対象の重要性、性能要件、許容損失、回復手順を構成へ結び付ける。ベンチマーク値と、本番のアクセス条件・永続性の違いを説明する。
立ち止まって考える:保存直後の読戻しが成功し、RAIDもある。それだけで電源断と誤削除に耐えられるか
読戻しは、その時点で参照できる内容を確認した結果である。電源断後に残る層まで同期したかは別に確認する。RAIDは、誤削除を構成要素へ同時に反映してしまう場合があり、過去の時点へ戻すバックアップの代わりにはならない。
出典と照合範囲
[1] コンプリートテキスト第14・15・16・18章、IPA「SAシラバス Ver.5.2」4-7、5-5、8-1、11-3、16-3:記憶階層、ストレージ、容量計画、コミットを出発点とした。配置の小例と数値は独自に作成し、IOPS・帯域、平均時間、理想容量の演算をPythonで確認した。公式シラバス
[2] Linux man-pages, getrusage(2):minor faultとmajor faultにおけるI/Oの有無を参照した。Linuxの測定項目を、すべてのOSで同名・同定義だとはしていない。公開マニュアル
[3] Linux Kernel Documentation, PSI — Pressure Stall Information:資源不足による待ちの時間を観測するという位置付けを参照した。特定の閾値を推奨したり、本事例の実測値を示したりしていない。公式文書
[4] Linux Kernel Documentation, Explicit volatile write back cache control:装置の揮発性キャッシュと、フラッシュ・FUAによる完了条件の制御を参照した。公式文書
[5] Linux man-pages, fsync(2):ファイルの同期、ディレクトリの同期との区別、失敗の扱いを参照した。あらゆるOS・媒体に共通の永続化手順を提示するものではない。公開マニュアル
[6] PostgreSQL 18 Documentation, Write-Ahead Logging:ログ先行の順序と、データページへ未反映の変更を再実行する説明を参照した。バージョンを固定した説明であり、装置や設定を含む実機検証ではない。公式文書