リーダーなしのエラーは-4038です。4038エラーが発生した場合、次の2つの可能性があります。
- 現在のリーダーは存在しますが、そのリーダーが現在のノードではありません。これは、リーダー切り替え後にLocation Cacheが更新されていないためかもしれません。
- 現在のリーダーが存在しません。この場合は、ログストリームのネットワーク接続性を調査する必要があります。
現在のリーダーが存在する場合
リーダー切り替え後(異常な切り替えおよびスムーズな切り替えを含む)にロケーションキャッシュが更新されず、リモート実行時に対象ノードがもはやリーダーでないため、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モジュールに異常があることを示します。さらなる調査が必要です。
テナントが無主になる一般的な原因
クロックのずれ
現在のElectionモジュールは、任意の2つのOBServer間のクロックのずれが2秒を超えないことを前提としています。これを超えるとリーダー不在に陥る可能性があります。以下のコマンドでOBServer間のクロックが同期されているか確認できます。
sudo clockdiff $IP
結果でずれ値が2秒を超えている場合は、クロックサービスが正常に動作しているかさらに確認する必要があります。一般的なクロックサービスには、NTPやChronyがあります。
テナント/テーブル/パーティションの削除
特定のテナントが削除されたり、テーブルやパーティションが削除されたりした場合、複数のレプリカの削除タイミングが一致しない可能性があります。もしLeaderが最後に削除された場合、投票を受け取れないため再選に失敗し、Leaseが期限切れになった際にリーダー不在が発生することがあります。
多数派レプリカのダウン
レプリカがダウンした場合、正常なレプリカでは多数派を維持できず、リーダー不在が発生します。
ネットワーク問題
多数派のレプリカプロセスがすべて存在し、ダウンも発生しておらず、かつLeaderレプリカのシステムログに leader lease is expired エラーが表示された場合、Leaderレプリカの再選(自身のLeaseの延長)に失敗したことを意味します。ネットワーク障害(単方向/双方向のネットワーク分離、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%)を超えると、強制的に書き込みが停止されます。この場合、そのノード上のレプリカはLeaderに選出されることができません。多数派レプリカが存在するノードでこのような状況が発生した場合、クラスタはリーダー不在となります。
テナントメモリ満杯
テナントの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が表示され、ネットワークパケットに時間がかかりすぎる場合。