odzyskać pojedynczą bazę danych mysql w zajętym systemie replikacji master-slave


10

Poszukuje strategii lub narzędzia do radzenia sobie z odzyskiwaniem pojedynczej bazy danych do określonego momentu w zajętym replikowanym systemie.

Mam 12 baz danych działających na 2 serwerach MySQL 5.0.77 w konfiguracji replikowanej master-slave. Codziennie wykonywany jest pełny zrzut urządzenia slave tylko do odczytu i dostępne są przyrostowe zrzuty SQL, z tymi kopiami zapasowymi poza siedzibą, a status replikacji jest monitorowany.

Edycja: Tabele to mieszanki InnoDB i myISAM, dlatego też rozwiązania specyficzne dla silnika nie są dostępne.

Więc biorąc pod uwagę całkowitą awarię serwera nadrzędnego, mogę przerwać replikację i wypromować serwer podrzędny, mam również opcję przebudowy nowego serwera i konfiguracji z kopii zapasowej FULL przy użyciu kopii zapasowej, a następnie zastosować różnicę pobieraną co godzinę z urządzenia podrzędnego.

Martwię się jednak, jak radzić sobie z częściową awarią lub awarią pojedynczej bazy danych. Mogę wymyślić 2 scenariusze, które są całkiem prawdopodobne;

  1. baza danych 7 (na przykład) ulega uszkodzeniu, nadal obsługuje niektóre żądania, dopóki ktoś nie zauważy, że jest uszkodzona, lub ostrzega z plików dziennika ...
  2. Niektóre zapytania, takie jak upuszczanie bazy danych, upuszczanie tabeli, zapytanie typu „aktualizuj gdzie ...”, uszkadza pojedynczą bazę danych lub pewien jej podzbiór.

W tej chwili mam kilka pełnych zrzutów w postaci plików FULL- $ DATE-all-databases.sql.gz oraz różnic, które można zastosować do pełnych zrzutów jako DIFF- $ DATE-all-databases.sql.gz

Aby przywrócić bazę danych 7 do pewnego momentu w czasie, konieczne będzie grep przez pliki FULL i DIFF oraz ręczne zastosowanie tej sql.

Jak powinienem postępować, aby móc odzyskać dane na jednym z poprzednich zrzutów DIFF do głównej bazy danych?

Czy muszę wykonać kopię zapasową do poszczególnych plików bazy danych, tj

mysqldump --databases "database1" | gzip > database1.sql.gz
mysqldump --databases "database2" | gzip > database2.sql.gz
mysqldump --databases "database3" | gzip > database3.sql.gz

zamiast..

mysqldump --master-data --lock--all-databases --all-databases | gzip > all-databases.sql.gz

Jeśli wybiorę osobne pliki mysqldump, co stanie się z dziennikiem binarnym danych podstawowych i czy powinienem nawet ustawić - dane-główne dla zrzutów odzyskiwania serwera głównego?

Odpowiedzi:


7

Jeśli cała baza danych korzysta tylko z InnoDB, mam dobre wieści.

Powinieneś zrzucić całą bazę danych równolegle z urządzenia podrzędnego.

W rzeczywistości możesz wymusić na wszystkich bazach danych ten sam punkt w czasie.

Pierwszą rzeczą do zapamiętania o Slave jest to, że nie jest wymagane włączenie rejestrowania binarnego, jeśli nie jest on Master dla innych Slave.

Nie można użyć --master-dataopcji dla zrzutów równoległych, ponieważ każdy zrzut będzie miał inną pozycję zapisaną w linii 22 każdego pliku zrzutu. Lepiej jest zapisać ostatni plik dziennika Master i ustawić Slave za pomocą SHOW SLAVE STATUS\G. W ten sposób wszystkie bazy danych mają tę samą pozycję w czasie.

Możesz zebrać wszystkie bazy danych i wykonać skrypt równoległego zrzutu całej bazy danych.

DBLIST=/tmp/ListOfDatabasesToParallelDump.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema')" > ${DBLIST}

