...

サーバー運用におけるメモリの断片化:原因と解決策

サーバー運用におけるメモリの断片化とは、RAMが空いているにもかかわらず、連続した大きなブロックが利用できなくなり、重要な割り当てが失敗することを意味します。その原因、典型的な症状、そして的を絞った対策を示します。 サーバー 計算可能な方法で反応し、配分を確実に行うことができる。 機能.

中心点

  • 内部 そして 外部 フラグメンテーションを区別し、具体的に対処する。.
  • バディ・アロケーター 理解する:オーダー、スプリット、ミッシングマージ。.
  • クロスカントリースキーヤー-ワークロード、ハイパーバイザーのオーバーヘッド、およびTHPを正しく設定する。.
  • 診断 buddyinfo、vmstat、およびコンパクション・メトリクスを含む。.
  • 配分パターン 改善する:プール、事前割り当て、個別の寿命。.

日常的なサーバーの使用において、メモリの断片化とは何を意味するのか?

私は次のように呼んでいる。 メモリー フラグメンテーションとは、空きワーキングメモリが小さな隙間に分かれてしまい、大きなリクエストが連続した領域を受け取れなくなる状態のことである。内部フラグメンテーションは、割り当てられたブロックが実際の必要量より大きく、未使用バイトがブロック内に残っている場合に発生する。 効率性 が減少する。外部断片化は、RAM全体には十分な空き領域があるにもかかわらず、空きセクションが分散し、まとまらなくなって大領域を形成する場合に発生する。大容量バッファやJIT予約、あるいは連続メモリを好むドライバが失敗するのは、大容量ブロックが一見逆説的に不足するためです。ホスティング環境では、高い並列負荷、長いアップタイム、異種ソフトウェアスタックがこの問題を悪化させる。 ダイナミクス 目につく。

Linux-Buddy-Allocatorが断片化を生み出す仕組み

Linuxカーネルは、物理メモリを バディ-アロケータは、ページを4KBから始まるサイズクラス(順序)で整理する。プロセスがより大きな領域を要求すると、カーネルは適切なサイズが利用可能になるまで、大きなブロックをバディに分割する。しかし、リクエストの長さが異なったり、ライフタイムが変化したり、リリースにばらつきがあったりすると、再アセンブリが妨げられ、外部からの再アセンブリが促される。 フラグメンテーション. .時間が経つにつれて、大きなオーダーのストックが空になり、小さなオーダーが膨れ上がる - /proc/buddyinfoは、低いオーダーの高い数字と高いオーダーのゼロを表示します。この時点から、コンパクションとおそらくOOM動作がより頻繁に介入するようになり、待ち時間が発生し、混乱が増加する。.

ホスティングおよび仮想化環境における原因

長時間稼動するウェブやデータベースのワークロードは、ラージブロックを分割し、後で使用できるようにするアロケーションのさまざまなパターンを作成します。 マージ 防ぐことができる。メモリを解放するのが遅かったり、調整されていなかったりするフレームワークやライブラリは、小さなリクエストにしか対応できない隙間を残す。仮想化は独自のオーバーヘッドを追加し、割り当てをゲストとハイパーバイザーにシフトさせる。 フラグメンテーション がより迅速に作成される。vm.min_free_kbytesの値が正しく設定されていないと、カーネルがアトミック・アロケーションに使用するバッファが少なすぎるか、バッファを過剰に確保するため、プレッシャーが増大する。より透明性の高い 仮想メモリ は、ゲストアロケータ、THP、Huge Pages、ハイパーバイザー間の相互作用をきちんと整理するのに役立つ。.

パフォーマンスとユーザー・エクスペリエンスへの影響

貯蔵タンクが多数の小島に分割されている場合 遅延時間, というのも、カーネルが大きなリクエストを処理できるようになる前に、圧縮やシフトが頻繁に行われるからだ。データベース、キャッシュ、マルチメディア・パイプラインなど、継続的な領域を必要とするアプリケーションは、より早く頓挫する。RAMが「空いている」にもかかわらず、大規模な割り当てが失敗し、エラーメッセージや再起動、ハードキャンセルが発生する。 トランザクション 障害。コンパクションのようなバックグラウンドのアクティビティは、CPU負荷とI/Oプレッシャーを増加させ、そうでなければ軽いワークロードでさえ遅く見える。ホスティングシナリオでは、これは長い応答時間、散発的なタイムアウト、ピーク負荷時のスケーリング不良として現れます。.

