2014-10-28 5 views
14

Mam replikację master - slave dla zaplecza MySQL db dla Django. Obecnie czytam i piszę tylko dla Master DB, ale moje kokpity są dość intensywne. szukałem opcji, gdzie można zdefiniować jak po bazachDjango Wielokrotne bazy danych Obniżenie do stanu nadrzędnego, jeśli Slave jest wyłączone

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

do kokpitów, raportów i różnych innych aplikacji, co chcę zrobić, to:

Spróbuj gra: default_slave: using default_slave, jeśli można to osiągnąć, używając default

Oznacza to, że jeśli urządzenie podrzędne jest w górze, pobierz raporty z samej bazy danych podrzędnych, jeśli nie pobieraj raportów z głównej bazy danych.

Połów jest, podrzędny może być w górę lub w dół, i chcę, aby to było dynamicznie wybierane w odniesieniu do bazy danych, która ma być używana do pobierania raportów, w oparciu o rechability.

Czy to możliwe? Czy mogę przetestować połączenie przed ręką i iść do przodu?

Z tym będę pisać i sync_db w Master, i zawsze czytać z Slave, jeśli niewolnik jest w górze.

Potrzebujesz roztwór/podpowiedź dla raw queries jak orm queries

Koncepcja Router wydaje się dobre, ale awaryjne na niewolnik nie osiągalny, nie wiem możliwość.

UPDATE

Jak przejść o wielu baz danych

DATABASES

DATABASES = { 
'default_slave': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'application', 
     'USER': 'root', 
     'PASSWORD': '', 
     'HOST': '', 
     'PORT': '3306', 
    }, 
'default': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'application', 
     'USER': 'root', 
     'PASSWORD': '', 
     'HOST': '', 
     'PORT': '3306', 
    }, 
} 
'linux': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'application', 
     'USER': 'root', 
     'PASSWORD': '', 
     'HOST': '', 
     'PORT': '3306', 
    }, 
} 
'linux_slave': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'application', 
     'USER': 'root', 
     'PASSWORD': '', 
     'HOST': '', 
     'PORT': '3306', 
    }, 
} 
'mac': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'application', 
     'USER': 'root', 
     'PASSWORD': '', 
     'HOST': '', 
     'PORT': '3306', 
    }, 
} 
'mac_slave': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'application', 
     'USER': 'root', 
     'PASSWORD': '', 
     'HOST': '', 
     'PORT': '3306', 
    }, 
} 
'pc': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'application', 
     'USER': 'root', 
     'PASSWORD': '', 
     'HOST': '', 
     'PORT': '3306', 
    }, 
} 
'pc_slave': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'application', 
     'USER': 'root', 
     'PASSWORD': '', 
     'HOST': '', 
     'PORT': '3306', 
    }, 
} 

Teraz mam 1. Static Data 2.Dynamic Data

statyczne dane muszą być przechowywane w „default”, które będą replikowane do „default_slave”

dla danych dynamicznych, zapytanie musi najpierw ocenić, gdzie może Danych dynamiczny leżeć: w „Mac” lub „pC” lub „Linux”