for DB in `cat ${DBLIST}` 
do 
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz & 
done 
wait 

mysql -h... -u... -p... -e"START SLAVE;"

Jeśli istnieje po prostu zbyt wiele baz danych, zrzuć je 10 lub 20 na raz w następujący sposób:

DBLIST=/tmp/ListOfDatabasesToParallelDump.txt
SSS=/tmp/ShowSlaveStatusDisplay.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema')" > ${DBLIST}

COMMIT_LIMIT=20
COMMIT_COUNT=0    
for DB in `cat ${DBLIST}` 
do 
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz & 
    (( COMMIT_COUNT++ ))
    if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
    then
        COMMIT_COUNT=0
        wait
    fi
done 
wait 
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

mysql -h... -u... -p... -e"START SLAVE;"

Jeśli potrzebujesz odzyskać pojedynczą tabelę, możesz równolegle zrzucać tabele 20 na raz w kolejności wielkości.

Spróbuj tego:

TBLIST=/tmp/ListOfTablesToParallelDump.txt
SSS=/tmp/ShowSlaveStatusDisplay.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql','performance_schema') ORDER BY data_length" > ${DBLIST}

COMMIT_LIMIT=20
COMMIT_COUNT=0    
for DBTB in `cat ${TBLIST}` 
do
    DB=`echo "${DBTB}" | sed 's/\./ /g' | awk '{print $1}'`
    TB=`echo "${DBTB}" | sed 's/\./ /g' | awk '{print $2}'`
    DUMPFILE=$DB-{DB}-TBL-${TB}.sql.gz
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} ${TB} | gzip >  ${DUMPFILE} & 
    (( COMMIT_COUNT++ ))
    if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
    then
        COMMIT_COUNT=0
        wait
    fi
done 
wait 
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

mysql -h... -u... -p... -e"START SLAVE;"

Teraz, gdy masz skrypty do zrzucania baz danych lub pojedynczych tabel, możesz załadować te dane według własnego uznania. Jeśli chcesz uruchomić SQL z dzienników binarnych w systemie głównym, możesz użyć mysqlbinlogi nadać mu pozycję datetime i wyprowadzić SQL do innych plików tekstowych. Musisz tylko dołożyć należytej staranności, aby znaleźć potrzebną ilość danych z dowolnych znaczników czasu, jakie mają dzienniki bnary. Pamiętaj tylko, że znacznik czasu każdego dziennika binarnego w systemie operacyjnym oznacza, że ​​był ostatnio zapisywany.


genialne odpowiedzi dzięki. Myślę, że posiadanie slave'a tylko do odczytu na XFS daje mi mnóstwo opcji, a twoje skrypty naprawdę pomogły.
— Tom H

w scenariuszu, w którym muszę odzyskać ogromny stół do mistrza z kopii zapasowej poza niewolnikiem. Muszę tylko odbudować tabelę w systemie głównym i wszystkie zmiany zostaną zreplikowane do urządzenia podrzędnego, nawet jeśli jest to 20 GB danych? Czy proces byłby następujący: 1) wyłącz klucze, 2) upuść tabelę na master i slave 3) przywróć tabelę master 4) włącz klucze --- i niech master replikuje wszystkie 20 GB aż do slave?
— Tom H

Jeśli te bazy danych NIE są innodb, czy nadal mogę je zrzucić równolegle?
— Tom H

Tak, jeśli 1) zaplanujesz przestoje, 2) uruchom service mysql restart --skip-networking, 3) wykonaj zrzut równoległy, 4) uruchom service mysql restart. Następnie załaduj ponownie potrzebne tabele.
— RolandoMySQLDBA

przypuszczalnie, jeśli celem restartu było zapobieganie zapisywaniu połączeń sieciowych do bazy danych, to mógłbym osiągnąć ten sam efekt, używając iptables i.e. iptables -I INPUT -p tcp --dport 3306 -j DROPet0 i lo
— Tom H
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.