repmgrd（repmgrのデーモン）によるフェールオーバ

今回はrepmgrd（repmgrのデーモン）を使用したフェールオーバの設定方法について書きます。

# フェールオーバとは
冗長構成を組んでいるシステムの現用系で異常が発生した場合に、自動で待機系にサービスを切り替え、サービスを継続する仕組みです。

PostgreSQL単独の場合、マスタ・スレーブ構成で冗長化していてもマスタが故障した場合はサービス（更新処理）は停止します。そのため、システムでPostgreSQLを使用するのであれば、[Pacemaker](http://linux-ha.osdn.jp/wp/dl)、[pgpool-II](http://www.pgpool.net/mediawiki/jp/index.php/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8)、repmgr等のクラスタリングソフトと組み合わせて、障害発生時にフェールオーバが行われるようにする必要があります。
（問題があったら気づいたときに復旧するぐらいの要件であれば、クラスタリングは不要ですので要件に応じて、検討する必要があります。）

# 前提条件
- [「記事：repmgrによるPostgreSQLのクラスタリング」](http://qiita.com/U_ikki/items/81ad07e9dc93853bc225)に従って、repmgrの環境構築済みである


前置きが長くなってしまいましたが、ここからフェールオーバを行うための設定と手順について説明します。
フェールオーバをするには、repmgrd（repmgrのデーモン）を使用します。
repmgrdとは、スタンバイノードで動作する管理とモニタリングデーモンです。
※マスタ、スレーブはプライマリ、スタンバイとも言ったりします。（厳密な使い分けはあると思いますが、本書では適宜読み替えてください。）

# 1. 各設定ファイルを修正する

## 1-1. postgresql.confを修正する（マスタ、スレーブで実施）
postgresql.confに以下の内容を追記します。

```~/local/pg952/data/postgresql.conf
shared_preload_libraries = 'repmgr_funcs'
```

## 1-2. repmgr.confを修正する（マスタ、スレーブで実施）
repmgr.confに以下の内容を追記します。


```~/local/pg952/pgsql/etc/repmgr.conf
failover=automatic
promote_command='repmgr standby promote -f ~/local/pg952/pgsql/etc/repmgr.conf'
follow_command='repmgr standby follow -f ~/local/pg952/pgsql/etc/repmgr.conf'
```

# 2. PostgreSQLを起動（マスタ、スレーブで実施）

```
$ pg_ctl -D ~/local/pg952/data start 
```

## 2-1. レプリケーション状態の確認（マスタのみで実施）
起動が終わったら、マスタスレーブ間でレプリケーションが実施されているか統計情報ビュー「pg_stat_replication」を確認してください。

```
$ psql repmgr -c 'SELECT * FROM pg_stat_replication' -U repmgr -x
-[ RECORD 1 ]----+------------------------------
pid              | 23325
usesysid         | 20997
usename          | repmgr
application_name | inu
client_addr      | 192.168.1.2
client_hostname  | 
client_port      | 51083
backend_start    | 2016-06-01 21:35:48.240615+09
backend_xmin     | 
state            | streaming
sent_location    | 0/33000528
write_location   | 0/33000528
flush_location   | 0/33000528
replay_location  | 0/33000528
sync_priority    | 0
sync_state       | async
```

ちゃんとstateが"streaming"になっているので、レプリケーションは開始されていますね。

## 2-2. repmgrでの管理状況の確認（マスタ、またはスレーブで実施）
あと、念のためにrepmgrの管理状況も確認しておきましょう。

```
$ psql repmgr -c 'SELECT * FROM repmgr_test.repl_nodes' -U repmgr
 id |  type   | upstream_node_id | cluster | name |              conninfo               | slot_name | priority | active 
----+---------+------------------+---------+------+-------------------------------------+-----------+----------+--------
  1 | master  |                  | test    | neko | host=neko user=repmgr dbname=repmgr |           |      100 | t
  2 | standby |                1 | test    | inu  | host=inu user=repmgr dbname=repmgr  |           |      100 | t
(2 rows)
```

"type"と"active"を見る限り、こちらも大丈夫そうですね。

# 3. repmgrdの起動（スレーブのみで実施）

```
$ repmgrd -f ~/local/pg952/pgsql/etc/repmgr.conf --verbose -d -p ~/repmgr/repmgr.pid > ~/repmgr/repmgr.log 2>&1
```

repmgrdが起動できているか、repl_eventsテーブルを確認します。

```
$ psql repmgr -c "SELECT * FROM repl_events WHERE event = 'repmgrd_start'" -U repmgr
 node_id |     event     | successful |        event_timestamp        | details 
---------+---------------+------------+-------------------------------+---------
       2 | repmgrd_start | t          | 2016-06-01 21:52:38.552002+09 | 
(1 rows)
```

これでrepmgrdによるフェールオーバの設定は完了です。

# 4. フェールオーバの動作確認
マスタを強制停止し、スレーブが自動でpromoteされるかどうか確認してみます。

```
$ pg_ctl -D ~/local/pg952/data -m immediate stop
```
## 4-1. スレーブのログを確認
スレーブのログを確認をtailコマンド等で確認していると以下のようなログが出力されます。
2016-06-01 22:41:04でマスタとの接続が切れた旨のログが出始めます。
しかし、1分後の2016-06-01 22:42:11にスレーブがpromoteコマンドを受け付けて新マスタに昇格しています。

```~/local/pg952/data/pg_log/postgresql-*.log
2016-06-01 22:41:04.346 JST [20185] FATAL:  could not receive data from WAL stream: server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.

2016-06-01 22:41:04.346 JST [20184] LOG:  invalid record length at 0/33000BF0
2016-06-01 22:41:04.351 JST [22743] FATAL:  could not connect to the primary server: server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.

2016-06-01 22:41:09.354 JST [22746] FATAL:  could not connect to the primary server: could not connect to server: Connection refused
        Is the server running on host "neko" (192.168.1.1) and accepting
        TCP/IP connections on port 5432?
・・・
2016-06-01 22:42:11.666 JST [20184] LOG:  received promote request
2016-06-01 22:42:11.666 JST [20184] LOG:  redo done at 0/33000BB8
2016-06-01 22:42:11.666 JST [20184] LOG:  last completed transaction was at log time 2016-06-01 21:52:38.552805+09
2016-06-01 22:42:11.669 JST [20184] LOG:  selected new timeline ID: 2
2016-06-01 22:42:11.730 JST [20184] LOG:  archive recovery complete
2016-06-01 22:42:11.741 JST [20184] LOG:  MultiXact member wraparound protections are now enabled
2016-06-01 22:42:11.741 JST [20186] LOG:  checkpoint starting: force
2016-06-01 22:42:11.742 JST [20179] LOG:  database system is ready to accept connections
2016-06-01 22:42:11.777 JST [22802] LOG:  autovacuum launcher started
```

## 4-2. repmgrの管理情報を確認する
repmgrの以下の情報を確認してみます。

|テーブル名|概要|
|:---|:---|
|repl_nodes|repmgrで管理しているノードの情報を管理するテーブル|
|repl_events|repmgrのイベント通知を記録するテーブル|

### repl_nodes

```
$ psql repmgr -c "SELECT * FROM repl_nodes" -U repmgr
 id |  type  | upstream_node_id | cluster | name |              conninfo               | slot_name | priority | active 
----+--------+------------------+---------+------+-------------------------------------+-----------+----------+--------
  1 | master |                  | test    | neko | host=neko user=repmgr dbname=repmgr |           |      100 | f
  2 | master |                  | test    | inu  | host=inu user=repmgr dbname=repmgr  |           |      100 | t
(2 rows)
```

id=1のノードの"acrive"がfに変化しており、id=2のノードの"type"がmasterになっています！

### repl_events

```
$ psql repmgr -c "SELECT * FROM repl_events" -U repmgr
 node_id |          event           | successful |        event_timestamp        |                                   details                                    
---------+--------------------------+------------+-------------------------------+------------------------------------------------------------------------------
       1 | master_register          | t          | 2016-05-23 21:34:18.076811+09 | 
       2 | standby_clone            | t          | 2016-06-01 21:35:26.533515+09 | Cloned from host 'neko', port 5432; backup method: pg_basebackup; --force: N
       2 | repmgrd_start            | t          | 2016-06-01 21:52:38.552002+09 | 
       2 | standby_promote          | t          | 2016-06-01 22:42:13.736828+09 | node 2 was successfully promoted to master
       2 | repmgrd_failover_promote | t          | 2016-06-01 22:42:13.767335+09 | node 2 promoted to master; old master 1 marked as failed
(5 rows)
```

マスタの障害（今回は強制停止）を検知して、自動でスレーブを新マスタに昇格してくれることを確認できました。

# 最後に
今回はrepmgrdによるフェールオーバの設定方法と動作確認を行いました。
次はrepmgrdが検知可能な障害はなにか？どういう仕組みで動いているのか？等を確認してみようと思います。