診断:バディインフォからコンパクション・メトリクスまで

まず、/proc/buddyinfo をチェックして、どの 受注状況 vmstatとsarは、カーネルがコンパクト化する頻度や、OOMパスがアクティブになったかどうかを示す。私はperfとstraceを使って、スレッドが直接コンパクションを待っているかどうかを認識する。Windowsサーバーがある環境では、デバッグツールで断片化されたヒープを可視化して、大きなギャップがないかチェックし、ヒープパラメーターを微調整する。 調整する. .また、空きRAMの合計だけでは診断として不十分なので、最大の空きブロックも計測している。.

カーネルとVMのチューニングの実際

私は、vm.min_free_kbytesを適度に高く、多くの場合、RAMの5~10 %程度に設定している。 お問い合わせ は確実に操作できる。透明な巨大ページは、負荷プロファイルと断片化のリスクに応じて、オンデマンドかmadvise経由のどちらかで、慎重に作動させる。静的巨大ページは予測可能性を提供するが、他の場所で問題を引き起こさないように適切な計画を立てる必要がある。 ボトルネック 秩序を生み出すために。コンパクションは短期的には秩序を生み出すが、永続的で不安定なパターンに対する構造的な解決策にはならない。私はNUMAトポロジーをチューニングに含めることで、大規模な割り当てがローカルにとどまり、ノード間で摩擦が生じないようにしている。.

セッティング ゴール ベネフィット ヒント
vm.min_free_kバイト 大口割り当てに備える OOM/コンパクションピークの減少 徐々に値を上げ、測定する
THP (on/madvise) 大きなページを好む フラグメンテーションの減少、TLBレートの向上 ワークロードのレイテンシーに注意
巨大なページ 静的 リザーブ連続エリア 予測可能な大型ブロック 事前にキャパシティを計画する
コンパクション フリーエリアをまとめる 一時的にブロックを大きくする 短期的にはCPU/I&Oを増加させる
NUMA-ポリシー 確実な現地割当 低遅延、クロストラフィックの低減 バランシングの設定

ストレージ・ゾーン、マイグレート・タイプ、そして「移動不可能」がすべてをブロックする理由

ページアロケータはオーダーだけでなく ゾーン (DMA、DMA32、ノーマル、ムーバブル)と タイプの移行 (移動可能、移動不可能、再生可能)。そのための粒子が「ページブロック」である。移動不可能なページ(例えば、カーネル構造体やドライバによって固定されたページ)がページブロックに入るとすぐに、カーネルはこのブロックを移動困難とマークします。まさにこの „汚染された “ブロックが、コンパクションが空き領域を大きな連続した 地域 フォームを使用します。そのため、私は意識的に(可能な限り)ZONE_MOVABLEでキャパシティを計画し、アプリケーション・データが主にMOVABLEとして割り当てられるようにしている。これは、連続した大きなリザーブが利用可能であり続ける可能性が高いことを意味する。DMA 要件の高いワークロードでは、UNMOVABLE ページがワイドなノーマルゾーンを破壊しないよう、ターゲット予約を使用する。.

クリーンな割当パターン設計

私は、保管に必要なものを次のように分類している。 耐用年数短い寿命のオブジェクトはプールに、長い寿命のオブジェクトは別々のリージョンに置くことで、リリースの際に全体を荒らさないようにしている。頻度の高いサイズを固定プールでグループ化することで、オーダーの変動を減らし、バディ・アロケータを緩和している。大きなバッファは、トラフィックの途中で要求するのではなく、最初にあらかじめ計画しておく。過剰なアラインメントはスペースを浪費し、内部的なアラインメントを促進するので、アラインメント要求は実際のニーズに合わせる。 フラグメンテーション. .ビルドとデプロイのパイプラインでは、トラフィックが本稼働する前に、負荷シナリオを使ってストレージパスをテストする。.

ユーザー空間でのアロケータ選択:glibc、jemalloc、tcmalloc

すべてのフラグメンテーションがカーネルの問題というわけではない。その ユーザースペース-glibcのmallocはスレッドごとのアリーナを使うので、多くのコアでは内部の断片化が激しくなる。私はアリーナ数を制限し、未使用領域がより早くオペレーティング・システムに戻るように、より積極的にトリムしている。jemallocやtcmallocのような代替手段は、より細かいサイズクラスとより一貫した共有パターンを提供し、外部断片化を顕著に減らすことができる。決め手となるのは各アロケータはレイテンシ、スループット、メモリフットプリントにおいて異なるトレードオフを持っているからだ。高いスループットと均一なオブジェクト・サイズのサービスでは、専用アリーナやスラブのようなプールが最も安定したパフォーマンスを提供することが多い。 遅延時間.

