Django 로 하여 금 데이터베이스 장 연결 을 지원 하 게 합 니 다. (많은 성능 을 향상 시 킬 수 있 습 니 다.)

현재 고성능 nonblock 의 app server 로 host Django 를 사용 하 는 것 이 유행 합 니 다. 이 Server 들 은 하나의 프로 세 스 단일 스 레 드 프로그램 이 라 고 볼 수 있 습 니 다. 그리고 nginx 로 전단 에서 프 록 시 를 반대 하고 N 여러 백 엔 드 로 부하 균형 을 잡 아 다 중 CPU 의 성능 을 충분히 이용 할 수 있 습 니 다. 물론 이 부분의 설정 작업 은 지난번 에 분명히 말 했 습 니 다.하지만 Django 에 게 문제 가 있 습 니 다.Django 의 데이터베이스 연결 은 검색 할 때 실시 간 으로 만 들 어 졌 기 때문에 사용 이 끝나 면 꺼 지고 연결 이 자주 열 리 기 때 문 입 니 다.하지만 토 네 이도 같은 서버 에 서 는 이런 방식 이 비효 율 적 이다.이 서버 의 가장 효율 적 인 작업 모드 는 모든 프로 세 스 가 연결 을 열 고 장기 적 으로 닫 지 않 는 것 입 니 다.본 논문 의 목적 은 Django 로 하여 금 일 관 된 태 도 를 바 꾸 고 이런 효율 적 인 작업 모델 을 사용 하 게 하 는 것 이다.본 고 는 Django 1.3 버 전 을 바탕 으로 낮은 버 전이 라면 조금 만 변경 할 수 있 듯 이 사용 할 수 있 습 니 다.
Django 의 데이터 베 이 스 는 설정 을 통 해 맞 춤 형 Backend 를 사용 할 수 있 습 니 다. 여기 서부 터 시작 하 겠 습 니 다.
우선 Django 가 가지 고 있 는 백 엔 드 가 어떻게 이 루어 졌 는 지 살 펴 보 자.Django 홈 페이지 에서 MySql 을 가 진 Package 구 조 를 볼 수 있 습 니 다. 여 기 를 클릭 하 십시오. 가서 참배 하 다.
소스 코드 를 보면 Django 는 기본적으로 MySQLdb 의 Connection 과 Cursor 라 는 두 대상 을 봉 인 했 음 을 알 수 있 습 니 다.그리고 백 엔 드 전 체 를 실현 하 는 것 은 현실 적 이지 도 않 고 근본적으로 문 제 를 해결 할 수도 없다.그래서 우 리 는 생각 을 바 꿀 수 있다.모든 데이터베이스 작업 은 Connection 대상 을 가 져 오 는 것 에서 시작 되 며, Connection 대상 을 가 져 오 는 데 는 하나의 입구 만 있 습 니 다. 바로 MySQLdb. connect 라 는 함수 입 니 다.그래서 우 리 는 MySQLdb 라 는 모듈 을 포장 하고 우리 자신의 connect 방법 으로 원래 의 것 을 대체 하면 근원 적 으로 문 제 를 해결 할 수 있 습 니 다.저 희 는 포장 기 내부 에서 MySQLdb 의 Connection 대상 을 유지 하고 긴 연결 을 유지 합 니 다. connect 가 호출 될 때마다 연결 이 존재 하면 기 존 연결 로 돌아 가 는 것 이 완벽 하지 않 습 니까?그래서 우 리 는 분 별로 첫 번 째 해결 방안 을 쓸 수 있다.
proxies = {}
 	  
class _DbWrapper():
    def __init__(self,module):
        self.connection=None #            
        self.db=module           #         MySQLdb module
  
    def __getattr__(self, key):
        return getattr(self.db, key)   #          
 	  
    def connect(self,*argv,**kwargv):
        if not self.connection:
           self.connection=self.db.connect(*argv,**kwargv)
           return _ConnectionWrapper(self.connection)
 
    def manage(module,keepalive=7*3600):
        try:
	        return proxies[module]
        except KeyError:
            return proxies.setdefault(module,_DbWrapper(module))

위의 코드 를 pool. py 라 는 파일 에 저장 하 세 요.그리고 Django 소스 코드 에 있 는 db / backend / mysql 패 키 지 를 복사 해서 우리 procject 디 렉 터 리 에 mysql 하나만 저장 합 니 다.pool 디 렉 터 리 에그리고 그 중의 base. py 를 수정 하여 맨 위 에 import 부분 을 찾 습 니 다. import MySQLdb as Database 라 는 문장 은 아래 코드 로 바 꿉 니 다.
try:
    import MySQLdb as Database
    Database = pool.manage(Database)
except ImportError, e:
    from django.core.exceptions import ImproperlyConfigured
    raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)

