Tworzenie kopii zapasowej bazy danych MySQL za pomocą migawek ZFS

12

Znalazłem wiele witryn mówiących o tym, ale brakuje mi kilku ważnych szczegółów. Ogólne kroki są

  • Biegać FLUSH TABLES WITH READ LOCK
  • Zrób migawkę ZFS
  • Biegać UNLOCK TABLES

Różne źródła podają, że InnoDB, którego używam, tak naprawdę nie honoruje FLUSH. Podręcznik użytkownika MySQL zauważa, że ​​istnieje FLUSH TABLES...FOR EXPORTwariant do użycia z InnoDB, ale wymaga on indywidualnego określenia każdej tabeli, zamiast tworzenia kopii zapasowej całej bazy danych. Wolałbym unikać określania każdej tabeli indywidualnie, ponieważ istnieje spora szansa, że ​​lista tabel nie będzie zsynchronizowana z tabelami, które faktycznie istnieją.

Innym problemem, jaki mam, jest to, że planuję zrobić coś takiego mysql -h"$HOST" -u"$USERNAME" -p"$PASSWORD" --execute="FLUSH TABLES WITH READ LOCK". Spowoduje to jednak opuszczenie blokady natychmiast po zakończeniu sesji. Ma to sens, ale jest również dość irytujące, ponieważ muszę trzymać blokadę odczytu, gdy wykonuję migawkę.

Moim drugim pomysłem jest zrobienie kopii zapasowej na gorąco za pomocą narzędzia takiego jak Percona XtraBackup i zrobienie migawek kopii zapasowej, ale wolałbym nie ponosić kosztów zapisania wszystkich moich danych w drugiej lokalizacji, aby je wykonać.

Andy Shulman
źródło
Dlaczego masz statyczną listę tabel? Z pewnością możesz wygenerować listę dynamicznie w czasie wykonywania.
EEAA
1
Czy baza danych jest na maszynie wirtualnej czy na gołym metalu? Czy pamięć jest nawet na tym samym komputerze?
Michael Hampton
EEAA, w porządku.
Andy Shulman,
Michael, baza danych i ZFS to różne maszyny, ale żadna z nich nie jest zwirtualizowana.
Andy Shulman,
@AndyShulman Myślę, że powinieneś wyjaśnić układ nieco lepiej. To nie ma sensu.
ewwhite

Odpowiedzi:

4

Jeśli używasz InnoDB tylko dla wszystkich tabel i ustaw innodb_flush_log_at_trx_commitna:

  • 1 (zawartość bufora dziennika InnoDB jest zapisywana do pliku dziennika przy każdym zatwierdzeniu transakcji, a plik dziennika jest opróżniany na dysk) lub,
  • 2 (zawartość bufora dziennika InnoDB jest zapisywana do pliku dziennika po każdym zatwierdzeniu transakcji, a plik dziennika jest opróżniany na dysk około raz na sekundę),

wtedy nie potrzebujesz FLUSH TABLES przed zrobieniem migawki, po prostu uruchom migawkę ZFS bezpośrednio. InnoDB może odzyskiwać dane z dzienników zatwierdzania transakcji bez utraty danych.

Ref: https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit

Gea-Suan Lin
źródło
Dzięki słownikowi danych wprowadzonemu w MySQL 8 nawet operacje DDL (modyfikacja schematu) są teraz atomowe. Wcześniej operacje DDL podczas migawki systemu plików mogły dawać częściowo zatwierdzone (tj. Uszkodzone) wyniki.
bernie,
13

Potrzebujesz pełnej blokady bazy danych, aby konsekwentnie tworzyć kopie zapasowe (większości) baz danych.

Podręcznik https://dev.mysql.com/doc/refman/5.5/en/backup-methods.html mówi, że TABLICE PŁUKUJĄCE Z BLOKADĄ CZYTANIA są właściwe dla migawek ZFS.

Tworzenie kopii zapasowych przy użyciu migawki systemu plików

Jeśli używasz systemu plików Veritas, możesz wykonać kopię zapasową w następujący sposób:

  1. Wykonaj z programu klienckiego FLUSH TABLES WITH READ LOCK.
  2. Z innej powłoki uruchom vxfsmigawkę montowania .
  3. Wykonaj od pierwszego klienta UNLOCK TABLES.
  4. Skopiuj pliki z migawki.
  5. Odmontuj migawkę.

Podobne możliwości tworzenia migawek mogą być dostępne w innych systemach plików, takich jak LVM lub ZFS.

To niby śmieszne , że pominięty fakt, że trzeba FLUSH TABLES table_a, table_b, table_c FOR EXPORTdla InnoDB z tymi instrukcjami. Głupio jest też wymieniać takie tabele. Ale, jak mówi EEAA, możesz dość łatwo wygenerować listę tabel, gdy zaczniesz tworzenie kopii zapasowej.

Jeśli chodzi o trzymanie blokady, musisz zachować aktywne połączenie db podczas wykonywania migawki

Zasadniczo użyłbym czegoś takiego jak Perl lub inny język programowania, który może łączyć, blokować db i utrzymując połączenie db wziąć migawkę, a następnie odblokować i rozłączyć. To nie jest skomplikowane. Założę się, że istnieją narzędzia, które już to robią, ale napisanie jednego jest łatwe.

