(Django内ではなく)Celeryスタンドアロンを使用しています。 1つのワーカータスクタイプを複数の物理マシンで実行することを計画しています。タスクは次のことを行います
私はPostgreSQLを使用していますが、これは接続を使用する他の種類のストアにも同様に適用されます。以前は、データベース接続プールを使用して、リクエストごとに新しいデータベース接続を作成したり、接続を長時間開いたままにしたりすることを避けてきました。ただし、Celeryの各ワーカーは別々のプロセスで実行されるため、実際にプールを共有できる方法がわかりません。何か不足していますか?セロリではセロリワーカーから返された結果を保持できることを知っていますが、それは私がここでやろうとしていることではありません。各タスクは、処理されたデータに応じて、いくつかの異なる更新または挿入を実行できます。
Celeryワーカー内からデータベースにアクセスする正しい方法は何ですか?
複数のワーカー/タスク間でプールを共有することは可能ですか、またはこれを行う他の方法はありますか?
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()
ワーカープロセスごとに1つのDB接続があります。セロリ自体がワーカープロセスのプールを維持するため、db接続は常にセロリワーカーの数と等しくなります。フリップサイド、つまり、db接続プールをセロリワーカープロセス管理に結び付けます。しかし、GILはプロセス内で一度に1つのスレッドしか許可しないので、それは問題ありません。
デフォルトの動作を上書きして、セロリの設定でプロセスごとのワーカーではなく、スレッド化されたワーカーを持つことができます。
CELERYD_POOL = "celery.concurrency.threads.TaskPool"
次に、共有プールインスタンスをタスクインスタンスに保存し、スレッド化された各タスク呼び出しから参照できます。
おそらく、 celery.concurrency.gevent はプール共有を提供し、GILを悪化させない可能性があります。ただし、サポートはまだ「実験的」です。
そして psycopg2.pool.SimpleConnectionPool は、すべてが単一のプロセス/スレッドで実行されるグリーンレット(コルーチン)間で共有します。
トピックに関する他の小さな stack ディスカッション。
実装および監視することにより、私の調査結果に貢献してください。
ようこそフィードバック。
参照:プールを使用 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接続が呼び出しをブロックしているためです。