...

データベース接続の飽和:高トラフィックによるMySQLの過負荷を避ける

トラフィックのピーク時には、データベース接続の飽和が新しいリクエストをブロックします。 MySQL-コネクションが枯渇し、ワードプレスがスロットを獲得できなくなった。以下の方法を実践的に紹介しよう。 MySQL 過負荷から保護し、ボトルネックを大幅に削減し、高負荷下でも安定した応答時間を維持します。.

中心点

  • 原因がある: 接続数が少なすぎる、クエリが遅い、漏れがある。.
  • 診断 プロセスリスト、ステータス変数、スローログ。.
  • チューニング: max_connections、スレッドキャッシュ、タイムアウト。.
  • 退院: プーリング、キャッシュ、インデックス。.
  • スケーリング: リードレプリカ、オートスケーリング。.

MySQLの接続飽和とは実際に何を意味するのか?

すべての問い合わせには 接続, すべてのスロットが埋まっていると、新しい接続がソケットバックログに溜まったり、エラーメッセージが出て失敗したりする。そのような時、アプリケーションは空き接続を待っているため、典型的な „Too many connections “エラーをよく目にする。 スレッド が何も受け付けなくなるまで待ちます。決定的な要因は、同時に何人のPHPワーカーが接続を要求し、個々のクエリがどれくらいの時間オープンされたままであるかである。実際、私は単純な計算式を使っています。同時ウェブワーカー数に平均クエリ時間を掛けたものが、プールにかかる圧力に等しくなり、すぐに飽和点に達します。 ホスティング ボトルネックが明らかになった。構造化された入門書としては、以下を参照されたい。 接続制限を理解する, コンフィギュレーションとアプリケーションが一致するように。.

アクセスが集中する典型的なきっかけ

訪問者が多いということは、同時多発的な訪問者が多いということである。 セッション, クエリが長引けば長引くほど、コネクションはブロックされたままになる。インデックスの欠落による長い読み取り操作、競合する書き込みによるロックキュー、コード内のコネクションリークはすぐに 飽和. .共有環境では、ホスティング業者がアカウントごとの接続数に厳しい制限をかけていることが多く、負荷がかかると突然500エラーが発生する。さらに、クーロンジョブ、クローラー、管理バックエンドが同じプールの枠を奪い合うため、同時に状況を悪化させる。そのため、私は制限の安全マージンを計画し、特にスパイクを監視し、クエリの実行時間を常に数秒の範囲に保つようにしています。 コントロール.

早期警告のサインにいち早く気づく

私はまず、不規則なロード時間に注意を払う。 TTFB-の値は、接続が不足しつつあることを非常に早い段階で示してくれる。Error establishing a database connection „や “Too many connections „といったメッセージは、すでにプールが一杯になり、リクエストが失敗する時点を示している。多くの “Sleep „エントリや “Waiting for table metadata lock „がプロセスリストに表示されるが、これは不運なロック状況やアイドル状態の接続が多すぎることを示している。私はアプリケーションのタイムアウトを並行してチェックします。なぜなら、厳しく設定された制限はエラーの可視性を悪化させ、誤ったアラームを発生させる一方、寛大な値は問題を隠すからです。 データベースのタイムアウト. .最後に、最大値に対する連結糸の曲線は依然として有用である。 飽和 はっきりと。.

診断:ステップ・バイ・ステップ

私はいつもエラーログから診断を始める。 エラー 接続の問題はすぐに明らかになる。その後、プロセスリスト全体を分析し、長いクエリーを特定し、それらがブロックされているか、あるいはゆっくりとしか読み込まれていないかをチェックします。Threads_connected、Threads_running、Max_used_connectionsなどのステータス変数により、設定された制限値に対する客観的な測定ポイントを得ることができ、ピーク時と継続的な負荷を分けることができます。それから、ランダムなピークにこだわるのではなく、本当に負荷の高いステートメントを見えるようにするために、適度なしきい値でスロークエリログを有効にします。最後に、EXPLAINを使用し、フルテーブルスキャン、インデックスの欠落、不正な結合ストラテジーの可能性を探します。 コネクション 長く縛られる。.

チューニングの主要数値一覧

値を変更する前に、フレームをメモリ上に置く、, スレッド と作業量を変更し、MySQL がスワッピングに陥らないようにします。私は単純な開始値を使用し、効果を測定し、大きくジャンプする代わりに小さなステップで改良します。接続ごとのバッファとグローバルバッファの合計を利用可能なRAMと照らし合わせて、オペレーティングシステムのキャッシュに空きがあることを確認することは重要です。コネクションを増やすだけでは、クエリが長すぎる場合に役に立たないからです。私は、クイック・リファレンス・ガイドとして以下の表を要約し、典型的な開始値と測定された変数にマーカーを設定しました。 早い に取り組む。.

