web-dev-qa-db-ja.com

Linuxカーネルのcpuset cgroup継承セマンティクスについて「壊れている」とは何ですか?

新しいコントロールグループインターフェイスの2013 systemdの発表 を引用するには(強調を追加):

ユニットプロパティとして現在公開されているcgroup属性の数は制限されています。カーネルインターフェイスがクリーンアップされるため、これは後で拡張されます。たとえば、cpusetまたはfreezerは、カーネルロジックの継承セマンティクスが壊れているため、現在はまったく公開されていません。また、実行時にユニットを別のスライスに移行するカーネルには現在アトミックcgroupサブツリーの移動がないため、サポートされていません(つまり、実行中のユニットのSlice =プロパティの変更)。

それで、cpusetのカーネルロジックの継承セマンティクスについて何が壊れていますか(そして、この壊れ方はcpuなどの他のcgroupコントローラーには適用されません)?

RedHatのWebサイトの記事 は、管理が容易なsystemdユニットプロパティとしてサポートされていないにもかかわらず、RHEL 7でcgroup cpusetsを使用する方法について未検証のソリューションを提供しています...考え?上記の太字の引用が関係しています。

言い換えると、ここで参照されているcgroup v1 cpusetの使用に適用できる「落とし穴」(落とし穴)は何ですか?


私はこれについて賞金を始めています。

この質問に(特別な順序ではなく)回答するための考えられる情報源は次のとおりです。

  1. cgroup v1のドキュメント。
  2. カーネルのソースコード。
  3. 試験結果;
  4. 実際の経験。

上記の引用の太字の行の1つの考えられる意味は、新しいプロセスがフォークされたときに、親と同じcpuset cgroupにとどまらないか、同じcgroupにあるが何らかの「非強制」ステータスにあることです。これにより、cgroupで許可されているのとは異なるCPUで実際に実行されている可能性があります。しかし、これは私の部分の純粋な推測です、私は明確な答えが必要です。

5
Wildcard

Cpusetsの少なくとも1つの明確で未解決の問題は、カーネルバグトラッカーに次のように記載されています。

バグ42789 -cpuset cgroup:CPUがオフラインになると、すべてのcgroupのcpuset.cpusから削除されますが、オンラインになると、ルートcpuset.cpusにのみ復元されます

チケットから 1つのコメント を引用するには(実際のコミットにハイパーリンクを追加し、スパムボットの場合はIBMメールアドレスを削除します):

これはPrashanth Nageshappaによって独立して報告され、コミット 8f2f748b0656257153bcf0941df8d6060acc5ca6 で修正されましたが、その後Linusによってコミット 4293f20c19f44ca66e5ac836b411d25e14b9f185 として戻されました。彼のコミットによると、修正により他の場所でリグレッションが発生しました。

修正コミット(後で元に戻されました)は問題をよく説明しています:

現在、CPUホットプラグ時に、cpusetコールバックはシステムの状態を反映するようにcpusetsを変更し、この処理は非対称です。つまり、CPUがオフラインになると、そのCPUはすべてのcpusetから削除されます。ただし、オンラインに戻ると、ルートcpusetにのみ戻されます。

これにより、一時停止/再開中に重大な問題が発生します。サスペンド中は、すべての非ブートCPUをオフラインにし、レジ​​ューム中はオンラインに戻します。つまり、再開後、すべてのcpusets(ルートcpusetを除く)は単一のCPU(ブートcpu)だけに制限されます。しかし、サスペンド/レジュームの全体のポイントは、システムをサスペンドする前の状態に可能な限り近い状態にシステムを復元することです。


同じ非対称ホットプラグの問題について、継承との関係をさらに詳しく説明します。

バグ188101 -cgroupのcpusetのプロセススケジューリングが正しく機能していません。

そのチケットを引用する:

コンテナーのcpuset(docker/lxcは両方とも基盤となるcgroupを使用)が空になると(hotplug/hotunplugにより)、そのコンテナーで実行されているプロセスは、最も近い空でない祖先のcpusetの任意のcpuでスケジュールできます。

ただし、実行中のコンテナー(docker/lxc)のcpusetが空の状態から空になった場合(echoメソッドを使用して)実行中のコンテナーのcpusetを更新することにより、そのコンテナーで実行されているプロセスそれでも、最も近い空でない祖先と同じcpusetを使用します。


