1

私の Django Web アプリには、レート制限された API のクライアントであり、サーバー スレッドからその API へのすべての要求を処理するワーカー プログラムがあります。データベースを使用してタスク キューを格納します。タスクは大量に発生する場合もあれば、まったく発生しない場合もあります。イベントループを使用してキューをポーリングし、レート制限を超えた場合に備えてタスク間の遅延を管理しています (制限は動的です)。これはすべて正常に機能しますが、他にやりたいことは、キューが空になった場合にワーカーがデータベースへのアクセスを停止する方法と、Django アプリがキューがなくなったことをワーカーに通知する方法を用意することです。再び乾かします。

概略的には、疑似 Python では次のようになります。

state = NORMAL
delay_time = NORMAL_DELAY

while True:
    sleep(delay_time)

    if state == DORMANT:
        continue

    task = get_next_task() # hits database
    if task is None:
        state = DORMANT
        delay_time = NORMAL_TIME

    try:
        execute(task)
    except RateExceeded:
        delay_time = backoff(delay_time)
    else:
        delay_time = NORMAL_DELAY

# Triggered by web layer
def asynchronous_event():
    state = NORMAL

そして、状態をNORMALに戻すことができるWebレイヤーからトリガーされる非同期イベント(実行中に実行されるsleep)、または不要なループDBクエリを追加しない他の軽量チェックが必要です。

単一マシンのセットアップでは、シグナルを使用することもできますが、これは明らかに複数マシンのセットアップでは機能しません。この 1 つのシグナルのためだけに別のメッセージ キュー サーバーを実行する必要がないようにしています。ネットワークベースのソリューションが機能する場合に備えて、私は Dotcloud でホストされています。理想的には、シグナル ハンドラーとしての実装の容易さにおいて多かれ少なかれ同等のものです。ZeroRPC を調べましたが、イベント ループに組み込む方法がわかりません。

何か案は?

編集

この問題を解決するために ZeroMQ を調べていますが、助けが必要です。注意が必要なのは、複数の Web サーバー インスタンスが同時に存在することです。再デプロイ時には、1 つのワーカーから後続のワーカーにスムーズに移行する必要があります。私の用語はおそらく正しくないので、ご容赦ください。最善の方法は、各ワーカーをメールボックスとしてアドレスに非同期的にバインドし、メインループでチェックして休眠モードから復帰させることです。 . 各ワーカーは、IP のデータベースにレコードを作成し、作成日のタイムスタンプが付けられます。リクエストを送信すると、Web サーバーはすべてのワーカーにメッセージを発行します。ワーカーは、メッセージを受信すると、作成日が最新のワーカーであるかどうかを確認します。作成日が最新のワーカーである場合はメッセージを処理し、そうでない場合は自分自身を終了します。

これは大変なことのように思えますが、アプリケーションの他の場所でこのパラダイムを使用する可能性が高いため、これを正しく処理したいと考えています。

4

2 に答える 2

0

結局のところ、ループを繰り返すたびにデータベースにアクセスすることにしました。しかし、これを本当に効率的にするための努力をしたいのであれば、ZeroMQが進むべき道であるとも決めました。仕組みは次のとおりです。

各ワーカーはZeroMQサブスクライバーソケットをバインドし、ソケットのIPアドレスとポートを含むワーカーのデータベースに自分自身を登録します。WebスレッドはDO_TASK、最後に登録されたワーカーにメッセージを公開し、作業QUITしている可能性のある他のワーカーにメッセージを公開します。

Dotcloudにデプロイしていますが、カスタムサービス環境変数とビルドオプションを使用すると、必要なポートを開いてワーカータスクインスタンスのIPを取得できるとのサポートがあります。

于 2013-02-02T05:46:21.360 に答える
0

delay_timeデータベースにタスクがない場合、指数バックオフをワーカー ジョブに適用するのはどうですか? これにより、Web アプリからワーカー ジョブにメッセージを送信するという複雑さを増やさずに、DB の負荷を十分に減らすことができます。何かのようなもの:

delay_time = NORMAL_DELAY

while True:
    sleep(delay_time)
    task = get_next_task() # hits database

    if task:
        try:
            execute(task)
        except RateExceeded:
            pass
        else:
            delay_time = NORMAL_DELAY
            continue

     delay_time = backoff(delay_time)
于 2013-01-24T20:02:35.040 に答える