クリティカルセクションは、高同時実行システムにおいてパフォーマンスに非常に関連するリソースの一種であり、クリティカルセクションはロックによって保護される必要があります。ここで言うロックとは、ユーザーの意味論上でデータの一貫性を保証するために使用されるロック(悲観的ロックまたは楽観的ロック)ではなく、物理的実装上でクリティカルセクションを保護するためのある種の同期メカニズムを指します。OceanBaseデータベースでは、これをラッチ(Latch)と呼んでいます。ホットスポットとなるクリティカルセクションは、同時アクセス時に競合を引き起こし、作業スレッドが待機状態に入る可能性があります。このような待機状態を記録することは、パフォーマンス最適化にとって重要な指針となります。
ロックの古典的な実装としては、呼び出し元がまずロックの取得を試みます。ロックが取得できない場合、SPIN処理に入り、繰り返しロックの取得を試みます(CPUを早期に放棄して待機状態に入ることを避けるため、短いクリティカルセクションに対して非常に効果的です)。SPIN回数が上限(SPIN上限と呼ばれる)に達しても、呼び出し元が依然としてロックを取得できない場合、WAIT処理に入り、自分自身を待機キューに入れてCPUを譲ります。待機キューはデフォルトでFIFOをサポートしていますが、読み取り優先など他の優先順位戦略もサポート可能です。
OceanBaseデータベースは、すべてのロックイベントに関連する監視情報を表示するための独立したビューを提供しており、現在100種類以上のロックイベントが存在します。ロックイベントは本質的に待機イベントの一種であり、すべてのロックイベントは同一の待機イベントカテゴリ(WAIT_CLASSはCONCURRENCY)に属します。しかし、一般的な待機イベントと比較して、ロックイベントはより多くの監視情報を備えています。各ロックイベントは一つのクリティカルセクションに対応しており、呼び出し元はロックイベントのSPIN回数と呼び出し回数の比率からホットスポットとなるクリティカルセクションを特定し、最適化措置を講じるかどうかを決定できます。設計が適切な並行システムでは、ロックイベントのSPIN回数と呼び出し回数の比率はできるだけ小さい方が望ましいです。
| ビュー | 表示内容 | 備考 |
|---|---|---|
GV$SYSTEM_EVENT |
テナントレベルのロックイベント統計。 | where WAIT_CLASS='CONCURRENCY' and event like 'latch:%' |
GV$SESSION_EVENT |
セッションレベルのロックイベント統計。 | where WAIT_CLASS='CONCURRENCY' and event like 'latch:%' |
GV$SESSION_WAIT |
セッションレベルのロックイベント詳細。 | where WAIT_CLASS='CONCURRENCY' and event like 'latch:%' |
GV$SESSION_WAIT_HISTORY |
セッションレベルのロックイベント詳細履歴。 | where event like 'latch:%' |
GV$LATCH |
ロック呼び出し統計。 | |
ロックイベントは本質的に待機イベントでもあるため、上述の待機イベント関連ビュー(主に待機統計と待機詳細を含む)もロックイベントに適用可能です。クエリ条件にwhere event like 'latch:%'を追加するだけで済みます。例えば、テナントレベルのロック待機イベントを照会する場合は以下のようになります:
obclient> select * from gv$system_event where event like 'latch:%' limit 10;
+--------+-------------+----------+----------+-------------------------------------+---------------+-------------+-------------+-------------+----------------+-------------+----------------------+-------------------+
| CON_ID | SVR_IP | SVR_PORT | EVENT_ID | EVENT | WAIT_CLASS_ID | WAIT_CLASS# | WAIT_CLASS | TOTAL_WAITS | TOTAL_TIMEOUTS | TIME_WAITED | AVERAGE_WAIT | TIME_WAITED_MICRO |
+--------+-------------+----------+----------+-------------------------------------+---------------+-------------+-------------+-------------+----------------+-------------+----------------------+-------------------+
| 1 | xx.xx.xx.xx | 2882 | 15002 | latch: kvcache bucket wait | 104 | 4 | CONCURRENCY | 0 | 0 | 0 | 0 | 0 |
| 1 | xx.xx.xx.xx | 2882 | 15003 | latch: default spin lock wait | 104 | 4 | CONCURRENCY | 103879 | 0 | 7504.0817 | 0.07223867865497358 | 75040817 |
| 1 | xx.xx.xx.xx | 2882 | 15004 | latch: default spin rwlock wait | 104 | 4 | CONCURRENCY | 1608 | 0 | 6.4665 | 0.004021455223880597 | 64665 |
| 1 | xx.xx.xx.xx | 2882 | 15005 | latch: default mutex wait | 104 | 4 | CONCURRENCY | 19210 | 0 | 62.2564 | 0.003240832899531494 | 622564 |
| 1 | xx.xx.xx.xx | 2882 | 15006 | latch: time wheel task lock wait | 104 | 4 | CONCURRENCY | 0 | 0 | 0 | 0 | 0 |
| 1 | xx.xx.xx.xx | 2882 | 15007 | latch: time wheel bucket lock wait | 104 | 4 | CONCURRENCY | 5 | 0 | 0.0084 | 0.00168 | 84 |
| 1 | xx.xx.xx.xx | 2882 | 15008 | latch: election lock wait | 104 | 4 | CONCURRENCY | 0 | 0 | 0 | 0 | 0 |
| 1 | xx.xx.xx.xx | 2882 | 15009 | latch: trans ctx lock wait | 104 | 4 | CONCURRENCY | 1419 | 0 | 3.6988 | 0.002606624383368569 | 36988 |
| 1 | xx.xx.xx.xx | 2882 | 15010 | latch: partition log lock wait | 104 | 4 | CONCURRENCY | 0 | 0 | 0 | 0 | 0 |
| 1 | xx.xx.xx.xx | 2882 | 15011 | latch: plan cache pcv set lock wait | 104 | 4 | CONCURRENCY | 0 | 0 | 0 | 0 | 0 |
+--------+-------------+----------+----------+-------------------------------------+---------------+-------------+-------------+-------------+----------------+-------------+----------------------+-------------------+
10 rows in set (0.05 sec)
ロック(Latch)イベントは、待機統計や待機詳細に加えて、各種ロックの呼び出し回数やSPIN回数なども含まれます。GV$LATCHはこのような情報を記述しており、例えば以下のようになります:
obclient> select * from gv$latch limit 10;
+--------+-------------+----------+------+--------+--------+-------------------------+------+--------------+--------+--------+----------------+------------------+--------------+-----------+
| CON_ID | SVR_IP | SVR_PORT | ADDR | LATCH# | LEVEL# | NAME | HASH | GETS | MISSES | SLEEPS | IMMEDIATE_GETS | IMMEDIATE_MISSES | SPIN_GETS | WAIT_TIME |
+--------+-------------+----------+------+--------+--------+-------------------------+------+--------------+--------+--------+----------------+------------------+--------------+-----------+
| 1 | xx.xx.xx.xx | 2882 | NULL | 0 | 0 | latch wait queue lock | 0 | 223375312970 | 0 | 0 | 0 | 0 | 223375313928 | 0 |
| 1 | xx.xx.xx.xx | 2882 | NULL | 1 | 0 | default spin lock | 0 | 30228076439 | 103935 | 0 | 2248146333 | 38281 | 32837812102 | 702 |
| 1 | xx.xx.xx.xx | 2882 | NULL | 2 | 0 | default spin rwlock | 0 | 167079371683 | 1608 | 0 | 0 | 0 | 167110063485 | 0 |
| 1 | xx.xx.xx.xx | 2882 | NULL | 3 | 0 | default mutex | 0 | 2846874203 | 19153 | 0 | 4140817202 | 0 | 7160839948 | 0 |
| 1 | xx.xx.xx.xx | 2882 | NULL | 4 | 0 | kv cache bucket latch | 0 | 609838658953 | 0 | 0 | 0 | 0 | 609838670960 | 0 |
| 1 | xx.xx.xx.xx | 2882 | NULL | 5 | 0 | time wheel task latch | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | xx.xx.xx.xx | 2882 | NULL | 6 | 0 | time wheel bucket latch | 0 | 23552766799 | 5 | 0 | 0 | 0 | 23552863465 | 0 |
| 1 | xx.xx.xx.xx | 2882 | NULL | 7 | 0 | election latch | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | xx.xx.xx.xx | 2882 | NULL | 8 | 0 | trans ctx latch | 0 | 1421768682 | 1420 | 0 | 2096 | 1130 | 1426816069 | 0 |
| 1 | xx.xx.xx.xx | 2882 | NULL | 9 | 0 | partition log latch | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+--------+-------------+----------+------+--------+--------+-------------------------+------+--------------+--------+--------+----------------+------------------+--------------+-----------+
10 rows in set (0.04 sec)