Cpusetには他にも問題がある可能性がありますが、「カーネルロジックの継承セマンティクスが壊れているため」systemdがcpusetを公開または利用しないというステートメントを理解して理解するには、上記で十分です。

これらの2つのバグレポートから、再開後にCPUがcpusetに戻されないだけでなく、are(手動で)追加された場合でも、そのcgroupのプロセスは引き続きcpusetによって許可されていない可能性のあるCPUで実行したままにします。


私はこれを理由として直接確認する Lennart Poetteringからのメッセージ を見つけました(太字を追加):

2016年8月3日水曜日の16:56 +0200に、レナートポエタリングは次のように書いています。

水曜日、03.08.16 14:46、Werner Fink博士(suse.deのwerner)は次のように書いています:

cPUホットプラグイベント(オフライン/オンライン)を繰り返すv228の問題(そして、これは後で現在のgitのログからのAFAICSでもあると思います)。根本的な原因は、cpuset.cpusがmachinedによって復元されないことです。 libvirtは許可されていないため、これを実行できないことに注意してください。

これはカーネルcpusetインターフェースの制限であり、それが現在systemdでcpusetsをまったく公開しない理由の1つです。ありがたいことに、 cpusetsの代わりに、systemdのCPUAffinity =を介して公開されたCPUアフィニティコントロールは、ほとんど同じことを行いますが、セマンティクスがあまり重要ではありません。

Systemdで直接cpusetsをサポートしたいのですが、カーネルインターフェースが現状のままである限り、これは行いません。たとえば、cpusetsは、システムがサスペンド/レジュームサイクルを通過すると、現在完全にフラッシュされます。

3
Wildcard

私は決定的な答えを出すのに十分なcgroupsに精通していません(そして2013に戻ったcgroupsの経験は確かにありません!)が、Vanilla Ubuntu 16.04 cgroups v1ではそれが一緒に動作しているようです:

子供を使用して別のユーザーとしてforkすることを強制する小さなテストを考案しましたSudo /bin/bash&--Hフラグは、ルートのホーム環境でSudoを強制的に実行するための特別なパラノイアです。

cat <(whoami) /proc/self/cgroup >me.cgroup && \
Sudo -H /bin/bash -c 'cat <(whoami) /proc/self/cgroup >you.cgroup' & \
sleep 2 && diff me.cgroup you.cgroup

これにより、

1c1
< admlocal
---
> root

参考までに、これは私のシステムのcgroupマウントの構造です。

$ mount | grep group
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
lxcfs on /var/lib/lxcfs type Fuse.lxcfs (rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other)
$
4
Sirio Balmelli

Linuxカーネルのcpuset cgroup継承セマンティクスについて「壊れている」とは何ですか?

「現在、ユニットプロパティとして公開されているcgroup属性の数は制限されています。これは、カーネルインターフェースがクリーンアップされるため、後で拡張されます。たとえば、cpusetまたはfreezerは現在、カーネルロジックの継承セマンティクスが壊れているため、すべてが原因です。また、実行時にユニットを別のスライスに移行すること(つまり、実行中のユニットのSlice =プロパティの変更)はサポートされていません。アトミックcgroupサブツリーが移動しました。」

それで、cpusetのカーネルロジックの継承セマンティクスについて何が壊れていますか(そして、この壊れはどのようにcpuなどの他のcgroupコントローラーには適用されませんか?)

上記の太字の引用が関係しています。言い換えると、ここで参照されているcgroup v1 cpusetの使用に適用できる「落とし穴」(落とし穴)は何ですか?

本当に短い答え:コードはうまくマルチプロセスせず、さまざまなプロセスがPIDを解放し、子のPIDが終了する前にPIDを解放してプールに戻します-上流を離れてPIDの子がアクティブであると信じるので、そのPIDをスキップしますが、そのPID子供を解雇する前に再発行されるべきではありません。要するに、貧弱なロック。

サービス、スコープ、スライスは、管理者が自由に作成することも、プログラムで動的に作成することもできます。これは、起動時にOSによってセットアップされるデフォルトのスライスに干渉する可能性があります。

Cgroupsでは、プロセスとそのすべての子が、包含グループからリソースを引き出します。

Andはるかに...長い回答につながります...

