サーバの役割と呼び名
-
更新可否による分類
-
master/primary
- 読み書きできるやつ
-
standby/secondary
- プライマリ側のデータ変更を追跡するやつ
- PostgreSQL 9.6までは
slave
だった - PostgreSQL 10から
secondary
-
-
standbyのさらなる分類
-
warm standby
- masterに昇格するまでクライアントから接続できないやつ
-
hot standby
-
master昇格前もクライアントから接続できる
- 読み取りのみ
-
-
-
実現方法いろいろ
- 公式/実現方法の比較
-
Shared Disk Failover
-
プライマリとセカンダリでデータベースクラスタを共有するやつ
- ネットワークストレージデバイスとかで
-
プライマリ稼働中はセカンダリは停止していること
- 【所感】postmaster.pidがあるからかな
-
-
File System (Block Device) Replication
-
共有ディスク相当の機能をソフトウェアレベルで実装する
- DRBDとか
-
-
Write-Ahead Log Shipping
- PITRと同様の原理でのレプリケーション
-
WALの処理は同期/非同期で行うことができる
- 後述
-
データベースクラスタ全体についてレプリケーションする
- テーブル単位とかはできない
-
実装
- file-based log shipping
- streaming replication
-
Logical Replication
- PostgreSQL 10からサポートされたやつ
- 物理的なWALそのままではなく、論理的なデータ変更を流す
-
Trigger-Based Master-Standby Replication
-
Slony-Iとか
- テーブル単位の非同期maser/slaveレプリケーションシステム
- PostgreSQL 9.0でStreaming ReplicationがPostgreSQL本体に搭載されるまで活躍していた
-
-
Statement-Based Replication Middleware
- SQLクエリをミドルウェアでinterceptして、masterとsecondaryへクエリを流す
-
各サーバーが独立してSQLを実行するので、非決定的な関数は、サーバーごとに異なる値になる
random()
CURRENT_TIMESTAMP
-
Asynchronous Multimaster Replication
- Bucardoとか
- 常には接続されていない、コネクションが遅い場合等、常に同期をとるのが難しい場合に
- 各サーバー独立して動作し、定期的にサーバ間で通信してコンフリクト検出・解決する
- 【所感】gitににてる
-
Synchronous Multimaster Replication
- 読み書きサーバーが複数あるやつ
- データ変更を伝播するので、
random()
等の非決定的な関数もだいじょうぶ
-
本章の内容
- ストリーミングレプリケーション for 高可用化
- ロジカルレプリケーション for 負荷分散
ストリーミングレプリケーション
- 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のみを同期書き込みする
- 遥かに低コスト
-
-
永続性
- リカバリ時には、必要なLSN位置からWALレコードを順にリプレイしてロールフォワードする
-
LSN: Log Sequence Number
- 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に統合されたため
-
#------------------------------------------------------------------------------
# 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
が空白(デフォルト)だと、いずれも同期として扱わない