内部構造から学ぶPostgreSQL 設計・運用計画の鉄則 ch10 (高可用化と負荷分散) (1/6)
サーバの役割と呼び名
- 更新可否による分類
- master/primary
- 読み書きできるやつ
- standby/secondary
- プライマリ側のデータ変更を追跡するやつ
- PostgreSQL 9.6までは
slave
だった - PostgreSQL 10から
secondary
- master/primary
- standbyのさらなる分類
- warm standby
- masterに昇格するまでクライアントから接続できないやつ
- hot standby
- master昇格前もクライアントから接続できる
- 読み取りのみ
- master昇格前もクライアントから接続できる
- warm standby
- 実現方法いろいろ
- 公式/実現方法の比較
- Shared Disk Failover
- File System (Block Device) Replication
- 共有ディスク相当の機能をソフトウェアレベルで実装する
- DRBDとか
- 共有ディスク相当の機能をソフトウェアレベルで実装する
- Write-Ahead Log Shipping
- Logical Replication
- PostgreSQL 10からサポートされたやつ
- 物理的なWALそのままではなく、論理的なデータ変更を流す
- Trigger-Based Master-Standby Replication
- Slony-Iとか
- テーブル単位の非同期maser/slaveレプリケーションシステム
- PostgreSQL 9.0でStreaming ReplicationがPostgreSQL本体に搭載されるまで活躍していた
- Slony-Iとか
- Statement-Based Replication Middleware
- Asynchronous Multimaster Replication
- Bucardoとか
- 常には接続されていない、コネクションが遅い場合等、常に同期をとるのが難しい場合に
- 各サーバー独立して動作し、定期的にサーバ間で通信してコンフリクト検出・解決する
- 【所感】gitににてる
- Synchronous Multimaster Replication
- 読み書きサーバーが複数あるやつ
- データ変更を伝播するので、
random()
等の非決定的な関数もだいじょうぶ
- 本章の内容
ストリーミングレプリケーション
- OSS-DB道場10
- OSS-DB道場11
- WALをファイル単位ではなく変更内容(WALレコード)ごとに流すやつ
- れきし
- PostgreSQL 9.0 非同期レプリケーション
- PostgreSQL 9.1 同期レプリケーション
- PostgreSQL 9.2 カスケード, remote_write
- ...
ストリーミングレプリケーションの仕組み
- PITRと同様の原理
- primaryで生成されたWALをsecondaryでリプレイ
WALの特性
- 公式/WALと信頼性
- 性能を担保しつつ永続性を保証するやつ
- 性能
- 永続性
ストリーミングレプリケーションの制限
- WALの特性を利用するので、WALレコードを出力しないunloggedテーブルなどはストリーミングレプリケーションされない
create table
文でunlogged設定可能
Description: define a new table Syntax: CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] table_name ( [ { column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ] | table_constraint | LIKE source_table [ like_option ... ] } [, ... ] ] ) [ INHERITS ( parent_table [, ... ] ) ] [ PARTITION BY { RANGE | LIST | HASH } ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [, ... ] ) ] [ USING method ] [ WITH ( storage_parameter [= value] [, ... ] ) | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACE tablespace_name ]
postgres=# CREATE UNLOGGED TABLE tbl (col int); CREATE TABLE
- unlogged確認
postgres=# SELECT relname,relpersistence FROM pg_class WHERE relname='tbl'; relname | relpersistence ---------+---------------- tbl | u (1 row)
ALTER TABLE
文でLOGGED
/UNLOGGED
切り替え可能
postgres=# ALTER TABLE tbl SET LOGGED; ALTER TABLE postgres=# SELECT relname,relpersistence FROM pg_class WHERE relname='tbl'; relname | relpersistence ---------+---------------- tbl | p (1 row)
Column: pg_resetwalコマンド
- 公式
- WALが壊れた時に実行するやつ
- メジャーバージョンが揃っていること
walsender/walreceiverプロセスの設定方法
- WALをやりとりするプロセス
walsender
on primarywalreceiver
on secondary
- postgresql.confの設定項目
- PostgreSQL11以前のrecovery.confでの設定項目も含まれる
- PostgreSQL12ではrecovery.confがpostgresql.confに統合されたため
- PostgreSQL11以前のrecovery.confでの設定項目も含まれる
#------------------------------------------------------------------------------ # REPLICATION #------------------------------------------------------------------------------ # - Sending Servers - # Set these on the master and on any standby that will send replication data. #max_wal_senders = 10 # max number of walsender processes # (change requires restart) ... # - Master Server - ... # - Standby Servers - # These settings are ignored on a master server. #primary_conninfo = '' # connection string to sending server # (change requires restart) ... #hot_standby = on # "off" disallows queries during recovery
#------------------------------------------------------------------------------ # WRITE-AHEAD LOG #------------------------------------------------------------------------------ # - Settings - #wal_level = replica # minimal, replica, or logical # (change requires restart) ... # - Archiving - #archive_mode = off # enables archiving; off, on, or always # (change requires restart) #archive_command = '' # command to use to archive a logfile segment # placeholders: %p = path of file to archive # %f = file name only # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' # - Archive Recovery - # These are only used in recovery mode. #restore_command = '' # command to use to restore an archived logfile segment # placeholders: %p = path of file to restore # %f = file name only # e.g. 'cp /mnt/server/archivedir/%f %p' # (change requires restart)
- primary側設定項目
postgres=# SELECT name,setting,context,boot_val FROM pg_settings WHERE name IN ('wal_level', 'max_wal_senders'); name | setting | context | boot_val -----------------+---------+------------+---------- max_wal_senders | 10 | postmaster | 10 wal_level | replica | postmaster | replica (2 rows)
- secondary側設定項目
postgres=# SELECT name,setting,context,boot_val FROM pg_settings WHERE name IN ('hot_standby', 'restore_command', 'primary_conninfo'); name | setting | context | boot_val ------------------+---------+------------+---------- hot_standby | on | postmaster | on primary_conninfo | | postmaster | restore_command | | postmaster | (3 rows)
- primary側
pg_hba.conf
設定項目- DATABASE列にreplicationを指定
# Allow replication connections from localhost, by a user with the # replication privilege. local replication all trust host replication all 127.0.0.1/32 trust host replication all ::1/128 trust
walsender/walreceiverプロセスの処理
- secondary側のwalreceiver主導
- secondaryのwalreceiver起動、primaryへ接続要求
- primaryのwalsender起動
- secondaryのwalreceiverはprimaryのwalsenderへWALレコード要求
- primaryのwalsenderはsecondaryのwalreceiverへWALレコード送信
- なので、
max_wal_senders
の許す限り動的にsecondaryを増設できる
可能なレプリケーション構成
- 1:Nのマルチスタンバイ構成
- primary 1 : secondary N
- PostgreSQL 9.2~: カスケード構成
- スタンバイに対してさらにスタンバイ接続
同期/非同期の違い
- clientがprimary serverのWAL処理を待つかどうか
- primaryがsecondaryのWAL処理を待つかどうか
- primaryの
postgresql.conf
のsynchronous_commit
で同期レベルを設定する
postgres=# SELECT name,setting,context,boot_val,enumvals FROM pg_settings WHERE name='synchronous_commit'; name | setting | context | boot_val | enumvals --------------------+---------+---------+----------+------------------------------------------ synchronous_commit | on | user | on | {local,remote_write,remote_apply,on,off} (1 row)
- 同期レベル
設定値 | (a)sync | clientが primary serverの WAL処理を待つか |
primaryが secondaryの WAL処理を待つか |
---|---|---|---|
off | async | 待たない | 待たない |
local | async | 待つ | 待たない |
remote_write | sync | 待つ | 待つ(メモリ書き込みまで) |
on | sync | 待つ | 待つ(ディスク書き込みまで) |
remote_apply | sync | 待つ | 待つ(WAL適用まで) |
- 同期レベル最高の
remote_apply
以外では、WAL適用を待たないことに注意する- secondaryのデータはprimaryのデータと必ずしも同じ状態ではない
- PostgreSQL 9.0でストリーミングレプリケーション搭載時点では非同期だけだった
- PostgreSQL 9.1で同期レプリケーションも搭載
複数のスタンバイがある場合
- どのスタンバイを「同期」として扱うか
- secondaryの
primary_conninfo
で、接続先情報に「ぼくの名前は○○です」という情報を添えておく
primary_conninfo = 'user=postgres port=5432 application_name=sby'
- primaryの
synchronous_standby_names
で設定- reloadで設定反映
- 【所感】せっかくwalreceiver主導でsecondaryを動的に追加できるアーキテクチャなのに、この設定を更新するたびにprimaryのrestartが必要だと台無しだからかな
postgres=# SELECT name,setting,context,boot_val FROM pg_settings WHERE name='synchronous_standby_names'; name | setting | context | boot_val ---------------------------+---------+---------+---------- synchronous_standby_names | | sighup | (1 row)
- 「
sby
sby2
sby3
のうち接続できたもの先頭1つが同期」
synchronous_standby_names = 'sby,sby2,sby3'
- バージョンによって「最初のN個」とか「どれかN個」とかも設定できる
synchronous_standby_names
が空白(デフォルト)だと、いずれも同期として扱わない