postgres, wal
WAL
負荷テスト時、書き込み処理が著しく劣化した原因について調査する
- vg1-swap、vg1-root に負荷がかかっている形跡
- free disk space の占有
- postgres.log に大量の checkpoint 作成のログ
その際に、write処理時間が著しく劣化(?)
WAL とは?
WAL (Write-Ahead Logging) は、データベース管理システム(DBMS)における信頼性とデータ保護を目的とした技術です。WAL は以下の仕組みで動作します。
-
トランザクションの順序性の確保: データを直接書き換える前に、変更内容をログファイル(WALファイル)に記録します。このログは、ディスクへの書き込みが行われる前に、まず安全に保管されます。
-
障害回復のサポート: サーバがクラッシュしたり障害が発生しても、WAL に記録されたログを元に、未完了のトランザクションを再適用したり、完了済みのトランザクションを巻き戻すことができます。
-
データの整合性維持: WAL によって、データベースのトランザクションが確実に安全に行われるよう保証されます。すべての変更がログに先に記録されることで、後から復元や再実行が可能になります。
PostgreSQL の場合
PostgreSQL などのデータベースでは、WAL はデータの信頼性と復旧を支える重要な機能です。データベースのパフォーマンスにも影響しますが、耐障害性を高めるための基本的な技術となっています。
WAL の主な利点は、次のような場面でデータを安全に守る点です。
- システムクラッシュ時の復旧
- レプリケーションやバックアップとの統合
WAL は基本的に、データの変更がディスクに反映される前にログに記録するという、信頼性の高い方法です。
pg_walのばしょかくにん
SHOW data_directory;
# '/var/lib/pgsql/data'
サイズ上限の設定値
SHOW wal_keep_size;
# 0
wal_keep_size (integer)
ストリーミングレプリケーションにおいて、スタンバイサーバが過去のファイルセグメントを取得する必要がある場合に備え、pg_walディレクトリに保持しておくファイルセグメントの最小サイズを指定します。 もし送出サーバに接続しているスタンバイサーバがwal_keep_sizeメガバイトを越えて遅延した場合、送出サーバはスタンバイサーバが今後とも必要とするWALセグメントを削除する可能性があります。 この場合、レプリケーション接続は終了させられます。結果として下流に対する接続も結局は終了されることがあります。(しかし、WALアーカイブが使用されていれば、スタンバイサーバはアーカイブからセグメントを取り出し、復旧することができます。)
pg_walに保持され続けるセグメントの最小値のみを設定します。 システムはWALアーカイブのため、またはチェックポイントからの復旧のため、より多くのセグメント保持が必要となることがあります。 もしwal_keep_sizeが(デフォルトの)ゼロの場合、システムはスタンバイサーバのために追加セグメントを保持することはしません。 従って、スタンバイサーバが使用できる古いWALセグメントの数は、直前のチェックポイントの場所とWALアーカイブの状況によって算出されます。 この値が単位無しで指定されると、メガバイトであると見なします。 このパラメータは、postgresql.confファイル、もしくはサーバコマンドラインでのみ設定可能です。
めも
wal_buffers
に関する解説
wal_buffers
は、PostgreSQLのWAL(Write-Ahead Logging)データがメモリ上に一時的に保存されるバッファで、ディスクへの書き込みが効率的に行われるように最適化されています。wal_buffers
に関連する気になる点について、以下で詳細に解説します。
wal_buffers
のサイズを超えた場合のフラッシュについて
1. トランザクション内での書き込みがwal_buffers
のサイズを超えるデータがトランザクション内で書き込まれた場合、WALデータは自動的にディスクにフラッシュされます。具体的には、以下のような動作になります。
-
WALの自動フラッシュ:
wal_buffers
が満杯になると、そのバッファに書き込まれたWALデータはディスクに書き出され、バッファが再利用されます。この動作は、WALバッファが溢れるたびに繰り返されます。 -
トランザクションの進行中: トランザクション内で何度も
wal_buffers
の容量を超える書き込みが発生する場合、その都度ディスクへのフラッシュが発生します。フラッシュが発生するタイミングはトランザクションのCOMMIT
に依存せず、wal_buffers
が超えた時点で即座に行われます。 -
パフォーマンスへの影響: フラッシュが頻繁に発生する場合、ディスクI/Oに負荷がかかり、特に大量のデータを短期間で書き込むトランザクションでは、パフォーマンスの低下が懸念されます。
-
ディスクについての補足: この「ディスク」は、WALファイルの保存先を指します。WALデータは、データベースの永続化先のディスクとは別の場所に保存されることが一般的です。
wal_buffers
が溢れると、WALファイルのディスクにフラッシュされます。
wal_buffers
は別トランザクションと共通か?
2. はい、wal_buffers
はシステム全体で共通のバッファです。つまり、複数のトランザクションが同時に実行されている場合でも、それらは同じwal_buffers
を共有します。
-
マルチトランザクションの処理: 複数のトランザクションからのWALデータが同じバッファに書き込まれるため、大量のトランザクションが同時に発生する場合、
wal_buffers
が溢れる可能性が高くなります。これは、フラッシュ頻度が増加し、ディスクI/Oが増える結果を招きます。 -
共有バッファのメリットとデメリット:
-
メリット: 複数のトランザクションが同じ
wal_buffers
を共有することで、ディスクへの書き込みが効率的に行われ、システム全体のパフォーマンスが向上します。 -
デメリット: トランザクションが急増し、
wal_buffers
が頻繁に溢れる場合、ディスクI/Oがボトルネックとなり、パフォーマンスの低下が懸念されます。
-
メリット: 複数のトランザクションが同じ
wal_buffers
が溢れた場合の挙動と長期間の超過状態の懸念
3. wal_buffers
が溢れた場合や、複数のトランザクションが大量のデータをINSERT
やUPDATE
し続け、長時間にわたってwal_buffers
が超過し続ける状況についての懸念を以下に説明します。
-
wal_buffers
の超過時の挙動:-
wal_buffers
が溢れた場合、WALデータは即座にディスクにフラッシュされます。このフラッシュはトランザクションのCOMMIT
を待たずに実行されるため、バッファの超過が発生するたびにディスクI/Oが発生します。 -
フラッシュ頻度の増加に伴い、ディスクへの書き込みが頻発し、特にディスクI/Oが遅いストレージを使用している場合に、パフォーマンスが低下する可能性があります。
-
-
長時間の
wal_buffers
超過状態の懸念:-
ディスクI/O負荷の増加: 長時間にわたり
wal_buffers
が頻繁に溢れ、ディスクへの書き込みが継続すると、ディスクI/Oが過負荷になり、全体のクエリ処理が遅延する可能性があります。特に、SSDではなくHDDなどのストレージを使用している場合、この影響が顕著に現れる可能性があります。 -
パフォーマンスの低下: ディスクI/Oに負荷がかかることで、クエリの応答時間が長くなり、特に書き込み操作が多いワークロードでは、アプリケーション全体のパフォーマンスに影響が出る可能性があります。WALデータが継続的にフラッシュされることで、CPU負荷やメモリの使用量も増加することがあります。
-
他のプロセスへの影響: ディスクI/OがWALフラッシュに専有されると、他のプロセス(データの読み込みや他のバックグラウンドタスクなど)が遅延する可能性があります。これは、特に書き込み操作が集中しているシステムでは問題となります。
-
改善策
長時間にわたってwal_buffers
が超過し続ける場合、以下のような対策が効果的です。
-
wal_buffers
のサイズを増やす:-
wal_buffers
のデフォルトサイズは一般的に小さめに設定されています。大量のトランザクションや書き込みが頻繁に発生する環境では、wal_buffers
を増やすことでフラッシュ頻度を減らし、ディスクI/O負荷を軽減できます。サイズはシステムのメモリに応じて適切に設定する必要があります。
-
-
ディスクI/Oの最適化:
- 高速なディスク(SSDやNVMe)を使用することで、WALのフラッシュ時にかかる時間を短縮し、全体的なパフォーマンスを向上させることができます。
-
synchronous_commit
の設定変更:- 書き込み処理のパフォーマンスを改善するために、
synchronous_commit
をoff
に設定することで、WALのディスクフラッシュを非同期にし、COMMIT
時のディスクI/O負荷を軽減することができます。ただし、これにより障害発生時のデータ損失リスクが増加するため、要件に応じて調整する必要があります。
- 書き込み処理のパフォーマンスを改善するために、
まとめ
-
WALバッファの超過時:
wal_buffers
が溢れた場合、WALデータはディスクに自動的にフラッシュされます。トランザクションが続いている間でもフラッシュは発生するため、バッファが満杯になるたびにディスクI/Oが発生します。 -
共有バッファ:
wal_buffers
は複数のトランザクションで共有されているため、同時に大量のトランザクションが発生すると、バッファが頻繁に超過しやすくなります。 -
長時間の超過時の懸念:
wal_buffers
が超過し続けると、ディスクI/Oに負荷がかかり、システム全体のパフォーマンスに悪影響を及ぼす可能性があります。wal_buffers
のサイズ調整やディスク性能の向上が必要です。 -
ディスクについての補足: この「ディスク」は、WALファイルの保存先を指し、データベースの永続化先のディスクとは別の場所にWALデータが保存されます。
めも
トランザクションからWAL、チェックポイントまでの時系列(CPU負荷の観点を含む)
トランザクション開始からクエリ実行、WALの書き込み、そしてチェックポイントまでの流れを時系列に沿って整理し、それぞれの操作がどのタイミングで行われるか、またWALに対する負荷や影響、さらにCPU負荷の観点についても解説します。
BEGIN
)
1. トランザクション開始(-
操作: トランザクションが開始される(
BEGIN
)。 - WALとの関係: この時点では、WALには何も記録されません。トランザクション内で行われる変更が、WALに影響を与えます。
- 設定値に依存する項目: 特に関連する設定値はありません。
-
負荷:
- CPU負荷: トランザクション開始時点ではCPU負荷はほぼ発生しません。トランザクション開始時にメモリリソースが確保される程度です。
- ディスクI/O負荷: この時点ではほぼ負荷はありません。
INSERT
、UPDATE
、DELETE
など)
2. クエリ実行(- 操作: データの変更が実行されます。クエリが実行されると、変更内容がメモリ上に反映されます。
-
WALとの関係:
-
WAL書き込み: クエリが実行され、データの変更があると、即座に変更内容がWALに書き込まれます(まずは
wal_buffers
に書き込まれる)。この書き込みは、トランザクションがCOMMIT
されるかROLLBACK
されるかにかかわらず実行されます。つまり、クエリ実行時にWALへの書き込みはCOMMIT
とは無関係です。 - WALに書き込まれた変更内容は、トランザクションが
COMMIT
されれば有効化され、ROLLBACK
されれば無効化されますが、いずれの場合でもWALには書き込まれます。
-
WAL書き込み: クエリが実行され、データの変更があると、即座に変更内容がWALに書き込まれます(まずは
-
設定値に依存する項目:
-
wal_buffers
: WALのバッファサイズ。この値が小さいと、ディスクへのフラッシュが頻繁になりパフォーマンスに悪影響が出る可能性があります。
-
-
負荷:
- CPU負荷: クエリの実行による計算処理やデータの変更に伴い、CPU負荷が発生します。特に、インデックスの更新やテーブルのスキャンが行われる場合にCPU負荷が増加します。
- ディスクI/O負荷: WALバッファに書き込まれたデータがディスクにフラッシュされる場合、ディスクI/Oが発生します。特に、大量のデータを書き込むトランザクションでは、この負荷が顕著になる可能性があります。
3. WALのフラッシュ
-
操作: WALバッファに書き込まれたデータが、特定のタイミングでディスクにフラッシュされます。
fsync
を用いてディスクに確実に書き込むことで、障害時のデータ消失を防ぎます。 -
設定値に依存する項目:
-
synchronous_commit
: トランザクションのCOMMIT
の際、WALがディスクにフラッシュされるかどうかを制御します。on
に設定されている場合、COMMIT
はWALがディスクに書き込まれるまで待機します。off
の場合、フラッシュを待たずに即座にCOMMIT
が完了します。 -
fsync
: WALのフラッシュ処理時にデータをディスクに同期させる設定。off
にすると、書き込みは高速化しますが、障害時にデータの損失リスクがあります。
-
-
負荷:
- CPU負荷: フラッシュ処理自体は主にディスクI/Oに依存するため、CPU負荷は比較的少ないですが、大量のデータが処理される場合に負荷が増えることがあります。
-
ディスクI/O負荷: WALバッファからディスクへの書き込みは、ディスクI/Oを消費します。特に
fsync
操作によるフラッシュが頻繁に発生すると、ディスクI/Oの負荷が高まります。
COMMIT
4. トランザクションの-
操作: トランザクションが終了し、データの変更が確定されます(
COMMIT
)。 -
WALとの関係:
COMMIT
時に、WALに書き込まれたトランザクションの変更内容がディスクにフラッシュされます。これは、トランザクションの確定に不可欠なプロセスであり、ここでWALの同期が完了していないと、障害時にデータが失われる可能性があります。 -
設定値に依存する項目:
-
synchronous_commit
:COMMIT
時にWALがディスクにフラッシュされるタイミングを制御します。on
の場合、WALが確実にディスクに書き込まれるまでCOMMIT
が完了しません。off
にすると、ディスクに書き込まれる前にCOMMIT
が終了し、パフォーマンスは向上しますがデータ損失のリスクが高まります。
-
-
負荷:
-
CPU負荷:
COMMIT
の処理はCPUに大きな負荷をかけませんが、大量のトランザクションが同時にCOMMIT
されると、負荷が高くなる可能性があります。 -
ディスクI/O負荷:
COMMIT
が完了するまでの間にWALのフラッシュが必要になるため、ディスクI/Oに負荷がかかります。
-
CPU負荷:
ROLLBACK
5. トランザクションの-
操作: トランザクションが取り消され、変更内容が破棄されます(
ROLLBACK
)。 -
WALとの関係:
-
WALの挙動:
ROLLBACK
された場合でも、WALにはクエリ実行時に書き込まれた変更が記録されています。しかし、ROLLBACK
時にPostgreSQLはその変更を適用せず、実際のデータファイルへの反映は行われません。つまり、WALに記録されたデータが無効化され、トランザクションが取り消されたという記録だけが残ります。
-
WALの挙動:
- 設定値に依存する項目: 特に影響する設定はありません。
-
負荷:
-
CPU負荷:
ROLLBACK
そのものの処理には比較的低いCPU負荷しかかかりませんが、トランザクションが大規模である場合、無効化される操作が多いほど負荷が増える可能性があります。 -
ディスクI/O負荷:
ROLLBACK
された場合でもWALは書き込まれるため、ディスクI/Oの負荷が発生する場合があります。ただし、実際のデータファイルには反映されないため、負荷は低めです。
-
CPU負荷:
6. WALのアーカイブ(任意)
- 操作: WALのアーカイブが有効な場合、一定量のWALデータがディスクに書き込まれた後、アーカイブコマンドが実行され、WALセグメントが別の場所に保存されます。
-
設定値に依存する項目:
-
archive_mode
: WALのアーカイブを有効にするかどうか。 -
archive_command
: WALアーカイブの方法を指定するコマンド。
-
-
負荷:
- CPU負荷: アーカイブ処理自体は主にディスクI/Oに依存しますが、アーカイブ時に多くのWALデータを処理する場合にはCPU負荷が発生します。
- ディスクI/O負荷: アーカイブの際に、WALセグメントを別のストレージやリモートのバックアップ先にコピーするため、ディスクI/Oやネットワーク帯域を使用します。
CHECKPOINT
)
7. チェックポイント(- 操作: チェックポイントは、WALに記録されたデータをディスクの実際のデータファイルに反映させるプロセスです。チェックポイントが発生すると、WALに記録された変更内容がディスクのデータファイルに書き出され、以降WALの古いデータが削除されます。これにより、障害発生時のリカバリ時間が短縮されます。
-
設定値に依存する項目:
-
checkpoint_timeout
: チェックポイントが実行される時間間隔を設定します。これが短いと頻繁にチェックポイントが発生し、ディスクI/Oが増加します。 -
checkpoint_completion_target
: チェックポイントの処理をどの程度分散して実行するかを設定します。この値が高いと、チェックポイント処理を分散して実行し、ディスクI/Oのピークを避けます。 -
max_wal_size
: WALファイルの総サイズがこの値に達すると、強制的にチェックポイントが発生します。
-
-
負荷:
- CPU負荷: チェックポイント処理にはCPUも使用されますが、主にディスクI/Oがボトルネックになることが多いです。CPU負荷は、変更データの圧縮や同期などの処理によって増加します。
- ディスクI/O負荷: チェックポイントはWALからディスクへの大量のデータ書き込みを伴うため、ディスクI/Oに大きな負荷がかかります。特に、WALサイズが大きくなると、チェックポイント時にディスクI/Oのピークが発生します。
まとめ
ステージ | タイミング | 主要設定値 | 負荷がかかる操作 |
---|---|---|---|
トランザクション開始 |
BEGIN コマンド |
なし | ほぼ負荷なし |
クエリ実行 |
INSERT 、UPDATE 、DELETE など |
wal_buffers |
CPU負荷、WAL書き込みのディスクI/O負荷 |
WALのフラッシュ | クエリ実行後、COMMIT 前 |
synchronous_commit 、fsync
|
ディスクI/O負荷、CPU負荷は比較的少ない |
トランザクションのCOMMIT |
COMMIT 時 |
synchronous_commit |
ディスクI/O負荷、CPU負荷は少ないが同時に大量のCOMMIT がある場合は増加する |
トランザクションのROLLBACK |
ROLLBACK 時 |
特になし | CPU負荷は少ないがトランザクションが大きい場合増加、WALは書き込まれる |
WALのアーカイブ | WALファイルのローテーション時 |
archive_mode 、archive_command
|
ディスクI/Oおよびネットワーク負荷、CPU負荷も発生する可能性 |
チェックポイント | 一定間隔、またはWALサイズ超過時 |
checkpoint_timeout 、checkpoint_completion_target 、max_wal_size
|
ディスクI/O負荷、CPU負荷も増加する可能性あり |
追加の重要ポイント
-
クエリ実行時にWALに書き込まれる内容は
COMMIT
されるかどうかに関係なく書き込まれるため、クエリ実行のたびにWALには負荷がかかります。 -
ROLLBACK
された場合もWALには記録されるが、そのデータは実際のデータファイルには反映されないため、実際のディスクへの書き込み負荷は少ないです。ただし、トランザクションが大規模である場合、無効化されたWALの記録も多くなる可能性があります。 - CPU負荷の考慮: クエリ実行やチェックポイント処理はCPUにも負荷がかかります。特に、大量のデータを処理するクエリやインデックスの更新が絡む場合、CPU負荷が増加し、パフォーマンスに影響を与える可能性があります。
監視
sdaってなに
sda
とは
sda
は、Linuxシステムにおけるディスクデバイスの名前を指します。
具体的には、sda
は SCSI(Small Computer System Interface)や SATA(Serial ATA)ドライブなど、通常のハードディスクやSSDを示すための名前であり、システムで最初に検出されたディスクデバイスに対して割り当てられます。
デバイス命名の例
- sda: 一番目のディスクデバイス(通常、最初のSCSIまたはSATAディスク)
- sdb: 二番目のディスクデバイス
- sdc: 三番目のディスクデバイス
/dev/sda
というパスで参照されることが多く、sda1
, sda2
のようにパーティションを持つ場合もあります。
例
-
/dev/sda
: 最初に検出されたディスクデバイス -
/dev/sda1
:sda
上の最初のパーティション -
/dev/sda2
:sda
上の二番目のパーティション
まとめ
-
sda
は、システム内のディスク(HDDやSSDなど)のうち最初に認識されたものを指します。 -
sda1
,sda2
などは、sda
上のパーティションです。