Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Django Multiple Databases Fallback auf Master, wenn Slave ausgefallen ist

Mit der Verwendung eines Routers sind Sie auf dem richtigen Weg. Ich gehe davon aus, dass die Tatsache, dass Ihre beiden DB-Definitionen identisch sind, nur ein Tippfehler ist.

(FYI, ich werde auf die Datenbankhierarchie mit der sensiblere Master->Follower )

In Ihren db_for_read()-Funktionen können Sie die Konnektivität zu Ihrem Follower überprüfen. Dies kann etwas mehr Overhead verursachen, aber das sind die Kosten für ein automatisches Failover für eine Datenbank. Eine beispielhafte Datenbankdefinition wäre:

DATABASES = {
'follower': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'follower',
        'USER': 'root',
        'HOST': '54.34.65.24',
        'PORT': '3306',
    },
'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'application',
        'USER': 'root',
        'HOST': '54.34.65.23',
        'PORT': '3306',
    },
}  

Sie können die Verbindung mit einem schnellen Try/Außer wie dies testen Beispiel . Ein Router, der dies verwendet und das tut, was Sie brauchen, würde wie folgt aussehen:

from django.conf import settings
import socket


def test_connection_to_db(database_name):
    try:
        db_definition = getattr(settings, 'DATABASES')[database_name]
        s = socket.create_connection((db_definition['HOST'], db_definition['PORT']), 5)
        s.close()
        return True
    except (AttributeError, socket.timeout) as e:
        return False


class FailoverRouter(object):
    """A router that defaults reads to the follower but provides a failover back to the default"""

    def db_for_read(self, model, **hints):
        if test_connection_to_db('follower'):
            return 'follower'
        return 'default'

    def db_for_write(self, model, **hints):
        "Point all writes to the default db"
        return 'default'

    def allow_syncdb(self, db, model):
        "Make sure only the default db allows syncdb"
        return db == 'default'

Dies wird immer noch syncdb im Master wie gewünscht. Außerdem könnten Sie die Logik für beide db_for_read() erstellen und db_for_write() komplizierter (z. B. die Follower-Datenbank nur für bestimmte Modelle auswählen, die für Ihre Berichte abgefragt werden.

Ich weiß nicht, welchen Aufwand diese test_connection() hat wird für jeden Lesevorgang verursacht, da dies vom MySQL-Server und dem Timeout abhängt. Vielleicht ist es eine bessere Architektur, diese Berichte mit memcached zwischenzuspeichern oder einfach die Probleme mit dem Slave zu lösen, der jemals ausfällt, und zuerst Ihre Datenbankdefinitionen in den Einstellungen zu aktualisieren.