CPU はデータベースの中核となるリソースであり、日常の運用において主要な監視対象です。CPU の使用率が過度に高くなると、アプリケーションの応答時間が長くなったり、サービスの速度が低下したりする可能性があります。深刻な場合には、データベースインスタンスがハングアップしたり、高可用性の問題が発生したりして、本番ワークロードに重大な影響を及ぼすことがあります。したがって、CPU 使用率には安全なしきい値を設定し、それを超えた場合には予期せぬ深刻な事態を避けるため、直ちに対処する必要があります。
ビジネスの成長に伴う CPU 使用率
ビジネスが成長するにつれて、現在のクラスター仕様では不足することがあります。パフォーマンスチャートでは、通常、QPS や IOPS などのメトリクスが、CPU 使用率のトレンドと同様のパターンで上昇傾向を示します
CPU がボトルネックになっている場合、クラスター仕様がビジネストラフィックに対して不十分である可能性が高いです。この問題を解決するには、データベースクラスターに読み取り専用ノードを追加するか、クラスター仕様をスケールアップしてください。
データベースクラスターに接続できない場合や、実行中の DML ステートメントが失敗した場合は、現在のクラスター仕様の CPU リソースがワークロードに対して十分であるかを確認してください。CPU リソースが不十分であることが確認された場合は、システムの安定性を維持するために、速やかにクラスターをスケールアップしてください。
ワークロードの大部分が読み取りリクエストで構成されている場合は、読み取り専用ノードを追加してクラスターをスケールアウトし、読み取りトラフィックを分散させることができます。詳細については、「ノードの追加と削除」をご参照ください。
ワークロードの大部分が書き込みリクエストである場合、読み取り専用ノードを追加してもパフォーマンスは向上しません。この場合は、例えば 4 コアから 8 コアの仕様にアップグレードするなど、クラスター仕様を手動でスケールアップする必要があります。
CPU 使用率の高さのトラブルシューティング
CPU 使用率の予期せぬ上昇のトラブルシューティングは複雑になる場合があります。このトピックでは、スロークエリ、アクティブスレッド数の多さ、不適切なカーネル設定、システムのバグなど、いくつかの一般的な原因について説明します。
スロークエリ
CPU 使用率の高さは、多くの場合、非効率な SQL ステートメントが原因で発生し、スロークエリやアクティブスレッドの蓄積につながります。しかし、まずスロークエリが CPU 使用率の高さの根本原因であるか、あるいは別のリソースボトルネックがクエリを遅くし、間接的に CPU 使用率を増加させているのかを判断する必要があります。
PolarDBコンソールで の順に移動すると、スロークエリを表示できます。スローログの詳細 タブで、[スキャンされた行数] の値が [返された行数] の値より大幅に大きい場合、スロークエリが高い CPU 使用率の原因であることを示しています。
この分析は TP クエリに焦点を当てているため、count クエリは除外されます。一部の AP クエリも、[スキャンした行数] が非常に多くなることがあります。
TP クエリは、ごく少量のデータの読み取りと書き込みを伴います。クエリが大量のデータをスキャンする場合、インデックスが欠落している可能性が非常に高いです。たとえば、スロークエリリストのクエリで 10,000 行以上がスキャンされたにもかかわらず、返された行が 1 行のみであった場合、name 列にインデックスが欠落していることを明確に示しています。
SELECT * FROM table1 WHERE name='testname';次のステートメントを使用して、name 列にインデックスが存在するかどうかを確認できます。
SHOW index FROM table1;name列にインデックスがない場合、次のステートメントでインデックスを追加して、このような大規模なデータスキャンによって引き起こされる低速クエリを解消できます。ALTER TABLE table1 ADD KEY ix_name (name);name列にインデックスがある場合、次のステートメントを使用して SQL ステートメントの実行計画を表示し、正しいインデックスが使用されているかどうかを確認できます。EXPLAIN SELECT * FROM table1 WHERE name='testname';name列にインデックスが存在するにもかかわらず使用されていない場合、不正確な統計情報が原因で実行計画が正しくない可能性があります。次のステートメントを実行してテーブルの統計情報を再生成し、計画を修正できます。ANALYZE TABLE table1;コマンドが完了したら、再度実行計画を確認し、正しいインデックスが使用されるようになったことを確認してください。
EXPLAIN SELECT * FROM table1 WHERE name='testname';
FAQ:PolarDB の異なるクラスター間で、同一の SQL ステートメントとスキャン量にもかかわらず、CPU 使用率が大幅に異なるのはなぜですか?
CPU の飽和は、通常、遅いリクエストによって引き起こされます。SQL テキストと理論上のスキャン量が異なるクラスター間で同一に見えても、実際の実行動作は異なる場合があります。以下の点について調査してください。
実際のスロークエリログの詳細を比較する:両方のクラスターのスロークエリログを確認・比較し、実際にスキャンされた行数、返された行数、実行時間が異なるかどうかを確認してください。同じ SQL ステートメントでも、クラスターが異なれば実行計画が異なったり、異なるデータ分布に遭遇したりする可能性があります。
クラスターアーキテクチャの違いを確認する:高負荷のクラスターが低負荷のクラスターよりも読み取り専用ノードの数が少ないかどうかを確認してください。読み取りリクエストが読み取り専用ノードにオフロードされていない場合、プライマリノードの負荷が重くなり、結果として CPU 使用率が高くなります。
最適化の推奨事項:CPU の飽和を防ぐには、SQL テキストが同一であるかを確認するだけでなく、遅いリクエストを最適化し、SQL ステートメントによって実際にスキャンされる行数を減らすことに焦点を当ててください。
アクティブスレッド数の多さ
アクティブなスレッド数が多いと、CPU 使用率は常に上昇します。MySQL では、各 CPU コアは一度に 1 つのリクエストしか処理できません。例えば、16 コアのクラスターは、カーネルレベルで最大 16 の同時リクエストを処理できます。これはアプリケーションレベルの同時実行性とは異なります。PolarDBコンソールで に移動して、セッション情報を表示できます。
スロークエリがリクエスト処理失敗の原因でないと判断した場合、アクティブスレッドの蓄積は通常、本番トラフィックの増加が原因です。パフォーマンス曲線を表示してこれを確認できます。全体的なトラフィックとリクエストの傾向がアクティブスレッド蓄積の傾向と一致している場合、クラスターリソースが限界に達していることを示します。この問題を解決するには、データベースクラスターに読み取り専用ノードを追加するか、クラスター仕様をスケールアップする必要があります。
アクティブスレッド数がクリティカルポイントに達すると、CPU 競合が発生し、カーネル内に多数のミューテックスロックが生成される可能性があります。パフォーマンスチャートでは、通常、高い CPU 使用率、高いアクティブスレッド数、低い IOPS または QPS が表示されます。もう 1 つの原因は、トラフィックの急増です。この場合、高いレートの新規接続も CPU 競合とリクエストのバックログにつながります。多くの場合、クラスターのスレッドプール機能を有効にしてフロー制御を行うことで、この問題を緩和できます。アクティブスレッド数が減少した場合、タスクがまだアプリケーション側で滞留していないか確認してください。CPU 負荷とアクティブスレッド数が依然として高い場合は、クラスターのスケールアップも検討する必要があります。
フロントエンドの接続ストームも、クラスターに瞬間的なトラフィックスパイクを引き起こす可能性があります。これは異常なトラフィックであり、多くの場合、Web クローラーによって引き起こされます。SQL スロットリングを使用してリクエストを拒否できます。詳細については、「セッション管理」をご参照ください。
不適切なカーネル設定
セルフマネージド MySQL インスタンスのデフォルトパラメータは、汎用的なシナリオ向けに設定されており、すべてのワークロードに最適とは限らず、微調整が必要な場合があります。一部の問題は、データ量が少ないアプリケーションの初期段階では現れず、時間の経過とともにデータが増加し、特定の条件が満たされると出現することがあります。
メモリ競合は一般的な問題です。MySQL アーキテクチャでは、メモリは主にデータキャッシングに使用されます。最も一般的に使用されるメモリ領域は buffer pool と innodb_adaptive_hash_index です。データベースシステム全体のキャッシュ領域は、データ交換が最も頻繁に行われる場所です。メモリ不足やメモリページの競合があると、さまざまな例外の蓄積やスロークエリが発生する可能性があります。典型的な症状として、CPU 使用率が最大レベルまで急上昇し、スロークエリが発生します。調査によって問題がインデックスの欠落ではないと判明した場合、問題はメモリシステムにある可能性があります。
例えば、truncate table 操作が実行されると、MySQL は buffer pool を走査し、truncate されるテーブルのすべてのデータページを削除します。 大規模なクラスターでは、innodb_buffer_pool_instances が 1 に設定され、同時実行性が比較的高い場合、競合問題が発生する可能性があります。 この問題はサービスのライフサイクルの早い段階で発見でき、通常は innodb_buffer_pool_instances の値を CPU コア数に合わせ、buffer pool をバケットに分割することで回避できます。
もう 1 つのシナリオは、innodb_adaptive_hash_index に対する競合です。 明確な症状は、多数の hash0hash.cc の待機が発生することです。
SHOW ENGINE innodb STATUS;出力の AHI セクションには、著しいデータスキューが見られます。
insert 0, delete mark 0, delete 0
Hash table size 25499819, node heap has 20720 buffer(s)
Hash table size 25499819, node heap has 25111 buffer(s)
Hash table size 25499819, node heap has 23884 buffer(s)
Hash table size 25499819, node heap has 16835 buffer(s)
Hash table size 25499819, node heap has 23132 buffer(s)
Hash table size 25499819, node heap has 189284 buffer(s)
Hash table size 25499819, node heap has 38864 buffer(s)
Hash table size 25499819, node heap has 49094 buffer(s)
5469.32 hash searches/s, 5282.36 non-hash searches/sこの種の問題については、innodb_adaptive_hash_index パラメーターを無効にすることで、AHI 機能を無効にできます。データによると、読み取りと書き込みが混在するシナリオでは、AHI はパフォーマンスに悪影響を及ぼす可能性がありますが、無効にしてもビジネス全体に大きな影響はありません。
メモリリソースの異常による CPU の高騰またはプライマリ/スタンバイ切り替え
メモリリソースの異常は、間接的に高い CPU 使用率、インスタンスのクラッシュ、またはプライマリ/スタンバイ (HA) 切り替えを引き起こす可能性があります。以下のシナリオでは、メモリ使用率 100% への到達、メモリ不足 (OOM) イベント、クラッシュ、プライマリ/スタンバイ切り替え、HA イベント、閉じられていないプリペアドステートメント、長い SQL ステートメント、トリガー、クエリパーサーの問題など、一般的な原因について説明します。
シナリオ 1:OOM (メモリ不足) によるインスタンスのクラッシュ
原因:過剰な接続 (多数のアイドル接続) と、時間内に閉じられないプリペアドステートメントが過度のメモリ使用を引き起こし、最終的に OOM イベントをトリガーしてインスタンスがクラッシュします。
解決策:
アプリケーション側で、アイドル接続を速やかにリサイクルしてください。
プリペアドステートメントを時間内に閉じ、同時 Prepare 開始の根本原因を調査してください。
オフピーク時にマイナーエンジンバージョンを新しいものにアップグレードし、カーネルレベルのメモリ最適化を活用してください。
innodb_buffer_pool_sizeパラメーター値を小さくして、問題が改善されるか確認してください。
シナリオ 2:クエリパーサーのメモリ集中による持続的なメモリ増加またはプライマリ/スタンバイ切り替え
原因:長い SQL ステートメントと大きなトリガーが、パーサーの高いメモリ消費を引き起こします。以下の点にご注意ください。
特定の SQL ステートメントが最適化されているか、書き込みノードにルーティングされていない場合でも、他の長い SQL ステートメントやトリガーが依然として問題を引き起こす可能性があります。
DML 操作は、読み書き分離の設定に関係なく、プライマリノードで実行する必要があります。
解決策:
長い SQL ステートメントを複数の短いステートメントに分割してください。
トリガーを最適化するか、その長さを短くしてください。
アプリケーションレベルで SQL の長さを制御してください。
必要に応じて、インスタンス仕様をアップグレードするか、
innodb_buffer_pool_sizeパラメーターを調整します。
シナリオ 3:大規模スキャン SQL によるメモリ使用率 100% 到達とプライマリ/スタンバイ切り替えの誘発 (診断レポートには反映されない)
原因: 複雑な条件を持つクエリやCOUNT 集計などの大規模なスキャンを実行する SQL ステートメントは、大量のメモリを消費します。これらのステートメントは診断レポートに表示されない場合があるため、検出が困難になります。
解決策:
スロークエリログを分析して、特定の大規模スキャン SQL ステートメントを特定してください。
特定された SQL ステートメントを、適切なインデックスを追加したり、クエリを書き換えたりして最適化してください。
システムのバグ
システムのバグは、CPU の高い問題の比較的まれな原因です。以前のバージョンの例としては、プロセスのデッドロックや、テーブル統計がゼロにリセットされることによるフルテーブルスキャンなどがあります。製品が進化するにつれて、システムのバグによる CPU の問題は少なくなりました。しかし、これらの問題のトラブルシューティングには、多くの場合、深いカーネルレベルの情報が必要であり、ご自身で解決するのは困難な場合があります。テクニカルサポートについては、弊社までお問い合わせいただくことを推奨します。