본문 바로가기

python & django & scipy

[django] DB replica

 

트래픽량이 많아지면 DB에 접근하는 I/O 작업 시간이 길어지기 때문에 Application의 CPU 연산보다 더 큰 bottleneck이 된다. 

DB 작업은 read, 즉 select가 대부분이기 때문에 read replica를 두어 read는 replica가, write는 master(default)가 하게하면 read 작업을 분산시킬 수 있다.

 

django에서는 multidatabase를 쓸 수 있도록 되어있다. 

  1. Model.objects.using('{dbname}')
  2. Model Manager에서 .using('{dbname}')
  3. django.db.router로 DB Router 설정

 

모든 read 작업이 replica로 가는 것을 처리하기 위해서는

Router에서 db_for_read는 replica를 db_for_write는 default를 return하도록 하면 된다

 

이 때, write database로 설정한 default는 서드파티 라이브러리에서 db 이름을 default로 하드코딩 해놓은 사례가 있어 default에서 이름을 변경하지 않는 것이 좋다.

read replica의 이름은 변경해도 상관없다

DATABASES = {
    'default': {
        'NAME': 'default',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'swordfish',
    },
    'replica1': {
        'NAME': 'replica1_name',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'eggs',
    },
    'replica2': {
        'NAME': 'replica2_name',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'bacon',
    },
}
DATABASE_ROUTERS = ['path.to.DbRouter']
import random

class DbRouter:
    def db_for_read(self, model, **hints):
        """
        Reads go to a randomly-chosen replica.
        """
        return random.choice(['replica1', 'replica2'])

    def db_for_write(self, model, **hints):
        """
        Writes always go to default.
        """
        return 'default'

	...

 

 

결제 등의 transaction을 관리할 때, 아직 write가 끝나지 않은 데이터에 대해 read가 이루어져 데이터의 안정성을 해치는 것을 막으려면 아래와 같이 관리하면 된다. 

import random
from django.db import transaction

class DbRouter:
    def db_for_read(self, model, **hints):
       conn = transaction.get_connection('default')
       if conn.is_atomic_block:
           return 'default'
       return random.choice(['replica1', 'replica2'])

    def db_for_write(self, model, **hints):
        """
        Writes always go to default.
        """
        return 'default'

	...

 

 

그리고 Aurora는 custom endpoint를 사용해서 random choice하는 database name들을 굳이 저렇게 안 늘여놓아도 된다고 한다. 

 

 

참고 영상: https://www.youtube.com/watch?v=eAP8zimx05M&t=542s