アプリケーション側の対策:Java、PHP、キャッシュ、データベース

Javaでは アリーナ またはリージョンアロケータを使用し、ヒープを常に細かく分割するのではなく、大きくて連続した予約を好むGCプロファイルを選択する。Xms/Xmxのバランスをとり、ヒープが常に大きくなったり小さくなったりしないようにする。PHPとMySQLのスタックについては、固定メモリプールを使い、オーバーサイズのオブジェクトを制限し、バッファサイズを最適化して、一貫性のあるアロケーションパターンを目指している。 PHP/MySQLの最適化. .私は、リリースが常に大きなギャップを残さないように、チャンクサイズが均等になるようにキャッシュシステム(オブジェクトキャッシュやページキャッシュなど)を整理している。システム全体を破壊する可能性のある予定外のOOMイベントのリスクを冒す代わりに、メンテナンスウィンドウで制御された再起動を計画します。 サービス内容 をキャンセルする。.

コンテナとKubernetesの実践

コンテナの機能を変更することはない。 バディ-アロケータは、ビューとリミットをセグメント化するだけです。フラグメンテーションはホストの問題であることに変わりはないが、ポッドでは、立ち退き、レイテンシーの変動、THPの分割コストによって顕在化する。私は以下の方法で安定性を実現している:

  • QoSクラス(Guaranteed/Burstable)を設定して、クリティカルなポッドが固定リザーブを受け取り、同時に成長したり縮小したりしないようにする。.
  • メモリの制限を現実的なものにすることで、トリミングや再生が永久にハードディスクに違反しないようにする。 バウンダリー 衝突する。.
  • THP/Hugepagesは一貫してホストワイドで、大きなページを必要とするポッドに静的に予約されたプールを提供する。.
  • ウォームアップ戦略(プリフォールト、プリアロケーション)を使用し、大きなブロックが早期に占有され、負荷がかかっても後で要求されないようにする。.

私はベアメタルと同じようにコンテナ化されたノードを監視している:buddyinfo、コンパクション・イベント、OOMキル。.

仮想化、NUMA、ハードウェアの影響

ハイパーバイザーの中で、ゲストアロケータ、バルーン、ホストTHPがどのように相互作用するかをチェックします。 ブロック 乏しくなる。私は一貫してNUMAトポロジーを観察している。ローカルアロケーションはレイテンシを減らし、大きなリクエストがノードに分散して小さくなるのを防ぐ。理にかなっている場合は、ワークロードをNUMAノードに固定し、ページフォルトとTLBヒットへの影響を観察する。より細かい制御のために、私はストレージノードにガイドラインを設定し、次のように引きます。 NUMAバランシング をターゲットにした。また、ファームウェアとマイクロコードのアップデートも含めて、予期せぬ副作用を排除し、大規模な 必要条件 を受け取る。.

デバイスドライバ、DMA、CMA

肉体的に不自由なドライバー コヒーレント 領域(特定のDMAエンジン、マルチメディア、キャプチャカードなど)は、外部断片化を悪化させる。ここでは、連続メモリ・アロケータ(CMA)を使用するか、ブートプロセスの早い段階で大きなブロックを確保する予定です。これにより、ドライバがバッファを取得する前に、多くの小さな割り当てがアドレス空間を「かじる」のを防ぐことができる。同時に、(RDMA/DPDKを使用するなどして)ピンされたページを一般的なアプリケーション・メモリから分離し、そのUNMOVABLE文字によってページブロック全体が使用不能にならないようにしている。また、IOMMUコンフィギュレーションが、より大きな、連続しない領域を十分に仮想化しているかどうかもチェックする必要がある。そうでなければ、特定のリザーブと明確な時間制限が必要になる。 ウィンドウズ これらの割り当てのために。.

運用ルーチン:モニタリングとメンテナンスの窓口を賢く利用する