이렇게 해서 우 리 는 자신의 모듈 로 MySQLdb 를 교 체 했 습 니 다. connect 를 하려 고 할 때 연결 이 있다 고 판단 할 때 다시 연결 을 만 들 지 않 습 니 다.
역 을 뛰 어 올 라 보 니 결 과 는 어 떻 습 니까?몇 번 갱신 한 후에 잘못 보고 했다.Why?로 그 를 보면 다음 과 같은 오 류 를 볼 수 있 습 니 다.
Traceback (most recent call last): File “/home/www/.virtualenvs/django13/lib/python2.7/site-packages/gevent/wsgi.py”, line 114, in handle result = self.server.application(env, self.start_response) File “/home/www/.virtualenvs/django13/lib/python2.7/site-packages/django/core/handlers/wsgi.py”, line 275, in __call__ signals.request_finished.send(sender=self.__class__) File “/home/www/.virtualenvs/django13/lib/python2.7/site-packages/django/dispatch/dispatcher.py”, line 172, in send response = receiver(signal=self, sender=sender, **named) File “/home/www/.virtualenvs/django13/lib/python2.7/site-packages/django/db/__init__.py”, line 85, in close_connection conn.close() File “/home/www/.virtualenvs/django13/lib/python2.7/site-packages/django/db/backends/__init__.py”, line 244, in close self.connection.close()
보아하니 우 리 는 MySQLdb 자 체 를 포장 하 는 것 만 으로 는 안 되 는 것 같다. connect 후 Django 는 connection 의 대상 을 얻 은 후에 하고 싶 은 대로 할 수 있다. 그 는 다 쓴 후에 자각 적 으로 껐 다. 왜냐하면 그 는 connect 할 때마다 새로운 connection 대상 을 얻 었 다 고 직감 했 기 때문이다.그래서 우 리 는 반드시 Connection 대상 도 포장 해 야 한다.그래서 업그레이드 후의 해결 방안 코드 는 다음 과 같다.
proxies = {}
  
class _ConnectionWrapper(object):
    """
        Connection  
    """
    def __init__(self,conn):
        self.conn=conn
  
    def close(self):
        """
                  
        """
        pass
  
    def __getattr__(self,key):
        """
                       
        """
        return getattr(self.conn, key)
  
class _DbWrapper():
    """
      MySQLdb     
    """
    def __init__(self,module):
        self.connection=None  #HOLD     
        self.db=module            #   MySQLdb  
  
    def __getattr__(self, key):
        """
           connect      
        """
        return getattr(self.db, key)
  
    def connect(self,*argv,**kwargv):
        if not self.connection:
            self.connection=self.db.connect(*argv,**kwargv)
        return _ConnectionWrapper(self.connection)
  
def manage(module):
    try:
        return proxies[module]
    except KeyError:
        return proxies.setdefault(module,_DbWrapper(module))

우 리 는 하 나 를 증가 시 켰 다Connection Wrapper 클래스 는 Connection 대상 을 대리 하고 close 함 수 를 차단 합 니 다.역 을 달 려 보 니 이전의 문제 가 발생 하지 않 고 달 리 는 것 도 원활 하 다.하지만 몇 시간 이 지나 자 문제 가 또 생 겼 다.MySQLdb 의 Connection 은 연결 이 8 시간 동안 방치 되면 스스로 끊 어 지 는 문제 가 있 기 때문이다.그러나 이 문 제 를 해결 하 는 것 은 매우 간단 하 다. 우 리 는 연결 이 거의 8 시간 동안 방치 되 어 있 으 면 close 하고 다시 연결 을 만 들 면 되 지 않 겠 는가?그래서 마지막 해결 방안 의 코드 는 다음 과 같다.
import time
  
proxies = {}
  
class _ConnectionWrapper(object):
    def __init__(self,conn):
        self.conn=conn
  
    def close(self):
        pass
  
    def __getattr__(self,key):
        return getattr(self.conn, key)
  
class _DbWrapper():
    def __init__(self,module,max_idle):
        self.connection=None
        self.db=module
        self.max_idle=max_idle
        self.connected=0
  
    def __getattr__(self, key):
        return getattr(self.db, key)
  
    def connect(self,*argv,**kwargv):
        if not self.connection or time.time()-self.connected>=self.max_idle:
            try:
                if self.connection:
                    self.connection.close()
            except:
                pass
            self.connection=self.db.connect(*argv,**kwargv)
        self.connected=time.time()
        return _ConnectionWrapper(self.connection)
  
def manage(module,keepalive=7*3600):
    try:
        return proxies[module]
    except KeyError:
        return proxies.setdefault(module,_DbWrapper(module,keepalive))

이 문제 가 해결 되자, 세 계 는 마침내 깨끗 해 졌 다.

좋은 웹페이지 즐겨찾기