多くの人々が懸念を表明しています:

  1. " Linuxコントロールグループはジョブではありません "(2016)Jonathan de Boyne Pollard氏:

    「ジョブ」の抽象化を提供するオペレーティングシステムカーネルは、「ジョブ」全体をキャンセル/強制終了する方法を提供します。たとえば、Win32 TerminateJobObject() メカニズムを目撃してください。

    Systemdがcgroup内のすべてのプロセスを終了するとき、単一の「ジョブの終了」システムコールを発行しません。そんなことはありません。代わりに アプリケーションモードコードのループ内にあります cgroup内のすべてのプロセスIDを繰り返しスキャンし(PID番号でいっぱいのファイルを再度読み取ることにより)、新しいプロセスにシグナルを送信します。前に見た。これにはいくつかの問題があります。

    • systemdは、プロセスグループ内の子プロセスを取得しているものよりも遅くなる可能性があり、終了シグナルが完全に間違ったプロセスに送信される可能性があります。systemdがcgroupのプロセスリストファイルを読み取り、プロセスのリストにシグナルを送信するために実際に動き回っています。 ...

    ...

    • Cgroup内で迅速に新しいプロセスをフォークするプログラムは、systemdのスピンを長期間、理論的には適切な「天候」が続く限り無期限に継続できます。ループの各反復で、キルするプロセスがもう1つあるためです。これはフォーク爆弾である必要はありません。 systemdがループを実行するたびにcgroupで少なくとも1つ以上の新しいプロセスIDを確認できるようにするために、十分にフォークする必要があります。

    • systemdは、すでにシグナルを送っているプロセスのプロセスIDをセットに保持して、シグナルの再送信を試みないプロセスを特定します。 ID Nのプロセスに信号が送られ、終了し、リーパー/親によってプロセステーブルから削除される可能性があります。そして、cgroup内の何かが、同じプロセスID Nを再度割り当てられた新しいプロセスをフォークします。 systemdはcgroupのプロセスIDリストを再度読み取り、それが新しいプロセスにすでにシグナルを送っており、まったくシグナルを送っていないと考えます。

    これらは、真の「ジョブ」メカニズムによって対処されます。しかし、cgroupはそうではありません。 cgroupsは、伝統的で有名な設計上の欠陥のいくつかに対処する、伝統的なUnixリソース制限メカニズムの改善として意図されました。これらは、VMSや Windows NTジョブオブジェクト と同等になるようには設計されていません。

    いいえ、冷凍庫は答えではありません。 systemdは冷凍庫を使用しないだけでなく、systemdの人々は、「 カーネルロジックの継承のセマンティクスが壊れている 」を持っていると明示的に説明しています。あなたは彼らにそれが何を意味するのか尋ねる必要がありますが、フリーザーはcgroupを魔法のように仕事のメカニズムに変えません。

    さらに、これは、Dockerや他の人が独自の目的でコントロールグループのフリーズステータスを操作することは言うまでもありません。また、アトミックな読み取りと更新など、複数の所有者の間でこの設定を共有するための実際の競合のないメカニズムはありません。それのための。
    これにより、最後の変更日付スタンプが保持されている限り、このWebページを元の変更されていない形式でコピーおよび配布することが許可されます。

    • TerminateJobObject() 関数

      Terminates all processes currently associated with the job. If the  
      job is nested, this function terminates all processes currently  
      associated with the job and all of its child jobs in the hierarchy. 
      
    • Windows NTジョブオブジェクト

      A job object allows groups of processes to be managed as a unit.  
      Job objects are namable, securable, sharable objects that control  
      attributes of the processes associated with them. Operations  
      performed on a job object affect all processes associated with the  
      job object. Examples include enforcing limits such as working set   
      size and process priority or terminating all processes associated 
      with a job.
      

    Theanswer提供されるジョナサンの説明では:

    systemdのリソース制御の概念

    ...

    サービス、スコープ、スライスユニットは、cgroupツリー内のオブジェクトに直接マッピングされます。これらのユニットがアクティブ化されると、ユニット名から作成されたcgroupパスに直接(一部の文字をエスケープして)マッピングされます。たとえば、スライスfoobar-waldo.sliceのサービスquux.serviceは、cgroup foobar.slice/foobar-waldo.slice/quux.service /にあります。

    サービス、スコープ、スライスは、管理者が自由に作成することも、プログラムで動的に作成することもできます。ただし、デフォルトでは、OSはシステムの起動に必要な多数の組み込みサービスを定義します。また、デフォルトで4つのスライスが定義されています。最初に、ルートスライス-.slice(前述)だけでなく、system.slice、machine.slice、user.sliceもあります。デフォルトでは、すべてのシステムサービスが最初のスライスに配置され、すべての仮想マシンとコンテナが2番目のスライスに配置され、ユーザーセッションが3番目のスライスに配置されます。ただし、これは単なるデフォルトであり、管理者は新しいスライスを自由に定義して、サービスとスコープをそれらに割り当てることができます。 VMおよびコンテナープロセスと同様に、すべてのログインセッションは自動的に個々のスコープユニットに配置されます。最後に、ログインしているすべてのユーザーは、すべてのセッションがスコープが配置されます

    ...

    ご覧のとおり、サービスとスコープにはプロセスが含まれており、スライスに配置されています。スライスには独自のプロセスは含まれていません。また、特別な「-.slice」はツリー全体のルートで暗黙的に識別されるため、表示されていないことにも注意してください。

    リソースの制限は、同じ方法でサービス、スコープ、スライスに設定できます。 ...

簡単な説明については、上記のリンクをたどってください。

  1. " Cgroups v2:リソース管理は2回目にさらに悪化します "(2016年10月14日)、davmacによる:

    ...

    他のグループ内にグループが存在するようにネストされた階層を作成でき、ネストされたグループは親グループのリソースを共有します(さらに制限される場合があります)。 PIDをグループの制御ファイルの1つに書き込むことにより、プロセスをグループに移動します。したがって、グループには潜在的にプロセスとサブグループの両方が含まれます。

    制限したい2つの明らかなリソースはメモリとCPU時間であり、これらのそれぞれに「コントローラー」がありますが、潜在的に他のもの(I/O帯域幅など)があり、一部のCgroupコントローラーは実際にリソース使用率を管理しませんそのようなもの(例えば「冷凍庫」コントローラ/サブシステム)。 Cgroups v1インターフェースでは、異なるコントローラーが接続された複数の階層を作成できました(この値は不明確ですが、可能性はあります)。

    重要なのは、プロセスは親グループのプロセスからcgroupメンバーシップを継承し、適切な特権がない限り、プロセスをcgroupの外(またはグループ)に移動できません。つまり、プロセスは、フォークによって課された制限を免れることができません。これをsetrlimitの使用と比較してください。RLIMIT_AS(アドレススペース)の制限を使用してプロセスのメモリの使用(たとえば)を制限できますが、プロセスはforkでき、その子は元のリソースから描画せずに追加のメモリを消費できます。処理する。一方、Cgroupの場合、プロセスとそのすべての子は、包含グループからリソースを引き出します。

    ...

    cgroupコントローラーは、システム管理の疑似ファイルシステムにコントロールノブを追加するだけだったため、パブリックAPIとして決して受け入れられない多くのノブを実装しました。 cgroupは、適切に抽象化または洗練されておらず、カーネルの内部の詳細を直接明らかにしていないインターフェースノブで終わりました。

    これらのノブは、明確に定義されていない委任メカニズムを通じて個々のアプリケーションに公開され、必要な精査を受けることなく、パブリックAPIを実装するショートカットとしてcgroupを効果的に悪用しました。

    ...

    cgroup v1では、cgroupにスレッドを含めることができました。これにより、親cgroupとその子cgroupに属するスレッドがリソースを奪い合うという興味深い問題が発生しました。 2つの異なるタイプのエンティティが競合し、それを解決する明確な方法がなかったため、これは厄介でした。コントローラーが異なれば、実行する処理も異なります。

  2. Cgroup v2のドキュメントも参照してください: " v1の問題とv2の根拠 ":

    複数の階層

    cgroup v1は任意の数の階層を許可し、各階層は任意の数のコントローラーをホストできました。これは高度な柔軟性を提供するように見えましたが、実際には役に立ちませんでした。

    たとえば、各コントローラーのインスタンスは1つしかないので、すべての階層で役立つことができるフリーザーなどのユーティリティタイプのコントローラーは、1つでしか使用できません。この問題は、いったん階層が設定されるとコントローラーを別の階層に移動できないという事実によって悪化します。もう1つの問題は、階層にバインドされたすべてのコントローラーが、階層のまったく同じビューを持つことを余儀なくされたことです。特定のコントローラーによって粒度を変えることはできませんでした。

    実際には、これらの問題により、同じコントローラに配置できるコントローラが大幅に制限され、ほとんどの構成では、各コントローラを独自の階層に配置することに頼っていました。 cpuやcpuacctコントローラーなど、密接に関連するものだけを同じ階層に配置するのが理にかなっています。これは、階層管理操作が必要な場合は常に、ユーザーランドが複数の類似した階層を管理して、各階層で同じ手順を繰り返すことを意味することがよくありました。

    さらに、複数の階層のサポートには多大なコストがかかりました。 cgroupコアの実装は非常に複雑になりましたが、さらに重要なことに、複数の階層のサポートにより、cgroupの一般的な使用方法とコントローラーが実行できる機能が制限されました。

    階層の数に制限はありませんでした。つまり、スレッドのcgroupメンバーシップを有限長で説明することはできませんでした。キーには任意の数のエントリを含めることができ、長さに制限がないため、操作が非常に厄介であり、メンバーシップを識別するためにのみ存在するコントローラーの追加につながり、階層数が増加するという元の問題をさらに悪化させました。

    また、コントローラーは他のコントローラーがオンになっている可能性のある階層のトポロジーについて何も期待できないため、各コントローラーは他のすべてのコントローラーが完全に直交する階層に接続されていると想定する必要がありました。これは、コントローラーが互いに協力することを不可能、または少なくとも非常に面倒にしました。

    ほとんどの場合、相互に完全に直交する階層にコントローラを配置する必要はありません。通常求められるのは、特定のコントローラーに応じて、さまざまなレベルの細分性を持つ機能です。つまり、特定のコントローラから見ると、階層がリーフからルートに向かって折りたたまれている可能性があります。たとえば、特定の構成では、CPUサイクルの分散方法を制御しながら、特定のレベルを超えてメモリがどのように分散されるかを気にしない場合があります。

