このガイドでは cgroups ホスティング Linuxのコントロールグループを使ってサーバーのリソースを分離し、「うるさい隣人」がサービスを低下させない方法を具体的に紹介します。Webサイト、コンテナ、ユーザーごとにCPU、RAM、ブロックI/O、ネットワークを制限し、優先順位を付け、確実に監視する方法を、実践的で実装可能な方法で学びます。.
中心点
以下の重要な点は、最も重要な決定とステップを案内するものである。.
- 断熱プロセスをきれいに分離し、隣人を飼いならす
- コントロールCPU、RAM、I/O、デバイスをターゲットに合わせて制限する。
- 優先順位プレミアム・サービス
- 透明性負荷の測定、アラームとトレンドの使用
- アップグレードv1からv2への明確な管理
cgroupがサーバーリソースを切断する方法
コントロールグループは、プロセスをグループに編成し、これらのグループをリソースドライバに接続します。 リソース をグループごとに設定することができる。共有サーバーでは、これによって1つのウェブサイトがCPU時間を消費したり、メモリをいっぱいにしたりするのを防ぐことができる。そのために、私は親グループが上限を指定し、子グループがそれを継承する階層を設定している。こうすることで負荷分散が一定に保たれ、ボトルネックを抑えることができる。特に、強いスパイクが孤立したトラックで走るため、„ノイジー・ネイバー “問題を顕著に緩和するためにこれを使用している。.
コントローラーとファイルシステム:商売道具
実際の作業は、/sys/fs/cgroup配下のcgroupファイルシステムから始まる。 制御システム の世話をする。CPU、メモリ、blkio、cpuset、デバイスなどのコントローラーを使って、タイムスライスを割り当てたり、RAMをカバーしたり、I/Oを遅くしたり、コアを固定したり、デバイスをロックしたりします。アプリケーションに応じて、これらのビルディングブロックを組み合わせる。例えば、メモリを大量に消費するアプリケーションにはハードRAMの制限を、ビルドジョブにはCPUのウェイトを、データベースにはI/O帯域幅を設定する。明確な名前付けは、後ですぐにグループを見つけられるようにするために重要だ。こうすることで管理しやすくなり、変更を見失うこともなくなる。.
| サブシステム | 目的 |
|---|---|
| cpu / cpuacct | CPU時間を割り当てる、, ウェイト クォータを設定する |
| メモリー | RAMを制限し、OOMキルを回避 |
| ブルキオ | スロットルブロックI/O、読み取り/書き込み速度の制御 |
| cpuset | CPUコアとNUMAノードの割り当て |
| デバイス | デバイスへのアクセスを許可またはブロックする |
| net_cls / net_prio | ネットワーククラスをマークし、優先順位をつける |
ホスティングにおけるcgroups v1とv2の比較
古いv1ではコントローラーがいくつかのツリーに分かれていて、大規模なセットアップでは混乱することがすぐにわかりました。 コンバージョン を v2 に変更しました。cgroups v2では、すべてが明確なツリーにバンドルされるため、管理、デバッグ、継承が簡素化される。さらに、v2 の cpu.max、cpu.weight、memory.max は、首尾一貫したレバーのセットを提供し、うまく連携する。コンテナ・オーケストレーターも、セマンティクスがより標準化されているため、v2の使用を好む。そのため、多くのクライアントを抱えるホスティング環境では、v2の方が無駄がなく、信頼性の高い選択となる。.
cgroups v2での細かいコントロール:io、メモリ、pid、PSI
v2では、サブツリーごとに明示的にコントローラを有効にし、継承をよりコントロールできるようになりました。親ノードで許可した場合のみ、子グループで使用することができます。これは、無秩序な成長を防ぎ、クリーンなポリシーを保証します。.
# ルートノードの子ノードのコントローラをアクティブにする
echo "+cpu +io +memory +pids" > /sys/fs/cgroup/cgroup.subtree_control
# サブグループを作成し、ワークスペースとして使用する
mkdir /sys/fs/cgroup/prod-web
I/Oについては、(blkioの代わりに)v2のioコントローラーを使っている。メジャー:マイナー指定でデバイスごとに帯域幅やIOPSの制限を設定している。これにより、ログ、インデックス、バックアップがディスクを詰まらせないようにしている。.
# /dev/sda (8:0)のデバイスは、読み込み50MiB/s、書き込み20MiB/sに制限される。
echo "8:0 rbps=50M wbps=20M" > /sys/fs/cgroup/prod-web/io.max
# ウェイトを相対的に割り当てる (ハードキャップの代わりに 100-10000、デフォルトは 100)
echo 500 > /sys/fs/cgroup/prod-web/io.weight
私はメモリを2段階に分けて設定している。memory.highは早い段階でスローダウンさせ、memory.maxはハードストップさせる。また、レイテンシーが爆発しないように、重要なサービスではスワップを停止している。.
# ソフトブレーキ(ソフトリミット)とハードカバー
エコー $((400*1024*1024))> /sys/fs/cgroup/prod-web/memory.high
echo $((512*1024*1024))> /sys/fs/cgroup/prod-web/memory.max
# スワップ禁止 (0) または制限 (例えば 128 MiB)
echo 0 > /sys/fs/cgroup/prod-web/memory.swap.max
私はpidsコントローラーを使って、フォーク・ストームを防ぎ、クライアントごとのプロセスとスレッドの上限を維持している。これは、共有環境での設定ミスや誤用に対する効果的な保護だ。.
# グループ内のプロセス/スレッドの最大数 512
echo 512 > /sys/fs/cgroup/prod-web/pids.max
診断には、グループごとにcgroup.eventsとPSI(Pressure Stall Information)を使っている。PSIは、CPU、メモリ、I/Oが定期的に低下し、待ち時間が発生しているかどうかを示してくれる。これは、ユーザーが気づく前にボトルネックを可視化するので、純粋な利用率よりも価値がある。.
# イベントとプレッシャーを読み出す
cat /sys/fs/cgroup/prod-web/cgroup.events
cat /sys/fs/cgroup/prod-web/cpu.pressure
cat /sys/fs/cgroup/prod-web/memory.pressure
cat /sys/fs/cgroup/prod-web/io.pressure
OOMの状況では、私は特にmemory.oom.groupでkillをバンドルし、システムを部分的に麻痺状態にするのではなく、関連するプロセス(例えばworker + helper)を一貫して終了させるようにしている。メンテナンスウィンドウの場合は、cgroup.freezeでグループを一時的にフリーズし、再びフリーズを解除する。.
# OOMのグループ全体の動作
echo 1 > /sys/fs/cgroup/prod-web/memory.oom.group
# 一時停止/再開グループ
echo 1 > /sys/fs/cgroup/prod-web/cgroup.freeze
echo 0 > /sys/fs/cgroup/prod-web/cgroup.freeze
ステップ・バイ・ステップ:Linuxでの制限設定
現在のカーネルを搭載したサーバーでは、cgroup v2を有効にして、適切な上限を持つグループを作成する。 コントロール をシステムに直接インストールする。以下のコマンドは、CPUとRAMに制限をかけた最小限の例です。私はクォータを保守的に選択し、負荷を監視し、反復して調整する。こうすることで、有用なバーストフェーズを不必要にカットすることなく、応答時間を低く保つことができる。この実装はカーネルに近いままであり、パネル・ソフトウェアとは独立して動作する。.
# cgroup v2 をマウントする(systemd 経由で自動的にマウントされない場合)
mount -t cgroup2 none /sys/fs/cgroup
#グループを作成する
mkdir /sys/fs/cgroup/prod-web
#プロセス(例:PID 1234)をグループに割り当てる。
echo 1234 > /sys/fs/cgroup/prod-web/cgroup.procs
#のCPUクォータ: 200msのうち100ms => 50%
echo "100000 200000" > /sys/fs/cgroup/prod-web/cpu.max
# RAMハードリミット: 512 MiB
echo $((512*1024*1024))> /sys/fs/cgroup/prod-web/memory.max
Systemdの統合と永続スライス
日常生活では、cgroupツリーの管理はsystemdに任せている。そのため、制限が残っている しつこい で、各サービスごとに透過的にドキュメント化されている。私はスライス(system.slice、user.slice、machine.slice)で作業し、クライアントやロールのために独自の階層を定義します。sys/fs/cgroupに手動で書き込むことなく、ドロップインファイルを使って重みと上限を設定しています。.
# 例: ウェブサービス用に独自のスライスを作成する
cat > /etc/systemd/system/web.slice < /etc/systemd/system/php-fpm.service.d/10-slice.conf <<'EOF'
[サービス]
スライス=web.slice
EOF
systemctl デーモン再ロード
php-fpm.service を再起動する
アドホック・テストでは、ユニット・ファイルを書かずにスコープでプロセスを開始する。これは、負荷のピークをシミュレートしたり、短時間の制限を試したりするのに適しています。.
# 簡単にリソースを設定し、制御下のプロセスを起動する。
systemd-run --scope -p CPUWeight=200 -p MemoryMax=512M
-p IOReadBandwidthMax=/dev/sda:50M -p IOWriteBandwidthMax=/dev/sda:20M ୧-͈ᴗ-͈)
stress-ng --vm 1 --vm-bytes 300M --cpu 1
コンテナランタイムはsystemdのもとで自分のスライス(machine.slice)を管理する。ランタイムサービスにサブツリーの管理(デリゲート)を任せることで、ポッド/コンテナがきれいに分離されます。これは、ホストとコンテナのポリシーが重ならないことを意味する。.
容器の制限を安全に使用する
コンテナ環境では、cgroupは目に見えないガードレールとして機能し、ランタイムパラメータで設定します。 コンテナ を公正な制限に変換する。例えば、Dockerは-cpus、-memory、-blkioオプションを直接cgroupsにマッピングし、Kubernetesはリクエストとリミットをv2パラメータに変換する。一貫性は非常に重要です。ポッドやコンテナが不必要にスロットルしたり、OOMエラーを引き起こしたりしないように、制限は実際の負荷と一致しなければなりません。私は生産的なサービスをタイトに保ち、ビルドやテストジョブは必要な場合のみ予算を増やします。これにより、デプロイメントを予測可能に保ち、ロールアウトが停滞するのを防ぎます。.
共有ホスティングとうるさい隣人を避ける
共有環境では、パッケージまたはサブスクリプションのレベルで制限を設定します。 公平性 をクライアント間に割り当てることができます。Pleskのようなパネルでは、サブスクリプションごとにCPU、RAM、I/Oを割り当て、それらを視覚的に表示するCgroupsマネージャによって、これを簡単に行うことができます。また、通知を有効にして負荷のピークを認識し、即座に対応できるようにしています。テナント分離を詳しく比較したい場合は、以下を参照してください。 テナント断熱 スロー。これは、たとえ個々の顧客がより多くのトラフィックを生み出す時があったとしても、すべてのウェブサイトが反応し続けることを意味する。.
正しい制限の設定:cgroups vs ulimits
cgroupsは実際の使用量に上限を設けるが、ulimitsは主にプロセスごと、あるいはシェルごとのハードリミットである。 コンビネーション 具体的には。CPU、RAM、I/Oについてはcgroupsをクリアに設定し、オープンファイルやプロセスについてはulimitで追加制御している。これにより、ファイル記述子のボトルネックを防ぎつつ、全体的な使用率を抑えている。システム関連の制限をリフレッシュしたい場合は、以下のサイトで概要を見ることができます。 ホスティングの制限. .両レベルとも、公正な顧客分離のための最も細かい調整ネジを提供する。.
モニタリングとアラート
測定がなければ、私はやみくもに決断を下すことになる。 しきい値 アラーム用だ。systemd-cgtop、ps、pidstat、Prometheus-Exporterなどのツールは、現在どのグループがリソースを使用しているかをライブで表示してくれる。パネルでは、cグループをダッシュボードにリンクして、しきい値をマークし、トレンドを視覚化する。グループが制限を超えたり、スロットルが頻繁に発生したりすると、メールやチャットでアラートが通知される。これにより、早期にボトルネックを特定し、制限を調整したり、ハードウェアを拡張したり、コードパスを最適化したりすることができる。.
詳細なモニタリング:主要数値、PSI、意味のあるアラーム
私は「使用率」だけでなく「圧力」もモニターしている。cgroups v2では、cpu.stat(throttled_usを含む)、memory.current、memory.high、memory.events、io.stat、そしてpressureファイルを読んでいる。私はこれらを使って、短いピーク時にイライラさせることなく、早い段階でリソース不足に反応するアラームを作成している。.
- CPU:throttled_usが恒常的に増加し、同時にレイテンシーが悪化した場合に警告を出す。それからCPUWeightを増やすか、cpu.maxを緩める。.
- メモリ:memory.highに近いmemory.currentは警告シグナルである。memory.eventsが頻繁に „high “を報告する場合は、highを増やすか、キャッシュを最適化する。.
- I/O:io.statはrbps/wbpsと待ち時間を表示する。io.weightまたは専用デバイスによる恒久的なスロットリングを修正する。.
- PSI: 持続的な „some“/„full “プレッシャーは、ワークロードが定期的にリソースを待っていることを示す指標である。私はこれをキャパシティプランニングに利用している。.
クリーンコンフィギュレーションのベストプラクティス
ピーク時に鋭すぎるリッドは、私はいつも保守的な値から始める。 パフォーマンス コストがかかる。その後、ab、siege、wrkなどのベンチマークでサービスに負荷をかけ、クォータを徐々に増やしていきます。マルチアプリホストの場合、重要なサービスが優先されるようにスライスでグループを配置し、他のサービスからすべてを奪うことがないようにします。I/O制限を設定することで、短いピークはすり抜けるが、長いフェーズは遅くなるようにしている。定期的に見直すことで、負荷プロファイルが変化しても制限が陳腐化するのを防いでいる。.
v1からv2への移行:私はこう進める
通常のインフラストラクチャーのアップグレードのように、切り替えを計画する。まず、カーネルと systemd v2 がデフォルトで有効になっているかどうかをチェックする。必要であれば、適切なブートパラメータで開始し、ユニファイドツリーがアクティブであることを検証する。その後、ステージング環境ですべての統合(パネル、エージェント、バックアップ、コンテナランタイム)をテストする。.
- 検出: mount | grep cgroup2 または systemd-cgls は、v2 が実行中かどうかを示してくれる。.
- ブートパラメーター:必要であれば、cgroup_no_v1=allに設定するか、v2だけがアクティブになるようにオプションを統一する。.
- コントローラーのマッピング:blkioがioになる。いくつかのv1機能(net_cls/prio)をcgroupまたはBPF分類器によるトラフィックコントロールに置き換える。.
- ポリシーの移行:厳格なクォータの代わりにウェイトを使用し、memory.highを導入し、スワップを個別に制限する。.
- モニタリングのカスタマイズ:新しいパスとフィールド(cgroup.events、cpu.stat)をダッシュボードに転送。.
プロセス分離の追加
cgroupsはリソースの問題を解決してくれますが、システムアクセスのために 名前スペース とファイル・ビューがある。Chroot、CageFS、ネームスペース、ジェイルは、パス、カーネルオブジェクト、デバイスを封鎖し、クライアントが互いにアクセスできないようにする。この保護レイヤーは、被害範囲と攻撃対象範囲を縮小するため、制限に追加するのに便利です。最も重要な亜種の簡潔な概要はここにある: プロセス分離. .cgroupsと組み合わせることで、どのような規模のホスティングセットアップでも、クリーンなクライアント分離が実現します。.
実践的なシナリオとチューニング
CMSセットアップのトラフィックのピーク時には、CPUに短期的な余裕を持たせるが、RAMはハードにしておく。 セキュリティ OOMの失敗に対して。データ集約型のショップでは、インデックス作成が他のすべての読み取りプロセスを遅くしないようにblkioを調整している。ウェブワーカーが他のコアで邪魔されずに応答できるように、cpusetを使って分析プロセスやワーカープロセスをいくつかのコアに固定する。バックグラウンドジョブをCPUウェイトの低いグループに移動させ、フロントエンドのリクエストが流動的であるようにします。専用の顧客に対しては、memory.minを許可して、プレミアムアプリのための小さな保証RAMベースを確保します。.
トラブルシューティングと典型的な障害
いくつかのエラーパターンは繰り返される。トラブルシューティングの時間を節約するために、私は以下の点に注意している:
- CPU quotas too hard: 恒久的なスロットルはレイテンシーを増加させる。cpu.weightとcpu.maxは安全ベルトとしてのみ使用した方が良いでしょう。.
- OOMのないメモリプレッシャー:memory.highは効果的に制限するが、ページキャッシュの上限が高すぎるとI/Oレイテンシが増加する。キャッシュを選択的に微調整して切り詰める。.
- スワップの影響:スワップが多すぎるとシステムが遅くなる。したがって、重要なサービスはmemory.swap.max=0で運用し、システム全体は小さなバッファで保護する。.
- サブツリーの忘れ物:cgroup.subtree_controlにエントリがないと、子ノードの制限が適用されない。常に最初に親ノードのコントローラをアクティブにしてください。.
- 間違ったグループ: プロセスが間違ったスライスに入ることがある。systemd-cglsで確認し、サービスユニットのオプション(Slice=, Delegate=)を修正してください。.
- pids.max too low: 多くのワーカースレッドを持つデーモンがサイレントで失敗する。余裕のあるバッファを選択し、モニタリングで追跡する。.
- デバイスごとのI/O制限:RAID/LVMの場合、正しいメジャー:マイナーを使用するか、ワークロードが実際に使用する可視ブロックデバイスに制限を設定する。.
- ネットワークの優先順位付け:net_cls/prioはv1のレガシー。v2では、cgroupやBPF分類器を使ったトラフィックコントロールに頼っている。.
役割、プロファイル、公平性モデル
私は、テンプレートとして保存し、自動的に展開される明確なサービスプロファイルを使って仕事をしたい:
- プレミアム(ゴールド):CPUとI/Oのウェイトが高く、メモリ.minはベース保証、メモリ.maxは十分なリザーブがあるハードな制限。.
- スタンダード(シルバー):ウェイトは中程度、io.weightは中程度、memory.highはキャッシュのスプロールを避けるためピークよりやや下。.
- 背景(ブロンズ):低いCPU/I/Oウェイト、インタラクティブなワークロードを切り離すための厳格なcpu.max。.
また、ホストと中央インフラ(モニタリング、ロギング、バックアップ)用にコアとRAMを確保している。これにより、クライアントがシステムのオーバーヘッドを飲み込むのを防ぎます。NUMAホストの場合、私はcpusetを使って、使用するコアにローカルなメモリを確保しています。これにより、メモリを多用するサービスのレイテンシのピークを減らすことができます。.
簡単な要約
cgroupsを使って、CPU、RAM、I/O、ネットワークに明確なガードレールを設定する。 公平性 サービス間のボトルネックを緩和します。cgroups v2の標準化されたアーキテクチャにより、v1と比べて計画、運用、トラブルシューティングが容易になりました。コンテナ、共有ホスティング、混在環境において、「うるさい隣人」を抑え、重要なワークロードを保護することができます。モニタリングと便利なアラームは、制限が負荷プロファイルに合わなくなった時に、早い段階で知らせてくれる。cgroups とプロセス分離、ulimits、クリーンなチューニングを組み合わせれば、一貫したパフォーマンスとクライアントを公平に扱う信頼性の高いホスティングプラットフォームを構築できます。.


