PostgreSQL 高度技術者育成テキスト ch3 (運用管理) (1/2)
LPI-Japan OSS-DB Gold 認定教材 PostgreSQL 高度技術者育成テキスト
- 作者:河原 翔
- 発売日: 2014/10/27
- メディア: オンデマンド (ペーパーバック)
容量監視
- 下記領域について見積もり・監視を行う
- データベース領域
- WAL領域
- アーカイブWAL領域
データベース領域
- 主にリレーションのデータを格納
- テーブル
- インデックス
- 最も増減がある領域
WAL領域
~9.4
- 昔話
#checkpoint_segments = 3 # in logfile segments, min 1, 16MB each
- WALセグメントひとつあたり16MB
ls -lAh pg_xlog/
total 16M -rw------- 1 postgres postgres 16M 2020-02-28 14:17 000000010000000000000001 drwx------ 2 postgres postgres 4.0k 2020-02-28 14:17 archive_status
- 頭打ちになるサイズ
16MB * (checkpoint_segments * 3 + 1)
- デフォルトの
checkpoint_segments = 3
だと160MB
9.5~
max_wal_size = 1GB min_wal_size = 80MB
- 上限値/下限値をダイレクトに設定できるようになった
アーカイブWAL領域
- 公式/Disk Full Failure
- アーカイブWAL領域がディスクフルになっても即座にPostgreSQLは停止しない
- アーカイブ処理に失敗し続け、WAL領域があふれるとPostgreSQLはPANICする
実測方法
データベース領域
- WAL領域、アーカイブWAL領域
- df/duコマンド
CREATE TABLE tbl (col int); INSERT INTO tbl VALUES (generate_series(1,1000000)); CREATE INDEX myindex ON tbl USING BTREE (col); SELECT pg_database_size('postgres'), pg_relation_size('tbl'), pg_total_relation_size('tbl');
-[ RECORD 1 ]----------+--------- pg_database_size | 66904943 pg_relation_size | 36249600 pg_total_relation_size | 58769408
- tableとindexとを別々に求めて足した値と4ページずれる…?
SELECT pg_total_relation_size('tbl') - (pg_relation_size('tbl') + pg_relation_size('myindex')) as diff;
diff ------- 32768 (1 row)
- と思ったら、VACUUM FULLしたら差分は無くなった
VACUUM FULL tbl; SELECT pg_total_relation_size('tbl') - (pg_relation_size('tbl') + pg_relation_size('myindex')) as diff;
diff ------ 0 (1 row)
テーブル・インデックス容量見積もり
fillfactor
- データ挿入時のページへのデータの詰め具合
- Btreeインデックスのleafについては、昔は50%,90%だけ選べたらしい?
- 今では10から100の任意の値を指定できる
- rootとinternalは70%固定らしい
CREATE INDEX myindex2 ON tbl USING BTREE (col) WITH (fillfactor=70); SELECT relname,reltuples,relpages,reloptions FROM pg_class WHERE relname LIKE 'myindex%';
relname | reltuples | relpages | reloptions ----------+-----------+----------+----------------- myindex | 1e+06 | 2745 | myindex2 | 1e+06 | 3537 | {fillfactor=70} (2 rows)
- fillfactorの小さなインデックスはfillfactorがデフォルト(90%)のものに比べてpage数が多い
テーブルデータの見積もり
\d tbl
Table "public.tbl" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- col | integer | | | Indexes: "myindex" btree (col) "myindex2" btree (col) WITH (fillfactor='70')
- 1行あたり容量
- ラインポインタ: 4バイト
- タプルヘッダ: 23バイト
- タプルデータ: 4バイト
col int
- ページヘッダ 24バイト
- ページあたり行数
(8192 - 24) / (4 + 23 + 4) = 263.48
- 行数1,000,000なのでページ数の見積もりは
1000000 / 263.48 = 3795
- (実際の値はわりとずれている)
SELECT relname,reltuples,relpages FROM pg_class WHERE relname = 'tbl';
-[ RECORD 1 ]---- relname | tbl reltuples | 1e+06 relpages | 4425
SELECT * FROM pgstattuple('tbl2');
-[ RECORD 1 ]------+--------- table_len | 36249600 tuple_count | 1000000 tuple_len | 28000000 tuple_percent | 77.24 dead_tuple_count | 0 dead_tuple_len | 0 dead_tuple_percent | 0 free_space | 125700 free_percent | 0.35
インデックスデータの見積もり
- fillfactorを考慮する
- まず全エントリカバーするのに必要なleaf数を算出する
- ついで、全リーフをカバーするのに必要なroot,internal数を算出する
セキュリティ
- 標準で搭載
- データ暗号化
- 通信経路暗号化
- サーバ認証
- クライアント認証
- 標準で搭載していない
- 監査ログ
- トリガやルールを使って、自前で実現する
- 監査ログ
データ暗号化
pgcryptoの導入
CREATE EXTENSION pgcrypto; SELECT extname,extversion FROM pg_extension;
extname | extversion -------------+------------ plpgsql | 1.0 pgstattuple | 1.5 pgcrypto | 1.3 (3 rows)
汎用ハッシュ関数
- digest
- ハッシュ値を得るやつ
SELECT digest('testdata', 'md5');
digest ------------------------------------ \xef654c40ab4f1747fc699915d4f70902 (1 row)
SELECT hmac('testdata', 'testkey', 'md5');
hmac ------------------------------------ \xe66a491c05c3f2a921ba32c6650369cc (1 row)
パスワードハッシュ化関数
- ソルトつき暗号化
gen_salt(type text [, iter_count integer ]) returns text crypt(password text, salt text) returns text
- つかう
SELECT gen_salt('md5');
gen_salt ------------- $1$HUbvn/DB (1 row)
- 毎回異なるソルトを得る
SELECT gen_salt('md5');
gen_salt ------------- $1$1Q92f5mK (1 row)
- ので、
crypt()
に渡す用と照会用の値が同じになるよう、サブクエリを用いる
CREATE TABLE users(account text, password text, salt text); INSERT INTO users (account, password, salt) SELECT 'testaccount', crypt('testpass', salt), salt FROM (SELECT gen_salt('md5') AS salt) tmp_salt; TABLE users;
-[ RECORD 1 ]-------------------------------- account | testaccount password | $1$.IKYM42v$z6ZXpPR78pXxHM7FIm/lN. salt | $1$.IKYM42v
PGP暗号化関数/対称鍵
- 対称鍵暗号化/復号化
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
- つかう
SELECT pgp_sym_encrypt('testdata', 'testpass');
pgp_sym_encrypt -------------------------------------------------------------------------------------------------------------------------------------------------------- \xc30d04070302889ab5f26b967ad17dd239010dd9c10a1e442c5eafd7f68c111656e737cbaf5055bc8a899a9a3c5349de8a9a58382aac6a14ce70749c979704662f86e569c37bef8c08be (1 row)
SELECT pgp_sym_decrypt('\xc30d040703028df075445a4beff276d23901185f131dcc1d0c5aea1fde529722fbab438b1f30b0de53c059c6c85dabc1c52ff2af30a7e4397cfb152381c7d9769a20fb432296032d4af0', 'testpass');
pgp_sym_decrypt ----------------- testdata (1 row)
- 共通鍵を間違えてみる
SELECT pgp_sym_decrypt('\xc30d040703028df075445a4beff276d23901185f131dcc1d0c5aea1fde529722fbab438b1f30b0de53c059c6c85dabc1c52ff2af30a7e4397cfb152381c7d9769a20fb432296032d4af0', 'ngpass');
ERROR: Wrong key or corrupt data
PGP暗号化関数/公開鍵
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
通信経路暗号化
- 先の「データ暗号化」は、通信経路のデータは平文筒抜け
- SSLを使う
- 公式/SSL-TCP
- 証明書の作り方を教えてくれてたりする
- 公式/SSL-TCP
- DBサーバのような、接続するクライアントが限定されている場合はオレオレ証明書でも問題ない
- SSL有効化方法
- configureオプション
--with-openssl
でビルド postgresql.conf
でssl=on
- reloadで反映
SELECT name,setting,context FROM pg_settings WHERE name='ssl';
name | setting | context ------+---------+--------- ssl | off | sighup (1 row)
pg_hba.conf
でhostssl
ルール設定- これもreloadで反映
監査ログ
- 発行したSQL文をログ出力するやつ
- 特定のテーブルのみ、とか器用なことはできない
#log_statement = 'none' # none, ddl, mod, all
- 特定のテーブルについて何かしたい場合はトリガプロシージャを自分で作り込む
バックアップ/リストア
分類
- オンラインバックアップ
- 論理
pg_dump
,pg_dumpall
/psql
,pg_restore
- 物理
pg_basebackup
- 論理
- オフラインバックアップ
- コールドバックアップ
- レプリケーション as バックアップ
- 操作ミスによるデータ損失の復旧は不可能
pg_basebackupコマンド
-X, --wal-method=none|fetch|stream include required WAL files with specified method
- f/fetch
- バックアップ取得中はWALファイルを転送せず、最後にWALファイルをまとめて転送
- ベースバックアップ中に書き出されるWALファイルがWAL領域から削除される可能性がある
wal_keep_segments
の値を大きくする等の対策を講じること
- s/stream
- WALファイルを随時転送
- 転送用の接続が1本必要
- WALファイルを随時転送