TransWikia.com

Масштабирование БД PostgreSQL при разработке Django проекта

Stack Overflow на русском Asked by svmitin on August 30, 2021

Стандартное масштабирование веб-приложения:

  • Деплоим приложение на n серверов. Перед серверами ставим балансировщик нагрузки
  • У БД настраиваем репликацию. Теперь в master будет идти только запись, все выборки идут с реплик. Для тяжелых аналитических запросов поднимаем отдельную реплику

Мой вопрос касается второго пункта при масштабировании Django-приложения. В Django мы не пишем sql-запросы, мы описываем модели данных используя ORM.

Можно ли настроить Django так, чтобы запись велась на один конкретный сервер, а все выборки из каких-то других серверов с репликами?

One Answer

Это можно сделать с помощью маршрутизаторов. Пример из документации:

settings.py

DATABASES = {
    'default': {},
    'primary': {
        'NAME': 'primary',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'spam',
    },
    'replica1': {
        'NAME': 'replica1',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'eggs',
    },
    'replica2': {
        'NAME': 'replica2',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'bacon',
    },
}

DATABASE_ROUTERS = ['path.to.PrimaryReplicaRouter']

router.py

import random

class PrimaryReplicaRouter:
    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 primary.
        """
        return 'primary'

    def allow_relation(self, obj1, obj2, **hints):
        """
        Relations between objects are allowed if both objects are
        in the primary/replica pool.
        """
        db_list = ('primary', 'replica1', 'replica2')
        if obj1._state.db in db_list and obj2._state.db in db_list:
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        All non-auth models end up in this pool.
        """
        return True

Correct answer by Sergey Gornostaev on August 30, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP