26

mod_wsgiのマルチプロセッシング機能と、マルチプロセッシング機能を備えたWSGIサーバーで実行されるWSGIアプリケーションの一般的な設計について少し混乱しています。

次のディレクティブを検討してください。

WSGIDaemonProcess example processes=5 threads=1

私が正しく理解していれば、mod_wsgiは5つのPython(CPythonなど)プロセスを生成し、これらのプロセスのいずれもユーザーからのリクエストを受け取ることができます。

ドキュメントには次のように書かれています。

共有データをすべてのアプリケーションインスタンスに表示する必要がある場合、それらが実行する子プロセスに関係なく、あるアプリケーションによってデータに加えられた変更は、別の子プロセスでの実行を含め、別のアプリケーションですぐに利用できます。データベースまたは共有メモリを使用する必要があります。通常のPythonモジュールのグローバル変数は、この目的には使用できません。

ただし、その場合、アプリが任意のWSGI条件(マルチプロセッシング条件を含む)で実行されることを確認したい場合は、非常に重くなります。

たとえば、接続されているユーザーの現在の数を含む単純な変数-memcachedから/へのプロセスセーフな読み取り/書き込み、DB、または(そのような標準外のライブラリメカニズムが利用可能な場合)共有メモリー?

そして、コードは次のようになります

counter = 0

@app.route('/login')
def login():
    ...
    counter += 1
    ...

@app.route('/logout')
def logout():
    ...
    counter -= 1
    ...

@app.route('/show_users_count')
def show_users_count():
    return counter

マルチプロセッシング環境で予期しない動作をしますか?

ありがとうございました!

4

3 に答える 3

24

あなたの質問で考慮すべきいくつかの側面があります。

まず、ApacheMPMとmod_wsgiアプリケーション間の相互作用。mod_wsgiアプリケーションを埋め込みモードで実行する場合(WSGIDaemonProcess不要WSGIProcessGroup %{GLOBAL})、apacheMPMからマルチプロセッシング/マルチスレッドを継承します。これが最速のオプションであり、MPM構成に応じて、プロセスごとに複数のプロセスと複数のスレッドが存在することになります。逆に、デーモンモードでmod_wsgiを実行するWSGIDaemonProcess <name> [options]と、とを使用して、わずかなオーバーヘッドWSGIProcessGroup <name>を犠牲にしてマルチプロセッシング/マルチスレッドを細かく制御できます。

単一のapache2サーバー内で、0、1、または複数の名前付きWSGIDaemonProcessesを定義でき、各アプリケーションはこれらのプロセスの1つ(WSGIProcessGroup <name>)で実行することも、。を使用して組み込みモードで実行することもできますWSGIProcessGroup %{GLOBAL}

wsgi.multithreadおよびwsgi.multiprocess変数を調べることにより、マルチプロセッシング/マルチスレッドをチェックできます。

構成WSGIDaemonProcess example processes=5 threads=1では、5つの独立したプロセスがあり、それぞれが単一の実行スレッドを持ちます。スポーンサブプロセスを制御できないため、グローバルデータも共有メモリもありませんが、mod_wsgiがそれを実行します。グローバル状態を共有するために、いくつかの可能なオプションをすでにリストしました。プロセスがインターフェースするDB、ある種のファイルシステムベースの永続性、デーモンプロセス(apacheの外部で開始)、およびソケットベースのIPCです。

Roland Smithが指摘しているように、後者は、サーバープロセスmultiprocessing.managersを作成して開始するApacheの外部で高レベルのAPIを使用して実装できます。BaseManager

m = multiprocessing.managers.BaseManager(address=('', 12345), authkey='secret')
m.get_server().serve_forever()

そしてあなたのアプリの中であなたconnect

m = multiprocessing.managers.BaseManager(address=('', 12345), authkey='secret')
m.connect()

上記の例はm、有用なメソッドが登録されていないためダミーですが、ここ(python docs)では、プロセス間でオブジェクト(例のように)を作成してプロキシする方法を説明しますcounter

例の最後のコメントprocesses=5 threads=1。これは単なる例であることを理解していますが、実際のアプリケーションでは、パフォーマンスは次の点で同等になるとprocesses=1 threads=5思います。マルチプロセッシングでデータを共有する複雑さは、「単一プロセスの多数のスレッド」よりも期待されるパフォーマンスが向上する場合にのみ行う必要があります。モデルは重要です。

于 2012-10-08T13:28:03.113 に答える
4

wsgiのプロセスとスレッドに関するドキュメントから:

Apacheが複数の子プロセスが存在するモードで実行されている場合、各子プロセスには各WSGIアプリケーションのサブインタープリターが含まれます。

つまり、構成では、それぞれ1つのスレッドを持つ5つのプロセスに、5つのインタープリターがあり、共有データはありません。カウンターオブジェクトは、各インタープリターに固有のものになります。セッションをカウントするためのカスタムソリューションを構築する必要があります(通信できる一般的なプロセスの1つ、永続性ベースのソリューションなど)。または、これは間違いなく私の推奨事項です。事前に構築されたソリューションを使用してください(GoogleAnalyticsとChartbeatは素晴らしいオプション)。

私は、グローバルを使用してデータを共有することを、グローバルな悪用の大きな形と考える傾向があります。これは、私が並列処理を行ったほとんどの環境でのバグであり、移植性の問題です。突然、アプリケーションが複数の仮想マシンで実行された場合はどうなりますか?これにより、スレッドとプロセスの共有モデルに関係なく、コードが破損します。

于 2012-10-05T19:30:30.860 に答える
2

を使用している場合、プロセス間でデータを共有する方法multiprocessing複数あります。配列は、プロセスに親子関係がある場合にのみ機能します(継承によって共有されます)。そうでない場合は、ManagerandProxyオブジェクトを使用してください。

于 2012-10-07T14:03:06.087 に答える