SQLおよびトランザクションリクエストを処理するスレッドはワーカースレッドとも呼ばれ、テナントごとに割り当てられます。つまり、各テナントには独自のSQL/トランザクションワーカーが存在します。
マルチテナントスレッドプール
スレッドプールの概要
マルチテナントは1つの大きなスレッドプールを共有し、各テナントはそのスレッドプールからワーカースレッドを申請します。スレッドプールはマルチテナントに従って初期化および破棄され、マルチテナントが初期化される際にはあらかじめ一定数のスレッドを予約します。その後、テナントの実行中にもスレッドプールを動的に拡張できます。
初期のスレッドプールサイズは、observerノードのCPU数、システムテナントの予約スレッド数、仮想テナントの予約スレッド数に関連しており、一部は構成パラメータで設定可能です。その後のスレッドプールの拡張時のスレッド数の上限は、OBServerノードのスレッド数上限とマルチテナントのスレッド数上限によって共同で制限され、構成パラメータで設定可能です。
スレッドプール関連の構成パラメータ
_ob_max_thread_num
OBServerノードのスレッド数上限を決定します。
デフォルト値は9999で、値の範囲は[0, 10000)です。動的に反映されません。
server_cpu_quota_min
システムテナントの最小仮想CPU数を決定します。マシンの物理CPUとは直接関係なく、マルチテナントスレッドプールの初期サイズにのみ影響します。
デフォルト値は0で、値の範囲は[0, 16]です。動的に反映されます。
server_cpu_quota_max
システムテナントの最大仮想CPU数を決定します。マシンの物理CPUとは直接関係なく、マルチテナントスレッドプールの上限サイズにのみ影響します。
デフォルト値は0で、値の範囲は[0, 16]です。動的に反映されます。
election_cpu_quota
electionテナントの仮想CPU数を決定します。マシンの物理CPUとは直接関係なく、マルチテナントスレッドプールの初期サイズと上限サイズにのみ影響します。
デフォルト値は3で、値の範囲は[0, 16]です。動的に反映されません。
location_cache_cpu_quota
location cacheテナントの仮想CPU数を決定します。マシンの物理CPUとは直接関係なく、マルチテナントスレッドプールの初期サイズと上限サイズにのみ影響します。
デフォルト値は5で、値の範囲は[0, 16]です。動的に反映されません。
テナントスレッド
テナントスレッド構成
単一テナントのスレッドには、ネストリクエストを処理するための7つの専用スレッドと、通常のリクエストを処理するための複数の汎用スレッドが含まれます。スレッドはアクティブまたはスホートの2つの状態になり得ます。ネストリクエスト専用スレッドは外部からほとんど認識されないため、以下の説明では汎用スレッドのみを対象とします。
アクティブスレッド数の概念
アクティブスレッドとは、正常にリクエストを処理できるスレッドを指し、スホートスレッドと区別されます。アクティブスレッド数は、単一テナントのCPU使用率を制限するために使用されます。テナントが実行されている間、アクティブスレッド数は一定に保たれ、テナントのアクティブスレッド数は構成パラメータとユニット仕様によって共同で決定されます。アクティブスレッド数 = unit_min_cpu × cpu_quota_concurrency。
大規模クエリのスレッドスホートロジック
ユーザーがOBServerノードに送信するSQL文は、大まかに2つのカテゴリに分類できます。1つはデータへのアクセスや操作量が少ないため、実行が非常に速いものです。もう1つは、大量のデータにアクセスしたり、大量のデータを書き込んだりする必要があるため、実行に時間がかかるものです。後者の時間のかかるSQL文を大規模クエリと呼びます。
大規模クエリの特別な処理は、直感的なユーザー効用仮説に基づいており、ユーザー数への影響と遅延のQoS(Quality of Service)要件から合理的に推測されます。1000個の小規模クエリが遅延する影響は、1個の大規模クエリが遅延する影響よりもはるかに大きいということです。言い換えれば、1秒のCPU時間を1個の大規模クエリの処理に費やすよりも、同じCPU時間を1000個の小規模クエリの処理に使った方が良いということです。
リクエストが大規模クエリと判断される条件は、処理時間が大規模クエリのしきい値を超えることです。このしきい値は構成パラメータで調整可能です。
テナントスレッド内で大規模クエリと判断されたリクエストを保持しているスレッドの一部は、直接実行権を得ることができ、残りのスレッドはスホートして待機する必要があります。実行権を得られるスレッドの割合は、構成パラメータによって決定されます。
最大スレッド数の概念
テナントのアクティブスレッド数を一定に保ちつつ、大規模クエリスレッドのスホート発生を考慮するため、テナントは動的にマルチテナントスレッドプールからスレッドを申請する必要があります。最大スレッド数は、単一テナントのメモリオーバーヘッドを制限するために使用され、各テナントが保持できる最大スレッド数は構成パラメータとユニット仕様によって共同で決定されます。最大スレッド数 = unit_max_cpu × workers_per_cpu_quota。
関連構成パラメータ
cpu_quota_concurrency
テナントのアクティブスレッド数とテナントユニット仕様の倍数関係を決定します。
デフォルト値は4で、値の範囲は[1, 20]で、動的に有効になります。
workers_per_cpu_quota
テナントの最大スレッド数とテナントユニット仕様の倍数関係を決定します。
デフォルト値は10で、値の範囲は[2, 20]で、動的に有効になります。
large_query_worker_percentage
テナントスレッド内で大規模クエリの実行権を持つスレッドの割合を決定します。
デフォルト値は30で、値の範囲は[0, 100]で、動的に有効になります。
large_query_threshold
リクエストが大規模クエリと判断される処理時間のしきい値です。
デフォルト値は5秒で、値の範囲は[1ms, +∞]で、動的に有効になります。
構成パラメータの確認および変更方法については、パラメータの設定を参照してください。
ログ診断
grep 'dump tenant info' observer.log* コマンドを使用すると、テナントのワーカースレッド数やリクエストキュー状況などを確認できます。例:
grep 'dump tenant info.tenant={id:1002' log/observer.log* | sed 's/,/,\n/g'
[2022-07-20 14:55:40.774143] INFO [SERVER.OMT] run1 (ob_multi_tenant.cpp:1993) [80700][MultiTenant][T0][Y0-0000000000000000-0-0] [lt=621]
dump tenant info(tenant={id:1002, //テナントID
tenant_meta:{unit:{tenant_id:1002, // tenant_metaはテナントメタデータであり、unit構成情報、SuperBlock、およびcreate_statusが含まれます
unit_id:1001, //unit ID
has_memstore:true, // MemTableがあるかどうか
unit_status:"NORMAL", //unitのステータス:UNIT_NORMAL/UNIT_MIGRATE_IN/UNIT_MIGRATE_OUT/UNIT_MARK_DELETING/UNIT_WAIT_GC_IN_OBSERVER/UNIT_DELETING_IN_OBSERVER/UNIT_ERROR_STAT
config:{unit_config_id:1003, // unitの設定ID
name:"2c2g", //unit設定の名前
resource:{min_cpu:2, //unit設定の最小CPU数
max_cpu:2, // unit設定の最大CPU数
memory_size:"1.5GB", // unit設定のメモリサイズ
log_disk_size:"5.4GB", // unit設定のログディスクサイズ
min_iops:20000, // unit設定の最小ディスクIOPS
max_iops:20000, // unit設定の最大ディスクIOPS
iops_weight:2}}, // unit設定のIOPS重み
mode:1, // CompatMode 0:MYSQL 1:ORACLE
create_timestamp:1658298418435426, // unitの作成時間
is_removed:false}, // このunitが削除されたかどうか
super_block:{tenant_id:1002, // ObTenantSuperBlock情報
replay_start_point:ObLogCursor{file_id=1, // テナントslogのログ再生ポイント
log_id=440,
offset=343322},
ls_meta_entry:[140](ver=0, // テナントls metaのslogチェックポイントの入口点
mode=0,
seq=139),
tablet_meta_entry:[141](ver=0, // テナントtablet metaのslogチェックポイントの入口点
mode=0,
seq=140)},
create_status:1}, // テナントの作成ステータス:CREATING = 0,CREATE_COMMIT=1,CREATE_ABORT=2,DELETING=3,DELETE_COMMIT=4
unit_min_cpu:"2.000000000000000000e+00", //最小CPUコア数、保証提供
unit_max_cpu:"2.000000000000000000e+00", //最大CPUコア数、制限上限
slice:"0.000000000000000000e+00",
slice_remain:"0.000000000000000000e+00",
token_cnt:8, //スケジューラが割り当てたトークン数、1トークンは1ワーカースレッドに変換されます
sug_token_cnt:8,
ass_token_cnt:8, //テナントが現在確認したトークン数(token_cntに基づいて確認、通常は両者が等しい)
lq_tokens:2, //Large Queryトークンの個数、token_cntに大リクエスト比率を乗じて設定
used_lq_tokens:0, //現在LQ Tokenを保持しているWorker数
stopped:false, //テナントunitが削除中かどうか
idle_us:6076629, //1ラウンド(10秒)におけるワーカースレッドのアイドル総時間、いわゆるアイドルは実際には待機キューの時間のみをカウント
recv_hp_rpc_cnt:1, //テナントが累計で受け取った異なるレベルのRPCリクエスト数、hp(High)、np(Normal)、lp(Low)
recv_np_rpc_cnt:5,
recv_lp_rpc_cnt:0,
recv_mysql_cnt:24, //テナントが累計で受け取ったMySQLリクエスト数
recv_task_cnt:1, //テナントが累計で受け取った内部タスク数
recv_large_req_cnt:0, //テナントが累計で予測した大リクエスト数、増加のみでリセットされない。実際には再試行時に増加します。
tt_large_quries:0, //テナントが累計で処理した大リクエスト数、増加のみでリセットされない。実際にはチェックポイントチェック時に増加します。
pop_normal_cnt:1024555,
actives:8, //アクティブなワーカースレッド数、通常はworkersと等しく、その差には以下が含まれます:テナントワーカースレッドキャッシュ+ワーカースレッド付きの大リクエストキャッシュ
workers:8, //テナントが保持するワーカースレッド数、実際にはworkers_というリストのサイズです。
nesting workers:7, //テナントが保持するネストリクエスト専用スレッド数、合計7つのスレッドが7つのネストレベルに対応します。
lq waiting workers:0, //大規模クエリと判断され、スケジューリングを待機しているワーカースレッド
req_queue:total_size=0 queue[0]=0 queue[1]=0 queue[2]=0 queue[3]=0 queue[4]=0 queue[5]=0 queue[6]=0 queue[7]=0 , //異なる優先順位のワーカーキュー、数字が小さいほど優先順位が高い
large queued:0, //現在予測された大リクエストの個数
multi_level_queue:total_size=0 queue[0]=0 queue[1]=0 queue[2]=0 queue[3]=0 queue[4]=0 queue[5]=0 queue[6]=0 queue[7]=0 , //ネストリクエストを格納するワーカーキュー、1~7は7つのネストレベルに対応します(queue[0]は一時的に使用せず、queue[5]もinnersqlリクエストを格納します)。
recv_level_rpc_cnt:cnt[0]=0 cnt[1]=0 cnt[2]=0 cnt[3]=0 cnt[4]=0 cnt[5]=0 cnt[6]=0 cnt[7]=0 ,
group_map:group_id = 1, //group_mapの後に各group_idに対応するgroupのスレッドとキュー状況が続きます
queue_size = 0, //groupキューのキュー状況
recv_req_cnt = 13526, //groupが累計でキューにプッシュしたリクエスト数
pop_req_cnt = 13526, //groupスレッドが累計でポップしたリクエスト数
token_cnt = 2, //groupが割り当てたトークン数、1トークンは1ワーカースレッドに変換されます
min_token_cnt = 2,
max_token_cnt = 2,
ass_token_cnt = 2 , //groupが現在確認したトークン数(token_cntに基づいて確認、通常は両者が等しい)
rpc_stat_info: pcode=0x150a:cnt=1489 pcode=0x150b:cnt=1091}) //テナントが一定時間内に受け取った最も多いRPC pcode、統計期間は10秒で、上位5つを表示