リーダーなしのエラーは-4038であり、4038エラーが発生した場合、以下の2つの可能性があります。
- 現在のリーダーは存在しますが、そのリーダーはこのノードではありません。これは、リーダー切り替え後にロケーションキャッシュが更新されていないために起こる可能性があります。
- 現在のリーダーは存在しません。ログストリームのネットワーク接続性を確認する必要があります。
現在のリーダーが存在する場合
リーダー切り替え後(異常な切り替えやスムーズな切り替えを含む)、ロケーションキャッシュが更新されず、リモート実行時にターゲットノードがもはやリーダーでないため、4038エラーコードが返され、その後ステートメントレベルで再試行されます。これを確認するには、以下の方法があります:
DBA_OB_SERVER_EVENT_HISTORYビューを使用して、実際にリーダー切り替えが発生したかどうかを確認します。- システムログを確認して、ターゲット側が実際に4038エラーコードを返したかどうかを確認します。
# grep 4038 observer.log
[2021-01-21 09:46:31.305260] WARN setup_next_scanner (ob_direct_receive.cpp:292) [15256][YB420B4043DA-0005A535D6FAE816] [lt=2] , ret=-4038
[2021-01-21 09:46:31.305295] WARN [SQL.EXE] setup_next_scanner (ob_direct_receive.cpp:295) [15256][YB420B4043DA-0005A535D6FAE816] [lt=31] while fetching first scanner, the remote rcode is not OB_SUCCESS(ret=-4038, err_msg="", dst_addr=""11.xx.xx.xx:2882"")
[2021-01-21 09:46:31.305302] WARN [SQL.EXE] inner_open (ob_direct_receive.cpp:123) [15256][YB420B4043DA-0005A535D6FAE816] [lt=6] failed to setup first scanner(ret=-4038)
[2021-01-21 09:46:31.305308] WARN [SQL.ENG] open (ob_phy_operator.cpp:138) [15256][YB420B4043DA-0005A535D6FAE816] [lt=4] Open this operator failed(ret=-4038, op_type="PHY_DIRECT_RECEIVE")
[2021-01-21 09:46:31.305314] WARN [SQL.ENG] open (ob_phy_operator.cpp:128) [15256][YB420B4043DA-0005A535D6FAE816] [lt=5] Open child operator failed(ret=-4038, op_type="PHY_ROOT_TRANSMIT")
[2021-01-21 09:46:31.305366] WARN [SERVER] test_and_save_retry_state (ob_query_retry_ctrl.cpp:242) [15256][YB420B4043DA-0005A535D6FAE816] [lt=2] partition change or not master or no response, reutrn it to packet queue to retry(client_ret=-4038, err=-4038, retry_type_=2)
現在のリーダーが存在しない
ログストリームに主が存在するかどうかは、下から上へと見ていくと、選出モジュール、CLOGモジュール、RoleChangeServiceモジュールの3つのモジュールによって決まります。そのため、ログストリームにリーダーが存在しない場合は、下から上へと調査を進めることができます。
- Electionリーダーが存在するかどうかを確認します。
- CLOGリーダーが存在するかどうかを確認します。
- RoleChangeServiceモジュールが正常に動作しているかどうかを確認します。
Election Leaderが存在するか確認する
ログストリームが存在する任意のノードで、システムログを照会することにより現在のElection Leaderを確認できます。例えば、以下のコマンドはテナント1のログストリーム1のElection Leaderを照会します。他のログストリームを照会する場合は、T1とid:1を他のテナントとログストリームのIDに置き換えるだけです。
grep 'T1_.*{id:1}' ./election.log | grep 'dump acceptor info'
そのうち、lease:{owner:"xx.xx.xx.xx:xxxxx"はそのログストリームのElection Leaderを表し、xx.xx.xx.xxはIPアドレスを表し、xxxxxはポート番号を表します。
現在のElection Leaderが存在しない場合、ログストリームのネットワーク接続状態に問題がある可能性が高いです。例えば:
- テナントにメモリがなくメッセージを受信できないため、メッセージを送信することはできますが、一方向のネットワーク接続となります。
- ウェアハウスキューの積み残しによりメッセージを受信できません。
- ノードがStop状態にあるためメッセージを受信できません。
- その他の理由によるネットワーク接続の問題。
さらに、ネットワークインタラクション統計情報に基づいてログストリームレベルのネットワーク接続性を分析する必要があります。以下のコマンドで照会できます。
grep 'T1_.*{id:1}' ./election.log | grep 'dump message count'
このログは、このレプリカと他のレプリカ間のメッセージの送受信記録を集計し、IPとメッセージタイプに分類して、最後のインタラクションのタイムスタンプを記録します。
ネットワーク接続統計データに基づいて、どのノードに異常があるか、問題が送信側にあるのか受信側にあるのかを初期判断し、対応するノードでさらに調査を進めます。
システムログに加えて、内部ビューイベントの照会と分析も可能です。システムテナントのDBA_OB_SERVER_EVENT_HISTORYビューを照会します。
obclient >
SELECT VALUE4,svr_ip,svr_port,event,name3,value3
FROM DBA_OB_SERVER_EVENT_HISTORY
WHERE module="ELECTION" AND value1=$tenant_id AND value2=$ls_id
ORDER BY VALUE4 limit 10;
Election Leaderが存在する場合、次にCLOG Leaderが存在するか確認します。
CLOG Leaderが存在するか確認する
Election Leaderが存在することが確認された場合、次にCLOG Leaderが存在するか調査します。
クラスタが利用可能(SQLクライアントが接続可能)場合、システムテナントのGV$OB_LOG_STATビューを照会します。
obclient>
select * from GV$OB_LOG_STAT
where tenant_id=$tenant_id and ls_id=$ls_id and role="LEADER";
注意
照会結果のノード数がmemberlist内のレプリカ数より少ない場合、特定のログストリームレプリカの状態に異常が発生しており、さらに調査が必要です。
クラスタが利用不可(SQLクライアントが接続できない)場合、システムログを照会します。前のステップで取得したElection Leaderノードで、以下のコマンドを実行します。
grep 'Txxx_.*PALF_DUMP.*palf_id=xxxx,' observer.log.* | less
# ここで、Txxxはtenant_idを表します。例えば、T1001はテナント1001のログを検索します。
# palf_idはログストリームIDを表します。例えば、palf_id=1001はログストリーム1001のログを検索します。
ログ内のroleがFollowerである場合、CLOG Leaderは存在しないことを意味し、CLOG Leaderが存在しない理由をさらに調査する必要があります。
CLOG Leaderが存在する場合、RoleChangeServiceが正常に動作しているか確認します。
RoleChangeServiceが正常に動作しているか確認する
CLOGでロール切り替えが発生すると、RoleChangeServiceのタスクキューに非同期タスクがデリバリされます。RoleChangeServiceのバックグラウンドスレッドはプライマリ/スタンバイ切り替えを実行する役割を担っており、システムログからRoleChangeServiceの動作状況を調査することができます。コマンドは以下のとおりです。
grep 'Txxx_RCS' observer.log rootservice.log.xxxx -h | sort | less
最後のログが
end handle_role_change_event_ではない場合、プライマリ切り替え操作の実行時にフリーズしている可能性があります。最後のログのスタックをさらに確認して問題を特定することができます。最後のログが
end handle_role_change_event_であり、かつCLOGにプライマリが存在する場合、RoleChangeServiceモジュールに異常があるため、さらに調査が必要です。
テナントが無主になる一般的な原因
クロックのずれ
現在の選挙モジュールは、任意の2つのOBServer間のクロックのずれが2秒を超えないことを前提としています。超過した場合、リーダーが存在しない状態になる可能性があります。以下のコマンドでOBServer間のクロック同期を確認できます。
sudo clockdiff $IP
結果としてずれ値が2秒を超える場合、クロックサービスが正常に動作しているかどうかさらに確認する必要があります。一般的なクロックサービスにはNTPやChronyなどが含まれます。
テナント/テーブル/パーティションの削除
特定のテナントまたはテーブル/パーティションが削除された場合、複数のレプリカの削除タイミングが一致しない可能性があるため、リーダーが最後に削除された場合、投票を受け取れないことで再選に失敗し、リース期限切れ時にリーダーが存在しない状態になる可能性があります。
多数派レプリカのダウン
もしレプリカがダウンした場合、通常のレプリカでは多数派を満たせなくなり、リーダーが存在しない状態になります。
ネットワーク問題
多数派のレプリカプロセスがすべて稼働中で、ダウンは発生しておらず、かつリーダーレプリカのシステムログにleader lease is expiredのエラーが表示された場合、リーダーレプリカの再選(自身のリース延長)に失敗したことを意味します。これは、ネットワーク障害(一方向/双方向のネットワーク分離、RPCリクエストの積み残し、RPC遅延)が発生している可能性があり、さらに調査が必要です。
エラーの例は以下のとおりです。
# grep 'leader lease is expired' election.log
[2018-09-27 23:09:04.950617] ERROR [ELECT] run_gt1_task (ob_election.cpp:1425) [38589][Y0-0000000000000000] [log=25]leader lease is expired(election={partition:{tid:1100611139458321, partition_id:710, part_cnt:0}, is_running:true, is_offline:false, is_changing_leader:false, self:"11.xx.xx.xx:2882", proposal_leader:"0.0.0.0", cur_leader:"0.0.0.0", curr_candidates:3{server:"100.xx.xx.xx:2882", timestamp:1538050146803352, flag:0}{server:"11.xx.xx.xx:2882", timestamp:1538050146803352, flag:0}{server:"100.xx.xx.xx:2882", timestamp:1538050146803352, flag:0}, curr_membership_version:0, leader_lease:[0, 0], election_time_offset:350000, active_timestamp:1538050146456812, T1_timestamp:1538069944600000, leader_epoch:1538050145800000, state:0, role:0, stage:1, type:-1, replica_num:3, unconfirmed_leader:"11.xx.xx.xx:2882", takeover_t1_timestamp:1538069933400000, is_need_query:false, valid_candidates:0, cluster_version:4295229511, change_leader_timestamp:0, ignore_log:false, leader_revoke_timestamp:1538069944600553, vote_period:4, lease_time:9800000}, old_leader="11.xx.xx.xx:2882")
システム負荷の高さ
システムのload値が非常に高い場合、リーダーが存在しない状態になる可能性があります。システムコマンドを使用して、対応する時間点でのload値が正常であるかどうか確認できます。
clogディスクの使用率の上限達成
clogディスクの使用率がしきい値(テナント構成パラメータlog_disk_utilization_limit_thresholdによって制御され、デフォルト値は95%)を超えた場合、書き込みが強制的に停止されます。この時点で、そのノード上のレプリカはリーダーに選出されることができません。多数派レプリカが存在するノードすべてでこの状況が発生した場合、クラスタ全体でリーダーが存在しない状態になります。
テナントメモリが上限になる
テナントのMemTableメモリが上限になると、ログの再生を続けることができず、さらにログの回収も不可能になります(回収は再生やダンプに依存します)。そのため、CLOGディスクが上限になるのを防ぐために、テナントメモリが上限になった場合、レプリカはリーダーからのログ受信を続けることが許可されません。もし多数派のフォロワーでテナントメモリが上限になると、リーダーのログ同期が詰まり、多数派に達することができず、クラスタが無主状態になります。
CLOG reconfirm失敗
Electionモジュールが正常に動作し、リーダーが選出されたにもかかわらず、CLOGモジュールでreconfirmが失敗した場合、リーダーは自発的に辞任します。reconfirm失敗の原因をさらに調査する必要があります。
Takeover失敗
CLOG reconfirmが成功すると、takeover状態に入り、RoleChangeServiceモジュールが具体的な就任ロジックを実行します。RoleChangeServiceモジュールが異常動作すると、クラスタが無主状態になります。Takeover失敗の原因をさらに調査する必要があります。
トランザクションコールバック実行異常
リーダーレプリカのトランザクションスライディングウィンドウの左端のCLOGログが一定のしきい値(10秒)を超えても多数派に達せず、スライドアウトしない場合、リーダーは異常に辞任し、クラスタが無主状態になります。
エラー報告例は以下のとおりです。
# grep 'check_leader_sliding_window_not_slide_' observer.log
[2022-11-29 11:19:12.239777] ERROR [CLOG] check_leader_sliding_window_not_slide_ (ob_log_state_mgr.cpp:2243) [7393][0][Y0-0000000000000000-0-0] [lt=66] leader_active_need_switch_(partition_key={tid:1099511627898, partition_id:2, part_cnt:0}, now=1669691952239687, last_check_start_id_time_=1669691939215423, sw max_log_id=16282, start_id=16282) BACKTRACE:0xfbdfc9f 0xfbc93dd 0x55391ef 0x9c0a1f9 0x9af215d 0x532d801 0x532c0ae 0x532bc69 0x532bb4f 0x529b6a6 0x9adee54 0x5522e04 0xfa8d123 0xfa8cf7f 0xfd6284f
さらに調査する項目:
- ローカルCLOGのディスク書き込みが遅い場合は、CLOGディスクの負荷やawaitなどの指標を調査します。
- フォロワーレプリカのディスク書き込みが遅い場合は、上記と同じ方法で調査します。
- リーダーとフォロワー間のネットワークが遅い場合、例えば
packet fly cost too much timeがネットワークパケットの時間消費が非常に大きいことを示しています。