セッティング 効果 測定変数 標準的な開始値 ヒント
最大接続数 限定的な同時開催 クライアント 最大使用コネクション数 300-800 RAMが十分な場合にのみ増やす
スレッドキャッシュサイズ コスト削減 スレッド スレッド作成 128-512 Threads_createdが急速に増加する場合は、次の値を増やしてください。
ウェイトタイムアウト 非アクティブを閉じる セッション スレッド接続 30-90 s アイドリングの詰まりを防ぐ
innodb_buffer_pool_size 読書を加速させ 書く-アクセス バッファプールヒット率 50-70% RAM 生産負荷に合わせる
最大許容パケット数 より大きな パッケージ エラーログのエラー 64-256 MB 必要な場合のみリフトアップする

設定: MySQLをピーク負荷用に設定する

最初のうちは、中央の限界を用量で調整する。 コネクション また、接続ごとに多くのRAMを消費し、副作用をもたらす可能性がある。保守的な計画では、max_connectionsを徐々に増やし、スレッドキャッシュに余裕を与え、タイムアウトを短くして、スリープセッションがプールを詰まらせないようにする。各変更の前に、私はスレッドごとのバッファとグローバル・バッファの合計を、実際に利用可能なメモリに対して計算する。そして、Max_used_connectionsが定期的に新しい制限に触れるかどうか、Threads_runningが恒久的に高いままではなく、トラフィックと相関しているかどうかをチェックする。これにより、負荷のピークを管理しやすくなり、さらに次のような対策を講じることができる。 飽和.

[mysqld]
最大接続数 = 600
スレッドキャッシュサイズ = 256
wait_timeout = 60
インタラクティブタイムアウト = 60
innodb_buffer_pool_size = 12G
innodb_flush_log_at_trx_commit = 1

接続プーリングを正しく使用する

プーリングは、接続のセットアップコストを削減し、アプリケーションのスレッドを MySQL-スレッドということは、飽和状態になるのが遅くなるということだ。私はこのためにコネクションプロキシを使い、バックエンドのコネクションにハードリミットを設定し、スロットが空くまでプロキシにリクエストをバッファさせる。PHPスタックでは、制御不能な持続的接続は避け、代わりに上限を尊重する明確に設定されたプールを使う。スリーパーがバックエンドプールを使い果たし、 リクエストがプロキシに滞留することがないように、プール内のきれいな アイドルタイムアウトは依然として重要である。より詳細な実用的な関連性については、以下のコンパクトなガイドがある。 コネクション・プーリング, 制限、タイムアウト、リトライの挙動を首尾一貫して組み合わせることで、アプリケーションの安定性を保つ。 倍率付き.

負担を軽減するキャッシュ戦略

の上に結果を表示することで、データベースから仕事を取り除いている。 データベース その結果、接続需要を減らすことができる。ページキャッシュはクエリなしで匿名アクセスに答え、オブジェクトキャッシュは頻度の高いオプションとメタデータをRAMに保持し、トランジェントストラテジーは書き込み負荷を平準化する。キャッシュキーを明確に定義し、フラッシュする代わりに無効化し、古くなったコンテンツを危険にさらすことなくヒット率が上がるようにTTLを選択することが重要である。WordPressの場合、私はRedisやMemcachedを使用した専用のオブジェクトキャッシュを使用している。キャッシュのヒット数を目に見えて増やすと、Max_used_connectionsとThreads_runningが顕著に低下する。 飽和 を減らした。

SQLとスキーマの最適化

遅いクエリはすべてEXPLAINでチェックします。 インデックス が分単位で実行される本当の原因であることが多い。WHEREカラムとJOINカラムの選択的インデックスは、テーブルのフルスキャンを高速なインデックス範囲の読み込みに変え、ロックチェーンを断ち切る。私はクエリを単純化し、SELECTリストの不要なカラムを削除し、大規模な処理をより短いステップに分割することで、長い接続をより少なくします。WordPressでは、オートロードオプションとChattyプラグインを見る価値がある。短いメンテナンス・ウィンドウを持つクリーンなDDL変更も、„Waiting for table metadata lock “の原因となる長いメタデータ・ロックを防ぎます。 プロセスリスト 詰まる。.

スケーリング:垂直、水平、リードレプリカ

