web-dev-qa-db-ja.com

Python=に固執するか、それとも放棄すべきですか?

[〜#〜] loc [〜#〜] プロジェクトが Django で書かれており、かなりの量の CeleryRabbitMQ )必要に応じて非同期性とバックグラウンドジョブを実行し、システムの一部が何かで書き直されることでメリットがあるという結論に達しました Django以外の同時実行性。理由は次のとおりです。

  • Signals 処理および変更可能なオブジェクト。特に、1つの信号が別の信号をトリガーする場合、Djangoで [〜#〜] orm [〜#〜] を使用して信号を処理すると、インスタンスが変更または消失した場合に驚くかもしれません。渡されたデータがハンドラーで変更されないメッセージングアプローチを使用したい( Clojure's copy-on-writeアプローチは、うまくいけばいいようです)。
  • システムの一部はWebベースではないため、タスクを同時に実行するためのより良いサポートが必要です。たとえば、システムは [〜#〜] nfc [〜#〜] タグを読み取り、1つが読み取られるとLEDが数秒間点灯します(セロリタスク)、音が再生され(他のセロリタスク)、データベースが照会されます(他のタスク)。これはDjango管理コマンドとして実装されますが、DjangoとそのORMは本質的に同期であり、メモリを共有するのに制限があります(NFCリーダーを追加することを考えているので、 Django + Celeryのアプローチはもううまくいくと思いますが、より優れたメッセージパッシング機能を期待しています)。

TwistedTornado のようなものを使用することの長所と短所は、 Erlangなどの言語を使用する場合と比較して または Clojure ?私は実際的な利益と不利益に興味があります。

システムの一部が別の言語でうまく機能するとの結論にどうやって至ったのですか?パフォーマンスの問題がありますか?それらの問題はどの程度深刻ですか?それがより速くなる可能性がある場合、それがより速いことが不可欠ですか?

例1:Django HTTPリクエスト外での作業:

  1. NFCタグが読み取られます。
  2. データベース(および場合によってはLDAP)が照会され、データが利用可能になったときに何かを実行したい(赤または緑のライト、音を鳴らす)。これはDjango ORMの使用をブロックしますが、利用可能なCeleryワーカーがいる限り、それは問題ではありません。より多くのステーションで問題になる可能性があります。

例2:Djangoシグナルを使用した「メッセージパッシング」:

  1. post_deleteイベントが処理されます。これにより、他のオブジェクトが変更または削除される可能性があります。
  2. 最後に、通知がユーザーに送信されます。ここで、通知ハンドラーに渡された引数が削除済みまたは削除予定のオブジェクトのコピーであり、ハンドラー内で変更されないことが保証されているとしたら、すばらしいでしょう。 (もちろん、ORMによって管理されているオブジェクトをハンドラーに渡さないだけで、手動で行うこともできます。)
31
Simon Pantzare

冒頭の考え

システムの一部が別の言語でうまく機能するという結論にどうやって至ったのですか?パフォーマンスの問題がありますか?それらの問題はどの程度深刻ですか?それがより速くなる可能性がある場合、それがより速いことが不可欠ですか?

シングルスレッド非同期

シングルスレッドの非同期性とマルチスレッドの同時実行性の違い、長所、短所をすでに扱っているいくつかの質問やその他のWebリソースがあります。 Node.js's シングルスレッド非同期モデルがI/Oが主要なボトルネックであり、一度に多くのリクエストが処理されている場合のシングルスレッド非同期モデルの動作について読むのは興味深いです。

Twisted、Tornado、およびその他の非同期モデルは、シングルスレッドを効果的に使用しています。多くのWebプログラミングには多くのI/O(ネットワーク、データベースなど)があるため、リモート呼び出しの待機に費やされる時間は大幅に増加します。これは、他のデータベース呼び出しの開始、ページのレンダリング、データの生成など、他のことに費やす時間です。そのシングルスレッドの使用率は非常に高いです。

シングルスレッド非同期の最大の利点の1つは、使用するメモリがはるかに少ないことです。マルチスレッド実行では、各スレッドに一定量の予約済みメモリが必要です。スレッドの数が増えると、スレッドが存在するためだけに必要なメモリの量も増えます。メモリは有限なので、一度に作成できるスレッドの数に制限があることを意味します。


Webサーバーの場合、各リクエストに独自のスレッドが与えられているように見せかけます。各スレッドに1MBのメモリが必要で、Webサーバーには2GBのRAMがあるとしましょう。このWebサーバーは、これ以上処理するのに十分なメモリがなくなる前の任意の時点で(約)2000の要求を処理できます。

負荷がこれよりも大幅に高い場合、リクエストは非常に長い時間がかかります(古いリクエストが完了するのを待つとき)、または可能な同時リクエストの数を増やすために、より多くのサーバーをクラスターに投入する必要があります。 。


マルチスレッドの並行性

マルチスレッドの同時実行性は、代わりに複数のタスクを同時に実行することに依存しています。つまり、スレッドがブロックされてデータベースの呼び出しが戻るのを待機している場合、他の要求を同時に処理できます。スレッドの使用率は低くなりますが、実行されるスレッドの数ははるかに多くなります。

マルチスレッドのコードも、推論するのがはるかに困難です。ロック、同期、およびその他の楽しい同時実行性の問題があります。シングルスレッドの非同期は、同じ問題の影響を受けません。

ただし、マルチスレッドコードはCPUを集中的に使用するタスクのパフォーマンスがはるかに優れています。通常はブロックするネットワーク呼び出しなど、スレッドが「譲る」機会がない場合、単一スレッドモデルでは、同時実行性はまったくありません。

両方共存できます

もちろん、この2つは重複しています。それらは相互に排他的ではありません。たとえば、マルチスレッドコードは、各スレッドをより適切に利用するために、非ブロッキング方法で記述できます。


結論

他にも考慮すべき問題はたくさんありますが、私はこの2つについて次のように考えたいと思います。

  • プログラムがI/Oバウンドの場合、シングルスレッド非同期はおそらく非常にうまく機能します。
  • プログラムがCPUバインドの場合、マルチスレッドシステムがおそらく最適です。

特定のケースでは、完了している非同期作業の種類と、それらのタスクが発生する頻度を判別する必要があります。

  • リクエストごとに発生しますか?発生している場合、リクエスト数が増えるとメモリが問題になる可能性があります。
  • これらのタスクは順序付けされていますか?もしそうなら、複数のスレッドを使用する場合は同期を考慮する必要があります。
  • これらのタスクはCPUに負荷がかかりますか?その場合、シングルスレッドは負荷に追いつくことができますか?

簡単な答えはありません。ユースケースを検討し、それに応じて設計する必要があります。非同期のシングルスレッドモデルの方が良い場合があります。また、多数のスレッドを使用して大規模な並列処理を実現する必要がある場合もあります。

その他の考慮事項

選択する同時実行モデルだけでなく、他にも検討する必要がある問題があります。 ErlangまたはClojureを知っていますか?アプリケーションのパフォーマンスを向上させるために、これらの言語のいずれかで安全なマルチスレッドコードを記述できると思いますか?これらの言語の1つに習熟するのに長い時間がかかるのでしょうか。また、学習した言語は将来的に役に立ちますか?

これら2つのシステム間の通信に関連する問題はどうですか? 2つの別々のシステムを並行して維持することは過度に複雑になるでしょうか? ErlangシステムはどのようにDjangoからタスクを受け取りますか? Erlangはこれらの結果をDjangoにどのように伝えますか?パフォーマンスは、追加された複雑さがそれに見合うほど重要な問題ですか?


最終的な考え

私は常にDjangoで十分高速であることがわかりました。非常にトラフィックの多いサイトで使用されています。同時要求の数と応答時間を増やすために実行できるいくつかのパフォーマンス最適化があります。確かに、これまでCeleryで何もしていないので、通常のパフォーマンスの最適化では、これらの非同期タスクで発生する可能性のある問題はおそらく解決されません。

もちろん、問題により多くのハードウェアを投入するという提案は常にあります。新しいサーバーのプロビジョニングのコストは、まったく新しいサブシステムの開発および保守のコストよりも安いですか。

この時点であまりにも多くの質問をしましたが、それは私の意図でした。答えは、分析と詳細がなければ簡単ではありません。問題を分析できるということは、質問することを知ることにもなりますが、うまくいけば、私はその面で助けてくれました。

私の直感は、別の言語での書き換えは不要だと言っています。複雑さとコストはおそらく大きすぎるでしょう。


編集

フォローアップへの対応

フォローアップでは、いくつかの非常に興味深い使用例を紹介しています。


1. Django HTTPリクエスト外での作業

最初の例では、NFC=タグを読み取ってから、データベースにクエリを実行しました。別の言語でこの部分を書くことは、データベースまたはLDAPサーバーにクエリを実行するという理由だけで、それほど役に立ちません。はネットワークI/O(および場合によってはデータベースのパフォーマンス)によってバインドされます。一方、各管理コマンドは独自のプロセスとして実行されるため、同時リクエストの数はサーバー自体によってバインドされます。既に実行中のプロセスにメッセージを送信していないため、パフォーマンスに影響するセットアップ時間とティアダウン時間。ただし、それぞれが独立したプロセスになるため、同時に複数の要求を送信できます。

この場合、私はあなたが調査できる2つの道を見ます:

  1. データベースが接続プーリングで一度に複数のクエリを処理できることを確認してください。 (たとえば、Oracleでは、Djangoそれに応じて'OPTIONS': {'threaded':True}を構成する必要があります。)データベースレベルまたはDjango level独自のデータベースを微調整できることを確認します。データベースクエリを記述する言語に関係なく、LEDを点灯させるには、このデータが返されるのを待つ必要があります。クエリコードのパフォーマンスcanでも違いがあります。Django ORMは高速ではありません(but、通常は十分高速です)。
  2. セットアップ/ティアダウン時間を最小限に抑えます。常に実行中のプロセスを持ち、それにメッセージを送信します。 (私が間違っている場合は修正してください。ただし、これは元の質問が実際に焦点を当てているものです。)このプロセスがPython/Djangoで記述されているか、別の言語/フレームワークで記述されているかは、上記で説明しています。管理コマンドをそれほど頻繁に使用するのは好きではありません。 NFC=リーダーからのメッセージをメッセージキューにプッシュし、Celeryが読み取ってDjangoに転送する小さなコードを継続的に実行することは可能ですか?小さなコードのセットアップと破棄プログラムは、Python(ただしDjangoではない!)で記述されている場合でも)Djangoプログラム(そのすべてのサブシステムを含む)を起動および停止するよりも優れています) 。

DjangoにどのWebサーバーを使用しているかわかりません。 Apacheのmod_wsgiを使用すると、リクエストを処理するプロセス内のプロセスとスレッドの数を設定できます。サービス可能なリクエストの数を最適化するために、必ずWebサーバーの関連する構成を微調整してください。


2. Djangoシグナルによる「メッセージパッシング」

2番目の使用例もかなり興味深いものです。その答えがあるかどうかわかりません。モデルインスタンスを削除していて、後でそれらを操作したい場合、JSON.dumpsをシリアル化してからJSON.loadsを逆シリアル化できる可能性があります。関連フィールドはデータベースから遅延ロードされ、そのリンクは存在しなくなるため、後で(関連モデルのクエリ)オブジェクトグラフを完全に再作成することはできません。

他のオプションは、何らかの方法でオブジェクトを削除するためにmarkし、要求/応答サイクルの最後にのみ(すべてのシグナルが処理された後)削除することです。これを実装するには、post_deleteに依存するのではなく、カスタム信号が必要になる場合があります。

35
Josh Smeaton

私は主要な米国 [〜#〜] isp [〜#〜] に対して非常に高度でスケーラブルな開発を行いました。 Twisted サーバーを使用していくつかの深刻なトランザクション数を実行しました。Python/ CPUバインド =。 I/Oバウンド は問題ではありませんが、CPUバウンドは不可能でした。システムをすばやく組み立てることはできましたが、数百万の同時ユーザーに拡張できるようにすることは、CPUに拘束される場合、構成と複雑さの悪夢でした。

私はそれについてブログ投稿を書きました、Python/Twisted VS Erlang/OTP

TLDR; Erlang ウォン。

8
user7519

Twisted の実用的な問題(これは私が大好きで、約5年間使用しています):

  1. ドキュメンテーションは、何かが望まれるものを残し、モデルはとにかく学ぶのが非常に複雑です。他のPythonプログラマーにTwistedコードの作業を依頼するのは難しいと思います。
  2. 最終的には、適切なブロッキングAPIがないため、ブロッキングファイルI/Oとデータベースアクセスを使用することになりました。これは本当にパフォーマンスを低下させる可能性があります。
  3. Twistedを使用する巨大なコミュニティや健全なコミュニティはないようです。たとえば Node.js は、特にWebバックエンドプログラミングのために、より積極的な開発を行っています。
  4. それはまだPythonであり、少なくとも CPython は最速ではありません。

Node.jsで CoffeeScript を使用して少し作業を行いましたが、同時実行パフォーマンスが懸念される場合は、飛躍的に価値があるかもしれません。

Django の複数のインスタンスを実行することを検討しましたか?

4
Dickon Reed

別の言語への切り替えを検討する前に、次のことをお勧めします。

  1. LTTng を使用して、ページフォールト、コンテキストスイッチ、システムコール待機などのシステムイベントを記録します。
  2. Cライブラリを使用するのに時間がかかりすぎている場合は変換し、好きなデザインパターンを使用します(マルチスレッド、シグナルイベントベース、コールバック非同期、またはUnixの従来の select )。これはI/Oに適しています。

Pythonアプリケーションでパフォーマンスが優先されると、スレッドを使用しません。上記のオプションを使用すると、ソフトウェアの再利用や Django との接続など、多くの問題を解決できます、パフォーマンス、開発のしやすさなど.

1
holmes