詳細については、セクション3のリンクを参照してください。

  1. Lennart Poettering(systemd開発者)とDaniel P. Berrange(Redhat)の間の水曜日の20.07.16 12:53 systemd-devel archives から取得した通信: " [systemd-devel ] cpusetコントローラーを介してすべてのプロセスをCPU/RAMに制限する ":

    水曜日、20.07.16 12:53、Daniel P. Berrange(redhat.comのberrange)は次のように書いています。

    仮想化されたホストの場合、すべてのホストOSプロセスをCPU/RAMノードのサブセットに限定し、残りをQEMU/KVMが独占的に使用できるようにすることは非常に一般的です。歴史的に人々はこれを行うために「isolcpus」カーネル引数を使用していましたが、昨年そのセマンティクスが変更されたため、そこにリストされたすべてのCPUもスケジュールによって負荷分散から除外され、一般的な非リアルタイムの使用例ではまったく役に立たなくなりましたQEMUスレッドをCPU間で負荷分散する必要がある場合。

    したがって、唯一のオプションは、cpuset cgroupコントローラーを使用してプロコースを制限することです。申し訳ありませんが、systemdは現時点ではcpusetコントローラーを明示的にサポートしていません。そのため、systemdのバックの背後でこれを実現する「最適な」方法を考えながら、将来のsystemdのリリースで問題が発生するリスクを最小限に抑えています。

    2016年7月20日水曜日の03:29:30 PM +0200に、Lennart Poetteringは次のように返信しました。

    はい、現時点ではサポートしていませんが、サポートしたいと考えています。ただし、カーネルインターフェイスは現在のところかなり整備されておらず、修正されない限り、systemdでこれをサポートすることはほとんどありません。 (そして、私がTejunを理解したように、cpusetのmem対cpuの事柄は、おそらくそれがそうであるようにとどまることはないでしょう)。

    次のメッセージ

    水曜日、20.07.16 14:49に、Daniel P. Berrange(redhat.comのberrange)は次のように書いています。

    cgroupsv2は、ディストリビューションが切り替わると多くのことを壊す可能性が高いので、マイナーアップデートでは行われないと思います-メジャーな新しいディストリビューションリリースだけなので、心配はいりません。

分かりやすくなるといいですね。

1
Rob