Mówię kilka razy łatwo, nie skomplikowane itp. Zakładam, że masz jakieś podstawowe umiejętności programowania lub pisania skryptów.

Ryan Babchishin
źródło
Miałem nadzieję, że zachowam tak prosty pod względem koncepcyjnym skrypt w Bash, ale masz rację, zmiana języków sprawia, że ​​jest to o wiele łatwiejsze. Być może źle czytam twoją odpowiedź, ale wygląda na to, że mówisz, że muszę wykonać jedno FLUSH TABLES WITH READ LOCKi drugie FLUSH TABLES...FOR EXPORT, podczas gdy moje czytanie podręcznika MySQL mówi, że tylko jedna powinna być potrzebna.
Andy Shulman,
Przepraszam, że nie było jasne. Po prostu korzystam z instrukcji i mówi ona dwie różne rzeczy. Domyślam się, że masz rację i potrzebujesz tylko później. Ale wszystkie tabele powinny być zablokowane w jednym poleceniu.
Ryan Babchishin
1
Biorąc pod uwagę, że dokumentacja nie jest bardzo jasna, cała baza danych musi zostać zablokowana, a połączenie DB musi być utrzymywane podczas wykonywania migawki, łatwiej jest po prostu zamknąć DB, wykonać kopię zapasową i ponownie uruchomić to.
Andrew Henle,
2
@ andrew westchnienie ... Rozumiem. Ale to będzie powolne, spowoduje, że połączenia spadną / zakończą się niepowodzeniem, a ja widziałem, że bazy danych nie mogą poprawnie wrócić do bazy danych (złe dla automatyzacji). Dobrze byłoby uzyskać ostateczną odpowiedź od mysql / Oracle. Muszą mieć listę mailingową.
Ryan Babchishin
7

Zerwałem i dostosowałem koncepcyjnie prosty skrypt w Bash, który znalazłem w innym poście o błędzie serwera autorstwa Tobii . To powinno zapewnić ci około 90% drogi.

mysql_locked=/var/run/mysql_locked

# flush & lock MySQL, touch mysql_locked, and wait until it is removed
mysql -hhost -uuser -ppassword -NB <<-EOF &
    flush tables with read lock;
    delimiter ;;
    system touch $mysql_locked
    system while test -e $mysql_locked; do sleep 1; done
    exit
EOF

# wait for the preceding command to touch mysql_locked
while ! test -e $mysql_locked; do sleep 1; done

# take a snapshot of the filesystem, while MySQL is being held locked
zfs snapshot zpool/$dataset@$(date +"%Y-%m-%d_%H:%M")

# unlock MySQL
rm -f $mysql_locked

Tutaj używane mysqlpolecenie jest uruchamiane w tle i dotyka pliku. Czeka w tle, aż plik zniknie, przed wyjściem i odblokowaniem tabel. Tymczasem główny skrypt czeka na istnienie pliku, a następnie tworzy migawkę i usuwa plik.

Plik wskazany przez $mysql_lockedmusi być dostępny dla obu komputerów, co powinieneś być w stanie zrobić wystarczająco łatwo, ponieważ oba mogą uzyskać dostęp do wspólnego zestawu danych (chociaż mogą one używać różnych ścieżek, i powinieneś to uwzględnić).

Michael Hampton
źródło
Nie znam skryptów MySQL, więc może to być głupi pomysł, ale czy nie mógłbyś zrobić system zfs snapshot...tego w głównym skrypcie? A może migawki muszą przebiegać w osobnym procesie?
TripeHound,
@Tripehound obie rzeczy muszą się jakoś równolegle wydarzyć
Ryan Babchishin,
@RyanBabchishin Myślę, że on ma rację. SYSTEMPolecenie uruchamia rzeczy lokalnie. Jeśli uruchomię klienta mysql na polu FreeBSD i wykonam LOCK; SYSTEM zfs snapshot; UNLOCK, wydaje się, że to zadziała.
Andy Shulman,
@Andy właśnie powiedziałem, że muszą zdarzyć się równolegle. Nie ważne, jak sobie z tym poradzisz.
Ryan Babchishin
2

Do myisam potrzebujesz FLUSH TABLES WITH READ LOCK, ponieważ nie jest to kronikowanie.

Naprawdę nie potrzebujesz niczego dla innodb, IMO, ponieważ jest to księgowanie. I tak będzie spójny, po prostu automatycznie cofa dziennik, jeśli coś dzieje się w momencie, gdy migawka jest atomowa.

Jeśli chcesz mieć spójność na poziomie aplikacji, powinna ona wykorzystywać transakcje. Jeśli twoja aplikacja korzysta z transakcji i innodb, każda migawka będzie spójna, pytaj automatycznie o poziom aplikacji.

Jim Salter
źródło
2

Oto moje rozwiązanie, jak utworzyć migawkę ZFS przy zachowaniu blokady:

mysql << EOF
    FLUSH TABLES WITH READ LOCK;
    system zfs snapshot data/db@snapname
    UNLOCK TABLES;
EOF
Petr Stastny
źródło