私は、buddyinfoスナップショット、コンパクション・カウンター、OOMイベントを次のように組み込んでいる。 モニタリング, 個々の事象ではなく、傾向を見るためだ。ローリングデプロイメントを減らすことで、メモリの変動がタイムウィンドウに集中し、週の残りがよりスムーズに動くようにしている。メンテナンス・ウィンドウの間は、必要に応じて手動でコンパクションを発動させ、キャッシュをクリーンアップし、フラグメンテーションが生産性を低下させる前にサービスを再起動させる。ピーク時のトラフィックとログやメトリクスを関連付けて、繰り返し発生するパターンを認識し、それに応じてバッファを調整します。大きな変更については、まずステージングでテストし、驚くような変更を発見しないようにします。 副作用 ライブオペレーションで.

ランブック大規模なアロケーションが失敗したとき

注文Xの割り当てに失敗しました」というエラーメッセージが表示される場合は、明確なステップを踏んで作業する:

  1. 状況写真: buddyinfoを保存し、vmstat(allocstall/compact)をチェックし、dmesgでCompaction/OOMエントリを検索。最大の空きブロックを推定する(>0を持つ最上位)。.
  2. 短期的な救済: クリティカルでないサービスを一時停止し、負荷を軽減し、キャッシュをクリアします。手動でコンパクションをトリガーし、THP Defragがダメージを与えている場合は一時的に停止します。.
  3. 目標クリア: 次のピークが発生する前に、定義されたサービスにおいて、連続した大きなバッファを再構築する(制御された再起動)。.
  4. リザーブを増やす: vm.min_free_kbytesとウォーターマークは、今後数時間のアトミック・アロケーションを確保するために注意深く使用する。 モニター.
  5. 恒久的な治療法: アロケーションパターンを修正し、プールを導入し、プレアロケーションを開始位置に移動し、NUMAローカライゼーションをチェックし、THP/Huge Pagesを適切に調整する。.

測定変数、SLO、アラーム

RAMの合計を測定するだけでなく、次のようなことも定義している。 SLO アロカタビリティについては、「利用可能な最高オーダー」、「大きなアロケーションが成功するまでの時間」、「コンパクションのストール率」。ここから、ユーザーがタイムアウトを確認する前に、早期にアラームを発生させることができる。有用な主な数値は以下の通り。

  • 1分あたりの高オーダー(例:≧オーダー9)のフリーブロック数。.
  • 直接締め固めまたは埋め立ての待ち時間の頻度と期間。.
  • 総メモリ量に対するピン留め/ピン留め解除ページの割合。.
  • 負荷テストとデプロイメント後のラージアロケーションの成功率。.

私はこれらの指標を、リリース時間、トラフィックのピーク、コンフィギュレーションの変更にリンクさせています。こうすることで、私はパターンを認識し、それに基づいてプロアクティブに次のことができる。 スケール または割り当てウィンドウを再スケジュールする。.

キャパシティ・プランニングとコスト意識

保管マージンの計算は、次のように行う。 通常運転 アロケーションの増加やメンテナンスの段階を適切にカバーします。全面的にアップグレードするのではなく、まずパターン修正をチェックします。なぜなら、優れたチューニングはRAMの追加以上のものをもたらすことが多いからです。容量を拡張する際には、THP/巨大ページ用のリザーブを計画し、巨大ページがアプリケーションのピークと衝突しないようにします。NUMAとアロケーション・プロファイルを適切に設定すれば、より少ないが強力なホストに統合することで、フラグメンテーションを減らすことができる。要するに、フラグメンテーションを減らすことで、CPUのピークやI/Oの混雑を減らし、ライセンスをより効率的に使用できるため、ユーロのコストを削減できるのです。 使用.

簡単にまとめると

メモリの断片化は、長さもサイズも異なる多くの割り当てが一緒にリンクされている場合に発生する。 地域 そして大規模な問い合わせは、後に無に帰す。私は3つの面で問題を解決する:カーネル/VMのチューニング(vm.min_free_kbytes、THP/Huge Pages)、より良いアロケーションパターン(プール、事前アロケーション、個別のライフタイム)、クリーンなオペレーション管理(モニタリング、スケジュールされた刈り込み、NUMA規律)です。私は、/proc/buddyinfo、コンパクション・カウンター、最大の空きブロックの計測を診断に利用しています。仮想化とハイパーバイザーには細心の注意を払っています。 ブロック 早い段階で予約する。これらのビルディング・ブロックを組み合わせることで、予測可能性を高め、OOMによる障害を防ぎ、特にトラフィックやデータが増大している場合に、より迅速なレスポンスを実現する。.

現在の記事