チューニングとキャッシュが効いてきたら、次のレバーをチェックする: スケーリング より多くの RAM と CPU を介して、または複数のデータベースノードを介して。縦方向のステップでは、MySQLに大きなバッファプールとより多くのスレッドを与え、ホットセットがメモリに収まるようにし、ディスクに触れる頻度を減らす。水平方向では、プライマリ・システムをリード・レプリカで緩和し、リード・アクセスをそちらに向け、ライト・ロードを集中させることで、ブロックを減らしている。アプリケーションには、リード/ライトの分割と、読者が古いデータを見ないようにするための遅延対策も必要だ。トラフィックの変動が激しい場合は、アプリケーション側で自動スケーリングを行い、何百人ものPHPワーカーが突然DBプールを 飽和 ドライブ.

負荷モデルの明確化プールへの圧力を予測可能にする

私は単純な経験則でプレッシャーを定量化している:同時ウェブワーカー×平均クエリ保留時間≒所要時間 コネクション. .I/Oやロックのために平均ホールド時間が50ミリ秒から200ミリ秒に増加した場合、要件は4倍になる。例:PHPワーカー120人、平均DB時間0.2秒の場合、理想的な分散で24のコネクションが同時に使用されることになります。また、管理者/クーロンのワークロード用に追加のリザーブを確保し、クリティカルなジョブをそれぞれのプールに分けています。これにより、少数の長いトランザクションの陰で短いページビューが飢餓状態に陥るのを防ぐことができます。.

ウェブサーバーとPHPワーカーをDBの上限に合わせて拡張する

PHPのFPMワーカーの数を MySQL-バックエンドは、「大きい=良い」ではなく、「大きい=良い」のです。例えば、max_connectionsが600の場合、プーリング/プロキシに400のハードバックエンドスロットを与え、PHP-FPMはピーク時でも永久にこのスロットをオーバーしない数に制限する。アドミッション・コントロールは雪崩を防ぐ:NGINXやアプリのキューには上限が必要で、過密の場合は無制限のキューではなく、429/503をリトライ後に配信するようにしています。PHP-FPM については、過度にアグレッシブな pm.max_children を避け、短い I/O タイムアウトを設定して、ハングアップするバックエンドがワーカーバッチ全体を拘束しないようにしています。オンデマンドや動的な処理とボットのレート制限を組み合わせて、スケーリングがDBプールを „スイングアップ “させないようにしています。.

; php-fpm.conf (例)
pm = 動的
pm.max_children = 160
pm.start_servers = 20
pm.min_spare_servers = 20
pm.max_spare_servers = 40
request_terminate_timeout = 30s

トランザクション、分離、ロックの制御

長時間の取引は 飽和, なぜなら、ロックを保持し、アンドゥが増大し、他のクエリの速度を低下させるからだ。トランザクションはできるだけ短くする。最初にデータを読み込み、次に素早く書き込み、すぐにコミットする。REPEATABLE READが本当に必要なのか、READ COMMITTEDで十分なのかをチェックする。SELECT ... FOR UPDATEを選択的に使用し、適切なインデックスで影響を受ける行セットを制限する。読み取り専用アクセスにはオートコミットを有効にしておき、書き込みは自己完結型の小さな単位にまとめている。定期的にデッドロックを評価し、„Waiting for lock “で何分も待機させる代わりに、長い待機セッションを中止する。.

InnoDBが一定のレイテンシーを実現するための微調整

負荷がかかってもコミットレイテンシが安定するように、ログと I/O パスを設定した。より大きなREDOログ(innodb_log_file_size)はピークを滑らかにし、アダプティブフラッシング(innodb_adaptive_flushing)はスタッタリングを防ぎ、現実的なinnodb_io_capacity(-max)は実際のストレージ性能に合わせる。バッファプールはホットセットに対して十分な大きさのままだが、一貫性要件に応じてinnodb_flush_log_at_trx_commitを意図的に選択している。ページ分割とランダムI/Oを最小限にするため、主キーは単調(例えばAUTO_INCREMENT)にする。重要:私は各変更の前後でp95/p99のレイテンシを測定し、fsyncとredoのフラッシュレートを観察している。.

[mysqld]
innodb_log_file_size = 2G
innodb_flush_method = O_DIRECT
innodb_io_capacity = 1000
innodb_io_capacity_max = 2000
innodb_adaptive_flushing = 1

オペレーティングシステムとネットワークパラメータを忘れないでください

飽和はカーネルのキューやファイル記述子にも見られる。私は、OSの制限によって短期的なピークが失敗しないように、受け入れキューと空きポート範囲を増やしました。keepaliveの間隔を適度に設定し、open_files_limitとfs.file-maxをチェックして、多くの同時接続がファイル制限で終わらないようにする。MySQL側では、適切な大きさのback_logが、スレッドスケジューラがそれらを引き継ぐまで、着信接続バーストをバッファするのに役立ちます。これらの調整によって原因が緩和されるわけではありませんが、プールが破棄する代わりに処理する貴重なミリ秒が提供されます。.

