Является ли принудительное выполнение операций чтения из реплики чтения задачей прикладного уровня?

Т.е. у меня есть база данных Postgres, и я настроил реплику для чтения.

На стороне приложения у меня есть два соединения: одно для базы данных «запись», а другое - для базы данных «реплика чтения».

В моем коде, если я выполняю действие «чтения», я использую соединение с репликой чтения. Но когда я перехожу к вставке или обновлению, я использую соединение с базой данных «записи», также известной как master.

Что лучше с django или flask, чтобы это управлялось автоматически. т.е.

Я бы предпочел не указывать непосредственно в коде используемое соединение, а просто попросить django или flask разобраться в этом самостоятельно.

1
Edgar Martinez 1 Янв 2018 в 02:39

2 ответа

Лучший ответ

Джанго

Для этого django поддерживает так называемые маршрутизаторы баз данных.

Сначала создайте собственный роутер:

class CustomRouter:
    def db_for_read(self, model, **hints):
        return 'replica'

    def db_for_write(self, model, **hints):
        return 'master'

И настройте django orm для его использования.

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

}

DATABASE_ROUTERS = ['path.to.CustomRouter']

Пример кода был взят из документации (стоит прочитать!) и немного поправил.

SQLAlchemy (флакон)

Я просмотрел документы SQLAlchemy и нашел ссылку на эта статья, в которой описывается, как реализовать подход маршрутизатора базы данных djangos с помощью SQLAlchemy.

Здесь вы можете использовать настраиваемый сеанс, чтобы реализовать это правильно.

Следующие фрагменты взяты из связанной статьи и немного изменены.

Создайте свои двигатели:

engines = {
    'master': create_engine('postgresql://user:***@localhost:5432/master',
                            logging_name='master'),
    'replica': create_engine('postgresql://user:***@localhost:5432/replica',
                             logging_name='replica'),
}

Создайте собственный класс сеанса:

class RoutingSession(Session):

    def get_bind(self, mapper=None, clause=None):
        if self._flushing:
            return engines['master']
        else:
            return engines['replica']

И создайте свою сессию следующим образом:

Session = scoped_session(sessionmaker(class_=RoutingSession, autocommit=True))

Прочтите статью, чтобы узнать подробности и ограничения.

8
dahrens 1 Янв 2018 в 14:13

Вот концептуальное решение для смены фляжки

https://gist.github.com/jasonwalkeryung/5133383d66782461cdc3b4607ae35d98

0
Ryabchenko Alexander 15 Ноя 2019 в 08:03