RDS에서 Django 앱 성능을 높이는 데이터베이스 설정 팁

RDS에서 Django 앱 성능을 높이는 데이터베이스 설정 팁

안녕하세요! 오늘은 AWS RDS를 사용하는 Django 애플리케이션의 성능을 최적화하는 방법에 대해 알아보겠습니다.

1. RDS 인스턴스 최적화

1.1 인스턴스 타입 선택

# RDS 인스턴스 크기 조정
import boto3

def resize_rds_instance():
    rds = boto3.client('rds')
    response = rds.modify_db_instance(
        DBInstanceIdentifier='your-db',
        DBInstanceClass='db.t3.large',  # 워크로드에 맞는 인스턴스 타입 선택
        ApplyImmediately=True
    )
    return response['DBInstance']

1.2 파라미터 그룹 설정

def create_parameter_group():
    rds = boto3.client('rds')

    # PostgreSQL 파라미터 그룹 생성
    response = rds.create_db_parameter_group(
        DBParameterGroupName='django-optimized',
        DBParameterGroupFamily='postgres13',
        Description='Optimized parameters for Django applications'
    )

    # 성능 관련 파라미터 설정
    parameters = [
        {
            'ParameterName': 'shared_buffers',
            'ParameterValue': '2GB',  # 시스템 메모리의 25%
            'ApplyMethod': 'pending-reboot'
        },
        {
            'ParameterName': 'effective_cache_size',
            'ParameterValue': '6GB',  # 시스템 메모리의 75%
            'ApplyMethod': 'pending-reboot'
        },
        {
            'ParameterName': 'work_mem',
            'ParameterValue': '16MB',  # 복잡한 쿼리에 대한 메모리 할당
            'ApplyMethod': 'pending-reboot'
        },
        {
            'ParameterName': 'maintenance_work_mem',
            'ParameterValue': '512MB',  # 유지보수 작업에 대한 메모리 할당
            'ApplyMethod': 'pending-reboot'
        },
        {
            'ParameterName': 'random_page_cost',
            'ParameterValue': '1.1',  # SSD 사용 시 설정
            'ApplyMethod': 'pending-reboot'
        },
        {
            'ParameterName': 'effective_io_concurrency',
            'ParameterValue': '200',  # SSD 사용 시 설정
            'ApplyMethod': 'pending-reboot'
        }
    ]

    for param in parameters:
        rds.modify_db_parameter_group(
            DBParameterGroupName='django-optimized',
            Parameters=[param]
        )

    return response['DBParameterGroup']['DBParameterGroupName']

2. 데이터베이스 연결 최적화

2.1 연결 풀 설정

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'your_db',
        'USER': 'your_user',
        'PASSWORD': 'your_password',
        'HOST': 'your-rds-endpoint',
        'PORT': '5432',
        'OPTIONS': {
            'connect_timeout': 10,
            'application_name': 'django_app',
        },
        'CONN_MAX_AGE': 60,  # 연결 유지 시간 (초)
        'CONN_HEALTH_CHECKS': True,
    }
}

2.2 연결 풀 모니터링

def monitor_connections():
    rds = boto3.client('rds')
    cloudwatch = boto3.client('cloudwatch')

    # 현재 연결 수 확인
    response = rds.describe_db_instances(
        DBInstanceIdentifier='your-db'
    )

    connections = response['DBInstances'][0]['DBConnections']

    # CloudWatch에 메트릭 발행
    cloudwatch.put_metric_data(
        Namespace='RDS',
        MetricData=[
            {
                'MetricName': 'DBConnections',
                'Value': connections,
                'Unit': 'Count',
                'Dimensions': [
                    {
                        'Name': 'DBInstanceIdentifier',
                        'Value': 'your-db'
                    }
                ]
            }
        ]
    )

3. 인덱스 최적화

3.1 인덱스 생성

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        indexes = [
            models.Index(fields=['name']),
            models.Index(fields=['category', 'price']),
            models.Index(fields=['created_at']),
        ]

3.2 인덱스 사용 분석

def analyze_index_usage():
    from django.db import connection

    with connection.cursor() as cursor:
        cursor.execute("""
            SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read, idx_tup_fetch
            FROM pg_stat_user_indexes
            ORDER BY idx_scan DESC;
        """)
        return cursor.fetchall()

4. 쿼리 최적화

4.1 쿼리 캐싱

from django.core.cache import cache
from django.db.models import Prefetch

def get_optimized_products():
    cache_key = 'products_list'
    products = cache.get(cache_key)

    if products is None:
        products = Product.objects.select_related(
            'category'
        ).prefetch_related(
            Prefetch('images', queryset=ProductImage.objects.filter(is_primary=True))
        ).filter(
            is_active=True
        )
        cache.set(cache_key, products, timeout=3600)

    return products

4.2 쿼리 실행 계획 분석

def analyze_query_plan():
    from django.db import connection

    with connection.cursor() as cursor:
        cursor.execute("""
            EXPLAIN ANALYZE
            SELECT * FROM products_product
            WHERE category_id = 1
            AND price > 1000;
        """)
        return cursor.fetchall()

5. 백업 및 복구 전략

5.1 자동 백업 설정

def configure_backups():
    rds = boto3.client('rds')

    response = rds.modify_db_instance(
        DBInstanceIdentifier='your-db',
        BackupRetentionPeriod=7,  # 7일간 백업 유지
        PreferredBackupWindow='03:00-04:00',  # 백업 시간대
        PreferredMaintenanceWindow='sun:04:00-sun:05:00',  # 유지보수 시간대
        ApplyImmediately=True
    )

    return response['DBInstance']

5.2 스냅샷 생성

def create_snapshot():
    rds = boto3.client('rds')

    response = rds.create_db_snapshot(
        DBSnapshotIdentifier=f'manual-snapshot-{datetime.now().strftime("%Y%m%d")}',
        DBInstanceIdentifier='your-db'
    )

    return response['DBSnapshot']['DBSnapshotIdentifier']

6. 모니터링 및 알림

6.1 성능 메트릭 모니터링

def monitor_performance():
    cloudwatch = boto3.client('cloudwatch')

    metrics = [
        'CPUUtilization',
        'FreeableMemory',
        'ReadIOPS',
        'WriteIOPS',
        'ReadLatency',
        'WriteLatency',
        'DatabaseConnections'
    ]

    for metric in metrics:
        cloudwatch.put_metric_alarm(
            AlarmName=f'RDS-{metric}-High',
            MetricName=metric,
            Namespace='AWS/RDS',
            Statistic='Average',
            Period=300,
            EvaluationPeriods=2,
            Threshold=80.0,
            ComparisonOperator='GreaterThanThreshold',
            AlarmActions=['arn:aws:sns:region:account-id:your-topic']
        )

6.2 슬로우 쿼리 로깅

def enable_slow_query_log():
    rds = boto3.client('rds')

    response = rds.modify_db_parameter_group(
        DBParameterGroupName='django-optimized',
        Parameters=[
            {
                'ParameterName': 'log_min_duration_statement',
                'ParameterValue': '1000',  # 1초 이상 걸리는 쿼리 로깅
                'ApplyMethod': 'pending-reboot'
            }
        ]
    )

    return response

7. 읽기 전용 복제본 설정

7.1 복제본 생성

def create_read_replica():
    rds = boto3.client('rds')

    response = rds.create_db_instance_read_replica(
        DBInstanceIdentifier='your-db-replica',
        SourceDBInstanceIdentifier='your-db',
        DBInstanceClass='db.t3.medium',
        AvailabilityZone='ap-northeast-2a'
    )

    return response['DBInstance']

7.2 Django에서 복제본 사용

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'your_db',
        'USER': 'your_user',
        'PASSWORD': 'your_password',
        'HOST': 'your-rds-endpoint',
        'PORT': '5432',
    },
    'replica': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'your_db',
        'USER': 'your_user',
        'PASSWORD': 'your_password',
        'HOST': 'your-replica-endpoint',
        'PORT': '5432',
    }
}

DATABASE_ROUTERS = ['path.to.router.ReadReplicaRouter']

결론

RDS에서 Django 애플리케이션의 성능을 최적화하는 다양한 방법을 알아보았습니다. 이러한 설정을 통해 데이터베이스 성능을 크게 향상시킬 수 있습니다. 추가적인 질문이나 궁금한 점이 있으시면 댓글로 남겨주세요!

댓글