web-dev-qa-db-ja.com

セロリワーカーデータベース接続プール

(Django内ではなく)Celeryスタンドアロンを使用しています。 1つのワーカータスクタイプを複数の物理マシンで実行することを計画しています。タスクは次のことを行います

  1. XMLドキュメントを受け入れます。
  2. それを変換します。
  3. Make multipleデータベースの読み取りと書き込み。

私はPostgreSQLを使用していますが、これは接続を使用する他の種類のストアにも同様に適用されます。以前は、データベース接続プールを使用して、リクエストごとに新しいデータベース接続を作成したり、接続を長時間開いたままにしたりすることを避けてきました。ただし、Celeryの各ワーカーは別々のプロセスで実行されるため、実際にプールを共有できる方法がわかりません。何か不足していますか?セロリではセロリワーカーから返された結果を保持できることを知っていますが、それは私がここでやろうとしていることではありません。各タスクは、処理されたデータに応じて、いくつかの異なる更新または挿入を実行できます。

Celeryワーカー内からデータベースにアクセスする正しい方法は何ですか?

複数のワーカー/タスク間でプールを共有することは可能ですか、またはこれを行う他の方法はありますか?

32
oneself

Tigeronk2のワーカーあたり1つの接続という考え方が好きです。彼が言うように、Celeryは独自のワーカーのプールを維持するため、個別のデータベース接続プールは実際に必要ありません。 Celery Signal docs は、ワーカーが作成されたときにカスタム初期化を行う方法を説明しているため、次のコードをtasks.pyに追加すると、期待どおりに機能するようです。ワーカーがシャットダウンしているときにも接続を閉じることができました。

db_conn = None

@worker_process_init.connect
def init_worker(**kwargs):
    global db_conn
    print('Initializing database connection for worker.')
    db_conn = db.connect(DB_CONNECT_STRING)


@worker_process_shutdown.connect
def shutdown_worker(**kwargs):
    global db_conn
    if db_conn:
        print('Closing database connectionn for worker.')
        db_conn.close()
24
ThatAintWorking

ワーカープロセスごとに1つのDB接続があります。セロリ自体がワーカープロセスのプールを維持するため、db接続は常にセロリワーカーの数と等しくなります。フリップサイド、つまり、db接続プールをセロリワーカープロセス管理に結び付けます。しかし、GILはプロセス内で一度に1つのスレッドしか許可しないので、それは問題ありません。

3
tigeronk2

デフォルトの動作を上書きして、セロリの設定でプロセスごとのワーカーではなく、スレッド化されたワーカーを持つことができます。

CELERYD_POOL = "celery.concurrency.threads.TaskPool"

次に、共有プールインスタンスをタスクインスタンスに保存し、スレッド化された各タスク呼び出しから参照できます。

2
Loren Abrams

おそらく pgbouncer を使用できます。セロリの場合、何も変更する必要はなく、接続プーリングはプロセスの外部で行われます。私は同じ issue を持っています。

(「副作用の可能性があるかどうかわからないため、おそらく」

1
kev

おそらく、 celery.concurrency.gevent はプール共有を提供し、GILを悪化させない可能性があります。ただし、サポートはまだ「実験的」です。

そして psycopg2.pool.SimpleConnectionPool は、すべてが単一のプロセス/スレッドで実行されるグリーンレット(コルーチン)間で共有します。

トピックに関する他の小さな stack ディスカッション。

0
p7k

実装および監視することにより、私の調査結果に貢献してください。

ようこそフィードバック。

参照:プールを使用 http://www.prschmid.com/2013/04/using-sqlalchemy-with-celery-tasks.html

各ワーカープロセス(-c kで指定されたpreforkモード)は、プールしたり再利用したりせずに、DBへの新しい接続を1つ確立します。したがって、プーリングを使用する場合、プールは各ワーカープロセスレベルでのみ表示されます。したがって、プールサイズ> 1は役に立ちませんが、接続を再利用しても、オープンおよびクローズからの接続を保存できます。

ワーカープロセスごとに1つの接続を使用する場合、初期化フェーズでワーカープロセスごとに1つのDB接続が確立されます(preforkモードcelery -A app worker -c k)。開閉からの接続を繰り返し保存します。

ワーカースレッド(イベントレット)の数に関係なく、各ワーカースレッド(セロリ-Aアプリワーカー-Pイベントレット)は、プールまたは再利用せずに、DBへの接続を1つだけ確立します。したがって、イベントレットの場合、1つのセロリプロセス(セロリ-Aアプリワーカー...)のすべてのワーカースレッド(イベントレット)には、各瞬間に1つのdb接続があります。

セロリのドキュメントによると

ただし、ブロッキング呼び出しが戻るまで、ワーカーで他のすべての操作が停止するため、タスクがブロッキング呼び出しを実行しないようにする必要があります。

これはおそらく、MYSQL DB接続が呼び出しをブロックしているためです。

0
Robin Loxley