# sysctl (例)
net.core.somaxconn = 1024
net.ipv4.ip_local_port_range = 10240 65535
fs.file-max = 200000

# my.cnf(追加)
バックログ = 512
open_files_limit = 100000

観測可能性:彩度を可視化する

私はいくつかの意味のあるメトリクスを中心にダッシュボードを作っている:threads_running対threads_connected、max_connectionsに対するmax_used_connections、p95/p99クエリーレイテンシー、innodb_row_lock_time、handler*カウンター、接続エラーなどです。私は低速クエリログを定期的にローテーションし、実用的な閾値(例えば200-300ミリ秒)を設定することで、プールを詰まらせる „中程度に高価な “ステートメントでさえも見えるようにしています。私はパフォーマンススキーマとsysビューを使用して、ホットステートメント、待ち時間、トップコンシューマを特定します。私は意図的にハードリミット(リミットの70-80%)以下にアラームを設定し、実際の障害が発生する前に介入できるようにしています。.

負荷試験、背圧、劣化

私は、ランプアップ、短いピーク、長いソークフェーズで現実的な負荷をテストします。目的は安定したp95のレスポンスタイムと制御されたスループットであり、単に最大リクエスト数/秒ではありません。過負荷の場合には、キュー制限、段階的なタイムアウト、頑固さの代わりに指数関数的な再試行など、バックプレッシャーをかけます。私は特に データベース 高価なウィジェットを隠したり、„stale “なデータでアグリゲーションに答えたり、書き込みの多い関数を一時的にスローダウンさせたり。ランブック(ログをチェックし、プールを拡大し、キャッシュを空にし、ウォームアップし、バックグラウンドジョブを一時停止する)を使った明確な緊急プランがあれば、ブラインドデバッグで失われるホットフェーズでの時間を節約できる。.

リード・レプリカの実際:レイテンシと一貫性のバランス

リード・レプリカは読み込みと書き込みを分離するが、レプリケーションの遅延をもたらす。クリティカルでないリードはレプリカにルーティングし、„リード・アフター・ライト “パスにはプライマリを意図的に残すか、書き込み操作の後に短い „スティッキネス “を使うようにしている。レプリケーションの遅延を継続的に測定し、遅延が大きい場合は自動的にプライマリにリードを戻すようにしている。計画されたレポートや検索インデックスを特にレプリカに移し、プライマリがユーザーに対するレイテンシーを維持できるように、ピーク負荷時にはスロットルをかける。重要: レプリカへの書き込みアクセスは決して許可しないこと。そうしないと、パスが混在してしまい、見つけるのが難しい不整合が発生してしまうからだ。.

高負荷時のWordPress:実用的なレシピ

ページ/オブジェクトのキャッシュに加えて、wp_optionsの対策もする価値がある:本当にグローバルで小さなオプションにだけautoloadフラグを設定し、残りは消去する。WooCommerceでは、wp_postmeta(post_idとmeta_keyの組み合わせ)のインデックスをチェックし、テーブル全体を実行するためにLIKE接頭辞を使用するクエリを避けます。WP-Cronをシステムクーロンに切り離し、重いジョブをオフピーク時にクロックする。RESTとAJAXエンドポイントは、ページレンダリングと同じプールをブロックしないように、独自のレート制限と短いタイムアウトが与えられています。リスト・ビューでは、meta_valueでの高価なソートを前処理フィールドまたは計算カラムに置き換えています。 スレッド 無料だ。

# WP cronの代わりにシステムクーロン
*/5 * * * /usr/bin/wp cron event run --due-now --path=/var/www/html >/dev/null 2>&1

迅速な対応のためのまとめ

私はデータベース接続の飽和に体系的に取り組んでいます:原因を絞り込み、コンフィギュレーションを増やし、クエリ時間を短縮することで、データベース接続の飽和を防ぎます。 コネクション がフリーになる。その後、プーリングとキャッシングで安定させます。なぜなら、これらの手段はデータベースから直接需要のほとんどを取り除くからです。スケーリングは、メトリクスによってチューニングが完了し、アプリケーションが複数のノードをきれいに処理できることが証明されたときにのみ行います。70-80%の利用率に関する明確なアラームで監視することで、不測の事態から守り、制限やキャッシュ戦略を強化する時間を与えてくれます。この順序を維持すれば、MySQL は高負荷下でも回復力を維持し、エラー数が減少し、ピーク時でもページが高速で信頼性の高いパフォーマンスを提供できる。 厩舎.

現在の記事