Django 영구 데이터베이스 연결
apache 및 mod_wsgi 및 PostgreSQL (모두 동일한 호스트에 있음)과 함께 django를 사용하고 있으며 많은 간단한 동적 페이지 요청 (초당 수백 번)을 처리해야합니다. 병목 현상은 django가 영구적 인 데이터베이스 연결이없고 각 요청에서 다시 연결된다는 문제에 직면했습니다 (거의 5ms 소요). 벤치 마크를 수행하는 동안 지속적인 연결로 거의 500 r / s를 처리 할 수 있지만 50 r / s 만 얻습니다.
누구에게 조언이 있습니까? 영구 연결을 사용하도록 django를 수정하는 방법은 무엇입니까? 또는 Python에서 DB 로의 연결 속도 향상
미리 감사드립니다.
Django 1.6 에는 영구 연결 지원 이 추가되었습니다 (django 1.9 용 문서 링크) :
영구 연결은 각 요청에서 데이터베이스에 대한 연결을 다시 설정하는 오버 헤드를 방지합니다. 연결의 최대 수명을 정의하는 CONN_MAX_AGE 매개 변수에 의해 제어됩니다. 각 데이터베이스에 대해 독립적으로 설정할 수 있습니다.
PostgreSQL 용 경량 연결 풀러 인 PgBouncer를 사용해보십시오 . 풍모:
- 연결 회전시 여러 수준의 잔인 함 :
- 세션 풀링
- 트랜잭션 풀링
- 문 풀링
- 낮은 메모리 요구 사항 (기본적으로 연결 당 2k).
Django 트렁크에서 다음 django/db/__init__.py
줄을 편집 하고 주석 처리합니다.
signals.request_finished.connect(close_connection)
이 신호 핸들러는 모든 요청 후 데이터베이스에서 연결을 끊습니다. 이 작업의 모든 부작용이 무엇인지는 모르겠지만 모든 요청 후에 새 연결을 시작하는 것은 이치에 맞지 않습니다. 아시다시피 성능이 저하됩니다.
나는 이것을 지금 사용하고 있지만 어떤 것이 깨지는 지 확인하기 위해 전체 테스트 세트를 수행하지 않았습니다.
왜 모든 사람들이 이것이 새로운 백엔드 나 특수 연결 풀러 또는 기타 복잡한 솔루션이 필요하다고 생각하는지 모르겠습니다. 이것은 매우 간단 해 보이지만, 애초에이 작업을 수행하게 만든 모호한 문제가 있다는 것은 의심 할 여지가 없습니다. 더 현명하게 다루어야합니다. 아시다시피 모든 요청에 대한 5ms 오버 헤드는 고성능 서비스의 경우 상당히 많습니다. ( 150ms 가 걸립니다 . 아직 이유를 알지 못했습니다.)
편집 : 또 다른 필요한 변경 사항은 django / middleware / transaction.py에 있습니다. 두 transaction.is_dirty () 테스트를 제거하고 항상 commit () 또는 rollback ()을 호출하십시오. 그렇지 않으면 데이터베이스에서 읽기만하면 트랜잭션을 커밋하지 않으므로 닫아야하는 잠금이 열린 상태로 유지됩니다.
sqlalchemy 풀링을 통해 MySQL과 PostgreSQL의 연결 풀링을 구현 하는 작은 Django 패치 를 만들었습니다 .
이것은 오랜 기간 동안 http://grandcapital.net/의 제작에서 완벽하게 작동합니다 .
패치는 주제를 약간 검색 한 후에 작성되었습니다.
면책 조항 : 나는 이것을 시도하지 않았습니다.
사용자 지정 데이터베이스 백엔드를 구현해야한다고 생각합니다. 연결 풀링을 사용하여 데이터베이스 백엔드를 구현하는 방법을 보여주는 몇 가지 예가 웹에 있습니다.
연결이 풀로 반환 될 때 네트워크 연결이 열린 상태로 유지되므로 연결 풀을 사용하는 것이 좋은 솔루션 일 것입니다.
두 게시물 모두 MySQL을 사용합니다. 아마도 Postgresql에서 유사한 기술을 사용할 수 있습니다.
편집하다:
- Django Book은 pgpool ( tutorial )을 사용하여 Postgresql 연결 풀링을 언급합니다 .
- 누군가 연결 풀링을 구현하는 psycopg2 백엔드 에 대한 패치 를 게시 했습니다 . 자신의 프로젝트에서 기존 백엔드의 복사본을 만들고 패치하는 것이 좋습니다.
전역 변수를 사용하여 영구 연결을 구현하는 작은 사용자 지정 psycopg2 백엔드를 만들었습니다. 이것으로 초당 요청 수를 350에서 1600으로 향상시킬 수있었습니다 (선택 사항이 거의없는 매우 간단한 페이지) base.py
. 아무 디렉토리 (예 : postgresql_psycopg2_persistent)에서 호출 된 파일에 저장 하고 설정에서 설정하기 만하면됩니다.
DATABASE_ENGINE-projectname.postgresql_psycopg2_persistent
노트!!! 코드가 스레드로부터 안전하지 않습니다-예상치 못한 결과로 인해 파이썬 스레드와 함께 사용할 수 없습니다. mod_wsgi의 경우 threads = 1로 prefork 데몬 모드를 사용하십시오.
# 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
또는 여기에 스레드로부터 안전한 것이 있지만 파이썬 스레드는 다중 코어를 사용하지 않으므로 이전 코어와 같은 성능 향상을 얻지 못할 것입니다. 다중 프로세스 하나와 함께 사용할 수도 있습니다.
# 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
ReferenceURL : https://stackoverflow.com/questions/1125504/django-persistent-database-connection
'programing' 카테고리의 다른 글
JavaScript로 파일 다운로드 시작 (0) | 2021.01.14 |
---|---|
LINQ는 내부적으로 어떻게 작동합니까? (0) | 2021.01.14 |
HTML에서 사진 비율을 왜곡하지 않고 너비와 높이를 백분율로 지정 (0) | 2021.01.14 |
2 개의 Android 앱간에 SQLite 데이터베이스를 공유 하시겠습니까? (0) | 2021.01.14 |
불필요한 @SuppressWarnings ( "unused") (0) | 2021.01.14 |