#author("2017-11-23T16:10:53+09:00","default:haikikyou","haikikyou")
#author("2017-11-23T23:34:19+09:00","default:haikikyou","haikikyou")
[[PostgreSQL/Pgpool-II]]

* フェイルオーバー[#geff8edc]

* フェイルオーバーのタイミング [#wd6a49a5]

* フェイルオーバーの内部動作 [#w52db569]

- フェイルオーバー契機が与えられると、フェイルオーバーリクエストが共有メモリ上の待ち行列に書き込まれる。続いて、フェイルオーバー処理依頼のシグナル(SIGUSR1)が親プロセスに送信される。~
&label(warn){参考};[[register_node_operation_request()>https://git.postgresql.org/gitweb/?p=pgpool2.git;a=blob;f=src/main/pgpool_main.c;h=a7a6b32f35b487af5ecd9726b6353d380318f7e7;hb=refs/heads/V3_6_STABLE#l620]] - &size(11){&color(gray){on https://git.postgresql.org/gitweb/?p=pgpool2.git};};
- フェイルオーバー処理はPgpoolの親プロセスで実行され、以下の関数で行われる。~
&label(warn){参考};[[failover()>https://git.postgresql.org/gitweb/?p=pgpool2.git;a=blob;f=src/main/pgpool_main.c;h=a7a6b32f35b487af5ecd9726b6353d380318f7e7;hb=refs/heads/V3_6_STABLE#l1595]] - &size(11){&color(gray){on https://git.postgresql.org/gitweb/?p=pgpool2.git};};

** failoverプロセス概要 [#f5e25664]
failover()関数の処理概要は以下の通りである。(詳細は、ソースコードを参照のこと)

+ 共有メモリの待ち行列にスイッチ中のフラグを立て、待ち行列のリクエスト処理ループに入る。
++ 待ち行列のセマフォのロック。待ち行列にリクエストがなければ、アンロックして終了。
++ 待ち行列からリクエストを取り出し、セフォマのアンロック。
++ リクエストが「CLOSE_IDLE_REQUEST」ならば、すべての子プロセスにSIGUSR1シグナルを送信する。~
(子プロセスは、SIGUSR1シグナルを受信するとアイドル状態のバックエンド接続を閉じる)
++ watchdogが有効ならば、watchdogにフェイルオーバー処理を通知する。
++待ち行列のリクエストごとに以下の分岐
---NODE_UP_REQUESTの場合~
途中
・バックエンドが全てダウンしていないか調べる。~
・バックエンドのステータスをCON_CONNECT_WAITにセットする。~
・リクエストがREQ_DETAIL_UPDATEでなければfailback_commandを実行する。~
---PROMOTE_NODE_REQUESTの場合~
途中
node_idがVALID_BACKENDでなければループをcontinueする。
--- NODE_DOWN_REQUEST && NODE_QUARANTINE_REQUESTの場合~
プライマリノードがダウンした場合など、このステップを通過する。NODE_QUARANTINE_REQUESTは、watchdogでクォラムを組んでいる時のリクエスト種別である。ここで、障害でダウンしたデータベースノードを調べる。
プライマリノードがダウンした場合など、このステップを通過する。NODE_QUARANTINE_REQUESTは、watchdogでクォーラムを組んでいる時のリクエスト種別である。ここで、障害でダウンしたデータベースノードを調べる。
++ 新しいマスタノードを決める。
++ 待ち行列のリクエストごとに以下の分岐~
---ストリーミングレプリケーションかつNODE_UP_REQUESTかつバックエンドが全てダウンしていない場合~
&code(need_to_restart_children = false、partial_restart = false);
---ストリーミングレプリケーションかつ(NODE_DOWN_REQUESTまたはNODE_QUARANTINE_REQUEST)かつREQ_DETAIL_SWITCHOVERでプライマリノードでない場合~
&code(need_to_restart_children = true、partial_restart = true );
---それ以外(''プライマリノードダウンはここ'')~
すべての子プロセスにシグナルSIGQUITが送信される(すべての子プロセスは終了する)。子プロセス再起動のフラグを立てる。~
&code(need_to_restart_children = true、partial_restart = false );
&code(need_to_restart_children = true、partial_restart = false );~
(ユーザーからのリクエストをacceptする子プロセスがいなくなる。)
++ 待ち行列のリクエストがNODE_DOWN_REQUESTの場合、failover_commandに指定されたスクリプトを実行する。新しいプライマリノード候補のpromoteが実行される。
++ 新しいプライマリノードを決める。
++ ストリーミングレプリケーションモードの場合、follow_master_commandを実行する。この動作は、プロセスをforkして子プロセスで実行される。
++ need_to_restart_childrenがtrueであれば、子プロセスの再起動を行なう。
++ need_to_restart_childrenがtrueであれば、子プロセスの再起動を行なう。need_to_restart_childrenがfalseの場合は、リスタートフラグを立てるだけ。(子プロセス中でセッションが終了したタイミングで再起動される。)~
&label(warn){参考};[[check_restart_request()>https://git.postgresql.org/gitweb/?p=pgpool2.git;a=blob;f=src/protocol/child.c;h=859e0befa8b40e165847865a72961cf7c4453fcb;hb=refs/heads/V3_6_STABLE#l295]] - &size(11){&color(gray){on https://git.postgresql.org/gitweb/?p=pgpool2.git};};
++ workerにSIGUSR1シグナル(再起動通知)を送信する。
++ sync_requiredがtrueならば、watchdogのフェイルオーバの終了処理。
+ スイッチフラグを解除。
+ pcpプロセスにSIGUSR2シグナルを送信し、failover/failbackの完了を通知。
+ pcp再起動。


** 障害ケースとプロセス [#q456856c]
*** ケース:プライマリノード障害+fail_over_on_backend_error = onの場合 [#vc89db41]

**** テスト条件 [#ybc0e460]

- プライマリノードダウン
-- &code(pg_ctl -m i -D pgdata stop);
- クライアント
-- psqlで更新クエリを連続実行
- pgpool 3.7RC1
-- num_init_children = 1
-- fail_over_on_backend_error = on
-- health_check_period = 0
- OS
-- Mac OS X
- PostgreSQL
-- 10.0

**** 実行 [#vdb8f39f]

連続クエリ実行中にプライマリノード障害を発生させ、親プロセスにシグナル送信される過程のスタックトレースが以下。~
シグナル送信前にブレークポイントを設定している。

#geshi{{{
* thread #1: tid = 0x89d759, 0x0000000107d9ec63 pgpool`signal_user1_to_parent_with_reason(reason=SIG_FAILOVER_INTERRUPT) + 35 at pgpool_main.c:535, queue = 'com.apple.main-thread', stop reason = breakpoint 24.1
  * frame #0: 0x0000000107d9ec63 pgpool`signal_user1_to_parent_with_reason(reason=SIG_FAILOVER_INTERRUPT) + 35 at pgpool_main.c:535
    frame #1: 0x0000000107d9c4dc pgpool`register_node_operation_request(kind=NODE_DOWN_REQUEST, node_id_set=0x00007fff57e605c0, count=1, flags='\x01') + 460 at pgpool_main.c:508
    frame #2: 0x0000000107d9f458 pgpool`degenerate_backend_set_ex(node_id_set=0x00007fff57e60824, count=1, flags='\x01', error='\0', test_only='\0') + 1720 at pgpool_main.c:1089
    frame #3: 0x0000000107d9ed92 pgpool`degenerate_backend_set(node_id_set=0x00007fff57e60824, count=1, flags='\x01') + 50 at pgpool_main.c:1138
    frame #4: 0x0000000107d9ed54 pgpool`notice_backend_error(node_id=0, flags='\x01') + 148 at pgpool_main.c:988
    frame #5: 0x0000000107dd9ca8 pgpool`new_connection(p=0x00007fc8ec003248) + 792 at pool_connection_pool.c:873
    frame #6: 0x0000000107dd94e1 pgpool`pool_create_cp + 225 at pool_connection_pool.c:248
    frame #7: 0x0000000107dc9c1c pgpool`connect_backend(sp=0x00007fc8ed801f88, frontend=0x00007fc8ed800038) + 44 at child.c:868
    frame #8: 0x0000000107dc6795 pgpool`get_backend_connection(frontend=0x00007fc8ed800038) + 981 at child.c:2326
    frame #9: 0x0000000107dc465a pgpool`do_child(fds=0x00007fc8ebe00620) + 1898 at child.c:337
    frame #10: 0x0000000107d9aac0 pgpool`fork_a_child(fds=0x00007fc8ebe00620, id=0) + 160 at pgpool_main.c:607
    frame #11: 0x0000000107d979c6 pgpool`PgpoolMain(discard_status='\x01', clear_memcache_oidmaps='\0') + 1878 at pgpool_main.c:363
    frame #12: 0x0000000107d95ea8 pgpool`main(argc=9, argv=0x00007fff57e6b7a8) + 2232 at main.c:318
    frame #13: 0x00007fff920465ad libdyld.dylib`start + 1
    frame #14: 0x00007fff920465ad libdyld.dylib`start + 1
}}}

notice_backend_error関数の実行後、子プロセスはabortして終了する。&label(warn){参考};[[pool_connection_pool.c#new_connection()>https://git.postgresql.org/gitweb/?p=pgpool2.git;a=blob;f=src/protocol/pool_connection_pool.c;h=320f76d17aba051cd025b9be8c777f096fecb86e;hb=refs/heads/V3_7_STABLE#l873]]

pgpoolのログは以下のとおりである。

#geshi{{{
2017-11-23 23:11:07: pid 87593: [CHILD:269] LOG:  DB node id: 0 backend pid: 87759 statement: insert into foo_t values(53);
2017-11-23 23:11:07: pid 87593: [CHILD:270] LOCATION:  pool_proto_modules.c:3116
2017-11-23 23:11:07: pid 87593: [CHILD:271] LOG:  DB node id: 0 backend pid: 87759 statement:  DISCARD ALL
2017-11-23 23:11:07: pid 87593: [CHILD:272] LOCATION:  pool_proto_modules.c:3116
2017-11-23 23:11:07: pid 87593: [CHILD:273] LOG:  DB node id: 1 backend pid: 87760 statement:  DISCARD ALL
2017-11-23 23:11:07: pid 87593: [CHILD:274] LOCATION:  pool_proto_modules.c:3116
2017-11-23 23:11:07: pid 87593: [CHILD:275] LOG:  connection closed.
2017-11-23 23:11:07: pid 87593: [CHILD:276] DETAIL:  retry to create new connection pool
2017-11-23 23:11:07: pid 87593: [CHILD:277] LOCATION:  pool_connection_pool.c:149
2017-11-23 23:11:07: pid 87593: [CHILD:278] LOG:  failed to connect to PostgreSQL server by unix domain socket
2017-11-23 23:11:07: pid 87593: [CHILD:279] DETAIL:  connect to "/tmp/.s.PGSQL.11002" failed with error "Undefined error: 0"
2017-11-23 23:11:07: pid 87593: [CHILD:280] LOCATION:  pool_connection_pool.c:522
2017-11-23 23:11:07: pid 87593: [CHILD:281] LOG:  received degenerate backend request for node_id: 0 from pid [87593]
2017-11-23 23:11:07: pid 87593: [CHILD:282] LOCATION:  pgpool_main.c:1053
2017-11-23 23:11:07: pid 87593: [CHILD:283] FATAL:  failed to create a backend connection
2017-11-23 23:11:07: pid 87593: [CHILD:284] DETAIL:  executing failover on backend  <== 子プロセスはabort
2017-11-23 23:11:07: pid 87593: [CHILD:285] LOCATION:  pool_connection_pool.c:876
2017-11-23 23:11:07: pid 87587: [MAIN:17] LOG:  Pgpool-II parent process has received failover request  <== 親プロセスでfailover開始
2017-11-23 23:11:07: pid 87587: [MAIN:18] LOCATION:  pgpool_main.c:1502
2017-11-23 23:11:07: pid 87587: [MAIN:19] LOG:  starting degeneration. shutdown host /tmp(11002)
2017-11-23 23:11:07: pid 87587: [MAIN:20] LOCATION:  pgpool_main.c:1714
2017-11-23 23:11:07: pid 87587: [MAIN:21] LOG:  Restart all children  <== 子プロセスは全てkillされる
2017-11-23 23:11:07: pid 87587: [MAIN:22] LOCATION:  pgpool_main.c:1835
2017-11-23 23:11:07: pid 87587: [MAIN:23] LOG:  execute command: /Users/guest/workspace/pgpool/test/etc/failover.sh 0 /tmp 11002 /Users/guest/workspace/pgpool/test/data0 1 0 /tmp 0 11003 /Users/guest/workspace/pgpool/test/data1
2017-11-23 23:11:07: pid 87587: [MAIN:24] LOCATION:  pgpool_main.c:2795
2017-11-23 23:11:07: pid 87587: [MAIN:25] LOG:  find_primary_node_repeatedly: waiting for finding a primary node
2017-11-23 23:11:07: pid 87587: [MAIN:26] LOCATION:  pgpool_main.c:2967
2017-11-23 23:11:07: pid 87587: [MAIN:27] LOG:  find_primary_node: checking backend no 0
2017-11-23 23:11:07: pid 87587: [MAIN:28] LOCATION:  pgpool_main.c:2910
2017-11-23 23:11:07: pid 87587: [MAIN:29] LOG:  find_primary_node: checking backend no 1
2017-11-23 23:11:07: pid 87587: [MAIN:30] LOCATION:  pgpool_main.c:2910
2017-11-23 23:11:07: pid 87587: [MAIN:31] LOG:  find_primary_node: primary node id is 1
2017-11-23 23:11:07: pid 87587: [MAIN:32] LOCATION:  pgpool_main.c:2940
2017-11-23 23:11:07: pid 87587: [MAIN:33] LOG:  starting follow degeneration. shutdown host /tmp(11002)
2017-11-23 23:11:07: pid 87587: [MAIN:34] LOCATION:  pgpool_main.c:1928
2017-11-23 23:11:07: pid 87587: [MAIN:35] LOG:  failover: 1 follow backends have been degenerated
2017-11-23 23:11:07: pid 87587: [MAIN:36] LOCATION:  pgpool_main.c:1946
=== follow_master_commandを実行するプロセスがforkされる ===
2017-11-23 23:11:07: pid 87587: [MAIN:37] LOG:  failover: set new primary node: 1
2017-11-23 23:11:07: pid 87587: [MAIN:38] LOCATION:  pgpool_main.c:1961
2017-11-23 23:11:07: pid 87587: [MAIN:39] LOG:  failover: set new master node: 1
2017-11-23 23:11:07: pid 87587: [MAIN:40] LOCATION:  pgpool_main.c:1968
=== ここで新しい子プロセスがforkされる ===
failover done. shutdown host /tmp(11002)2017-11-23 23:11:07: pid 87587: [MAIN:41] LOG:  failover done. shutdown host /tmp(11002)
2017-11-23 23:11:07: pid 87587: [MAIN:42] LOCATION:  pgpool_main.c:2074
2017-11-23 23:11:07: pid 87596: [WORKER:1] LOG:  worker process received restart request
2017-11-23 23:11:07: pid 87596: [WORKER:2] LOCATION:  pool_worker_child.c:155
2017-11-23 23:11:07: pid 88001: [UTILITY:1] LOG:  start triggering follow command. <== follow_master_commandが実行される
2017-11-23 23:11:07: pid 88001: [UTILITY:2] LOCATION:  pgpool_main.c:2995
2017-11-23 23:11:07: pid 88001: [UTILITY:3] LOG:  execute command: /Users/guest/workspace/pgpool/test/etc/follow_master.sh 0 /tmp 11002 /Users/guest/workspace/pgpool/test/data0 1 0 /tmp 0 11003 /Users/guest/workspace/pgpool/test/data1
2017-11-23 23:11:07: pid 88001: [UTILITY:4] LOCATION:  pgpool_main.c:2795
2017-11-23 23:11:07: pid 88002: [CHILD:1] LOG:  DB node id: 1 backend pid: 88004 statement: insert into foo_t values(55); <== クエリのリトライ
2017-11-23 23:11:07: pid 88002: [CHILD:2] LOCATION:  pool_proto_modules.c:3116
2017-11-23 23:11:07: pid 88002: [CHILD:3] LOG:  DB node id: 1 backend pid: 88004 statement:  DISCARD ALL
2017-11-23 23:11:07: pid 88002: [CHILD:4] LOCATION:  pool_proto_modules.c:3116
}}}
* 参考リンク [#v65d9c9a]

- [[Pgpool-II内部情報セミナー 第1回>http://www.pgpool.net/pgpool-web/contrib_docs/pgpool-II-internal-1.pdf]] - &size(11){&color(gray){ http://www.pgpool.net/pgpool-web/contrib_docs/pgpool-II-internal-1.pdf };};


トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
目次
ダブルクリックで閉じるTOP | 閉じる
GO TO TOP