Django永続的なデータベース接続
-
13-09-2019 - |
質問
を使用していdjango apacheとmod_wsgi ール(すべて同じホスト)を取り扱う必要があり多くのダイナミックページをご希望の方は、数百円して変更することができます。私がこのボトルネックはdjangoない永続的なデータベース接続と再接続毎に要求する近5ms).なベンチマークっと接続を切り取りをすることはでき近くの500r/sがない50のr/sとなります。
誰にでもして相談すればいいのだろうか。変更する方法django使持続しています。または速度ップ接続からpythonへのDB
よろしくお願いします。
解決
Django 1.6 を追加 永続的な接続をサポート(リンクdocのためのdjango1.9):
持続的な接続を避けるオーバーヘッドの再構築 接続は、データベースできます。うに制御され CONN_MAX_AGEパラメータを定義する最大の寿命まで 接続します。設定することが可能で独立して各データベースです。
他のヒント
試 PgBouncer -軽量接続poolerのためのPostgreSQL.特徴:
- 複数のレベルでの残虐行為が回転接続:
- セッションプーリング
- 取引プーリング
- 決算リング
- 低メモリ要件(2k接続によるデフォルト)。
Djangoのトランク、編集django/db/__init__.py
でと行をコメントアウトします:
signals.request_finished.connect(close_connection)
このシグナルハンドラは、それがすべての要求の後に、データベースから切断する原因となります。私はこれを行うの副作用の全てがどうなるかわかりませんが、それはすべての要求の後に新しい接続を開始するために、任意の意味がありません。あなたが気づいたとして、それは、パフォーマンスを破壊します。
私は今、これを使用していますが、私は何もブレークかどうかを確認するためにテストの完全なセットを行ってやりなさいます。
誰もが、これは新しいバックエンドまたは特別な接続プーラーまたは他の複雑なソリューションを必要と考えて、なぜ私にはわかりません。私は彼らが最初の場所でこれを行う作らいくつかのあいまいな落とし穴がある疑いはありませんが、これは、非常に単純なようだ - もっと賢明に対処する必要があります。あなたが気づいたとして、すべての要求のための5msのオーバーヘッドは、高性能なサービスのために非常に多くあります。 (それは私を取るの150msのの - 。私がやりなさい、なぜまだ考え出し)
編集:別の必要な変更はジャンゴ/ミドルウェア/ transaction.pyです。コミット呼び出し常に2 transaction.is_dirty()テストを削除し、()またはrollback()。それだけでロックが閉じられなければならないことを開いたままになるデータベースから読めばそうでなければ、それはトランザクションをコミットしません。
私はSQLAlchemyのプーリングを経由してのMySQLとPostgreSQLの接続プーリングを実装して、小さな Djangoのパッチを作成します。
これは、長時間の http://grandcapital.net/するの生産に完璧に動作します。
パッチは少し話題をグーグル後に書かれた。
免責事項:っていないのにします。
と思いを実装するために必要なカスタムデータベースに戻る。あの例のウェブがどのように実施するデータベースのバックエンとの接続をプールした.
を接続プールろうが良いソリューションの場合、ネットワーク接続を開放状態に保ったままでの時接続のプールがあります。
両方のポMySQL-うまく利用できる類似の技術Postgresql.
編集:
私はグローバル変数を使用して、永続的な接続を実現し、いくつかの小さなカスタムpsycopg2のバックエンドを作りました。
これで、私は(いくつかの選択と非常にシンプルなページ)350から1600秒あたりの要求のamoutをを改善することができました
ただ、任意のディレクトリにbase.py
(例えばpostgresql_psycopg2_persistent)と呼ばれ、
projectname.postgresql_psycopg2_persistentするDATABASE_ENGINE
注!!!コードはスレッドセーフではありません - あなたがスレッドとpreforkのデーモンモードを使用してくださいのmod_wsgiの場合には、理由unexpectable結果のpythonのスレッドでそれを使用することはできません= 1 の
<時間># Custom DB backend postgresql_psycopg2 based
# implements persistent database connection using global variable
from django.db.backends.postgresql_psycopg2.base import DatabaseError, DatabaseWrapper as BaseDatabaseWrapper, \
IntegrityError
from psycopg2 import OperationalError
connection = None
class DatabaseWrapper(BaseDatabaseWrapper):
def _cursor(self, *args, **kwargs):
global connection
if connection is not None and self.connection is None:
try: # Check if connection is alive
connection.cursor().execute('SELECT 1')
except OperationalError: # The connection is not working, need reconnect
connection = None
else:
self.connection = connection
cursor = super(DatabaseWrapper, self)._cursor(*args, **kwargs)
if connection is None and self.connection is not None:
connection = self.connection
return cursor
def close(self):
if self.connection is not None:
self.connection.commit()
self.connection = None
<時間>
それともここでは、スレッドセーフですが、Pythonのスレッドが複数のコアを使用していないので、あなたが以前のものと同じようなパフォーマンスの向上を得ることはありません。あなたも、マルチプロセスのいずれかで、このいずれかを使用することができます。
# Custom DB backend postgresql_psycopg2 based
# implements persistent database connection using thread local storage
from threading import local
from django.db.backends.postgresql_psycopg2.base import DatabaseError, \
DatabaseWrapper as BaseDatabaseWrapper, IntegrityError
from psycopg2 import OperationalError
threadlocal = local()
class DatabaseWrapper(BaseDatabaseWrapper):
def _cursor(self, *args, **kwargs):
if hasattr(threadlocal, 'connection') and threadlocal.connection is \
not None and self.connection is None:
try: # Check if connection is alive
threadlocal.connection.cursor().execute('SELECT 1')
except OperationalError: # The connection is not working, need reconnect
threadlocal.connection = None
else:
self.connection = threadlocal.connection
cursor = super(DatabaseWrapper, self)._cursor(*args, **kwargs)
if (not hasattr(threadlocal, 'connection') or threadlocal.connection \
is None) and self.connection is not None:
threadlocal.connection = self.connection
return cursor
def close(self):
if self.connection is not None:
self.connection.commit()
self.connection = None