celu osiągnięcia tego, że dodaje się jedno pole w „statycznie”: „query_on”, który zawiera wiązania [Mac "lub„Linux”lub„pc”]

Teraz, używając zestawu zapytań, po prostu piszę static = Static.objects.get(pk = 1)
query_on = static.query_on dynamic = Dynamic.objects.get(static = static).using(alias=query_on)

Działa to dobrze, trasy zapytanie do bazy danych, to musi dostać wykonany, tutaj muszę ocenić:

  1. Jeśli <'query_on'>_slave: Połączenie wynosi: zastosowania: <'query_on'>_slave LUB
  2. Jeśli <'query_on'>_slave: połączenie nie działa: użyj: <'query_on'>

Jak do tego zabrać ?

Dalsze szczegóły dotyczące stosowania:

  1. Jest jedna baza danych: default (baza danych konfiguracyjnych & Analytics): za utrzymanie danych konfiguracyjnych i raportowania danych analitycznych
  2. Istnieje 20 baz danych (raw baz): na przykład: mac, linux, rhel, windows, pc .... (przykładowa nazwa): do zbierania surowych danych, które nie są procesami analitycznymi
  3. każda baza danych ma jednego lub wiele niewolników, konwencja nazewnictwa be: default_slave _0, default_slave_1, default_slave_2 a więc dla innych baz danych, jak również

Teraz dane analityczne musi być najpierw zapytał za 5 minut, 30 minut, 1 godzinę .... i że kwerenda musi zostać wysłany do specyficznych bazy danych, ponieważ nie każda baza danych będzie zawierała specjalny zestaw danych wymagany do analizy.

Aby to zrobić, musimy

  1. uzyskać dane konfiguracyjne (domyślny lub jeden z jego niewolnika (część niewolnik jest pytanie))
  2. raz mamy konfigurację, możemy łatwo sprawdź, gdzie "surowe" dane mogą być: zapytanie o nieprzetworzone dane, zbieraj wyniki i analizuj -> przechowuj je w "domyślnej" bazie danych.

Teraz wszystkie 30 (surowe) i 1 domyślna baza danych będą wymagać "synchronizacji", ponieważ zachowamy tę samą strukturę danych abse we wszystkich węzłach.

Teraz, ponieważ patrzymy na skoki procesora we wszystkich bazach danych, sensowne jest używanie baz danych "niewolników" w celu zapytania o "surowe" dane.

stąd wymóg using.Nie jestem w stanie wyobrazić sobie, w jaki sposób routery byłyby pomocne?

Odpowiedz

10

Jesteś na dobrej drodze dzięki routerowi. Zakładam, że fakt, że twoje dwie definicje db są identyczne, to tylko literówka.

(FYI, mam zamiar odnieść się do hierarchii bazy danych przy użyciu the more sensitive master->follower)

W swojej db_for_read funkcje(), można sprawdzić połączenia do naśladowcy. Może to wiązać się z nieco większym obciążeniem, ale jest to koszt posiadania automatycznego przełączania awaryjnego dla bazy danych. Przykładem definicji bazy danych byłoby:

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', 
    }, 
} 

można przetestować połączenie z szybkim try/z wyjątkiem jak this example. Router za pomocą tego, że robi to, co trzeba będzie wyglądać następująco:

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' 

ten nadal będzie syncdb master jak chcesz. Ponadto, można zrobić logikę zarówno db_for_read() i db_for_write() bardziej skomplikowany (jak wybrać zwolennika db tylko dla niektórych modeli, które są testowane na raportach.

nie wiem, co na górze to test_connection() spowoduje dla każdego odczytu, ponieważ będzie to zależeć od serwera MySQL i limitu czasu.Być może lepszą architekturą jest buforowanie tych raportów przy użyciu memcached lub po prostu rozwiązywanie problemów z niewolnikiem kiedykolwiek zejdzie i zaktualizować definicje bazy danych w ustawieniach jako pierwsze

+0

Dzięki. To powinno działać Co mam zamiar zrobić, to '.using (alias = defualt_slave)' jeśli połączenie działa, fajnie jeśli nie, 'using = default' (split with _slave). k gotuj. – Joddy

+0

proszę sprawdzić aktualizację w pytaniu. Nie mogę jeszcze rozwiązać problemu, używanie routera nie ma sensu, gdy 'zestaw zapytań' ma' use'. @krimkus – Joddy

+0

Zamiast przekazywać 'query_on' do właściwości' using', spróbuj wyszukać tę wartość w routerze, a nie podczas tworzenia kwerendy. W ten sposób nadal możesz pozwolić routerowi zdecydować, jaki będzie db. – krimkus

Powiązane problemy