Jak mogę zoptymalizować mysqldump dużej bazy danych?

173

Mam aplikację symfony z bazą danych InnoDB, która jest ~ 2 GB z 57 tabelami. Większość wielkości bazy danych znajduje się w jednej tabeli (~ 1,2 GB). Obecnie używam mysqldump do tworzenia kopii zapasowych bazy danych co noc.

Z powodu mojego połączenia Comcast, często jeśli ręcznie wykonuję zrzut, moje połączenie z serwerem kończy się przed zakończeniem zrzutu, co powoduje, że muszę go ponownie uruchomić. [Obecnie uruchamiam crona, który wykonuje zrzut w nocy, to tylko dla zrzutów, które uruchamiam ręcznie.]

Czy istnieje sposób na przyspieszenie zrzutów w związku z przekroczeniem limitu czasu połączenia, ale także ograniczenie czasu zajmowanego przez serwer z tym procesem?

BTW, obecnie pracuję nad zmniejszeniem wielkości ogólnej bazy danych, aby rozwiązać ten problem.

Patrick
źródło
2
Jakie parametry (jeśli występują) przekazujesz do polecenia mysqldump?
Toby
Dodanie --compact może być dla Ciebie opcją.
Toby
nic tak naprawdę -mysqldump [database] -u[user] -p'[password]' > db_backup.sql
Patrick
4
Prostą alternatywą screendla twojej sytuacji byłoby użycie nohup, pozwoli ci to kontynuować działanie polecenia na serwerze, nawet jeśli połączenie zostanie zerwane. Np nohup mysqldump [options] > backup.sql 2> backup.err &. Jeśli nie podasz pliku wyjściowego nohup, zostanie on utworzony nohup.outdomyślnie.
dabest1
1
Spójrz na ati screen(ten ostatni, jeśli jest zainstalowany, ale atjest standardem we wszystkich systemach uniksowych) lub ServerAliveIntervalopcje SSH, aby dowiedzieć się, jak radzić sobie z zaporą zamykającą cię po zbyt długim bezczynnym połączeniu.
MattBianco,

Odpowiedzi:

134

Głównym wąskim gardłem tego zrzutu jest napęd I / O. Odczytujesz ładunek danych i zapisujesz je ponownie. Możesz to przyspieszyć na kilka sposobów:

  • Upewnij się, że dane wyjściowe są przesyłane na inny dysk (dyski) niż ten, na którym przechowywane są pliki bazy danych - będzie to ogromna różnica w przypadku obracających się dysków, ponieważ głowice napędów nie będą ciągle przesuwać się między lokalizacją, z której są odczytywane i lokalizację, w której jest zapisywany.
  • Dane wyjściowe mysqldump będą bardzo ściśliwe, więc jeśli nie możesz oddzielić danych wyjściowych od danych wejściowych, jak wspomniano powyżej, potokuj dane wyjściowe gziplub podobnie. Zmniejszy to ilość zapisywanego tekstu (a więc zmniejszy ogólne obciążenie IO i ruchy głowy) kosztem czasu procesora (który i tak może mieć dużo wolnego czasu).
  • Ponadto (podobnie jak zamiast kompresji) przekaż dane wyjściowe przez narzędzie potokowe (takie jak pv ), które obsługuje duże bufory zapisu, aby zgrupować bloki zapisane na dyskach bardziej razem, ponownie, aby zmniejszyć efekt opóźnienia ruchu głowy - spowoduje to duża różnica, jeśli skorzystasz z --quickopcji zmniejszenia wpływu pamięci RAM podczas tworzenia kopii zapasowych dużych tabel).
  • Uruchom proces tworzenia kopii zapasowej tylko wtedy, gdy obciążenie We / Wy jest w przeciwnym razie niskie.

Być może naprawiasz niewłaściwy problem: zamiast tego łatwiej jest rozwiązać problemy z połączeniami (chociaż zmniejszenie obciążenia we / wy narzuconego przez kopie zapasowe pomoże zmniejszyć wpływ, jaki wywierasz na innych użytkowników, więc i tak warto spróbować). Czy możesz uruchomić ręczne tworzenie kopii zapasowych na ekranie (lub podobnych narzędziach, takich jak tmux )? W ten sposób, jeśli połączenie z serwerem zostanie screenprzerwane , możesz po prostu ponownie połączyć się i ponownie dołączyć do sesji bez przerywania procesów.

Jeśli wysyłasz dane bezpośrednio przez połączenie (tj. Uruchamiasz mysqldump na komputerze lokalnym ze zdalną bazą danych, więc zrzut pojawia się lokalnie), lepiej najpierw uruchomić zrzut na serwerze, kompresując go w razie potrzeby, a następnie przesyłając dane w sieci za pomocą narzędzia (takiego jak rsync), które obsługuje częściowe transfery, abyś mógł wznowić transfer (zamiast restartu), jeśli przerwa w połączeniu go zakłóci.

W ramach „zmniejszania wielkości ogólnej bazy danych w celu rozwiązania tego problemu” zgaduję, że duża część twoich danych się nie zmienia. Być może będziesz w stanie przenieść dużą część 1,2 Gb z głównej tabeli do innej i usunąć ją z tych, które zostały skopiowane przez mysqldumppołączenie. Nie trzeba tworzyć kopii zapasowych tych danych za każdym razem, jeśli nigdy się nie zmieni. Dzielenie danych między tabelami i bazami danych w ten sposób jest zwykle określane jako partycjonowanie danych i może również pozwolić na rozłożenie danych i obciążenia we / wy na wiele dysków. Wysokiej klasy baza danych ma wbudowane wsparcie dla automatycznego partycjonowania, chociaż w mysql prawdopodobnie będziesz musiał to zrobić ręcznie i zmienić warstwę dostępu do danych, aby to uwzględnić.

Odchodzę od tematu dla tej witryny (więc prawdopodobnie powinieneś przejść do ServerFault lub SuperUser, aby zapytać, czy potrzebujesz więcej szczegółów): Jeśli wydajesz się tracić połączenia z powodu braku aktywności, sprawdź opcje na serwerze SSH i kliencie SSH, aby upewnij się, że pakiety podtrzymujące są włączone i wysyłane wystarczająco często. Jeśli widzisz spadki, nawet jeśli połączenie jest aktywne, możesz również spróbować użyć OpenVPN lub podobnego do zawinięcia połączenia - powinno ono obsłużyć krótki spadek, a nawet całkowity spadek, jeśli całe połączenie zostanie zerwane na kilka sekund, tak że klient SSH i serwer nie zauważa.

David Spillett
źródło
Chciałbym móc zmniejszyć liczbę porzuconych połączeń ssh z moimi serwerami. Jeśli spodziewam się, że nie będę używać terminala dłużej niż ~ 60 sekund, działam, topaby upewnić się, że połączenie nie zostanie zerwane. (I jestem prawie pewien, że jest to połączenie Comcast, ponieważ używamy tylko standardowego routera WRT i zapory w pracy, a moje domowe połączenie Comcast nigdy nie spada)
Patrick
Dodałem krótką notatkę dotyczącą połączeń SSH.
David Spillett,
2
Głębokość i wgląd w tę odpowiedź. Powinieneś dostać za to +3. Przepraszam, mogę dać ci tylko +1.
RolandoMySQLDBA
116

INSIGHT IN THE RING BACKUPS WITH mysqldump

Tworzenie kopii zapasowych przez IMHO stało się bardziej formą sztuki, jeśli wiesz, jak się do tego zbliżyć

Masz opcje

Opcja 1: mysqldump całą instancję mysql

To jest najłatwiejsze, bez myślenia !!!

mysqldump -h... -u... -p... --hex-blob --routines --triggers --all-databases | gzip > MySQLData.sql.gz

Wszystko zapisane w jednym pliku: struktury tabel, indeksy, wyzwalacze, procedury składowane, użytkownicy, zaszyfrowane hasła. Inne opcje mysqldump mogą również eksportować różne style poleceń INSERT, plik dziennika i współrzędne pozycji z dzienników binarnych, opcje tworzenia bazy danych, częściowe dane (opcja --where) i tak dalej.

Opcja 2: mysqldump oddzielne bazy danych w osobne pliki danych

Zacznij od utworzenia listy baz danych (w tym celu 2 techniki)

Technika 1

mysql -h... -u... -p... -A --skip-column-names -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql')" > ListOfDatabases.txt

Technika 2

mysql -h... -u... -p... -A --skip-column-names -e"SELECT DISTINCT table_schema FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql')" > ListOfDatabases.txt

Technika 1 to najszybszy sposób. Technika 2 jest najpewniejsza i najbezpieczniejsza. Technika 2 jest lepsza, ponieważ czasami użytkownicy tworzą foldery do ogólnych celów w / var / lib / mysql (datadir), które nie są powiązane z bazą danych. Information_schema zarejestruje folder jako bazę danych w tabeli information_schema.schemata. Technika 2 pomija foldery, które nie zawierają danych mysql.

Po skompilowaniu listy baz danych możesz przejść do jej przeglądania i mysqldump, nawet jeśli to konieczne, równolegle.

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

Jeśli istnieje zbyt wiele baz danych, aby uruchomić je jednocześnie, zrzuć je równolegle 10:

COMMIT_COUNT=0
COMMIT_LIMIT=10
for DB in `cat ListOfDatabases.txt`
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
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

Opcja 3: mysqldump oddzielne tabele w osobne pliki danych

Zacznij od utworzenia listy tabel

mysql -h... -u... -p... -A --skip-column-names -e"SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql')" > ListOfTables.txt

Następnie zrzuć wszystkie tabele w grupach po 10

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

Opcja 4: WYKORZYSTAJ WYOBRAŹNIĘ

Wypróbuj odmiany wyżej wymienionych Opcji oraz techniki czyszczenia migawek

Przykłady

  1. Uporządkuj listę tabel według wielkości każdej tabeli rosnąco lub malejąco.
  2. Korzystając z osobnego procesu, uruchom „FLUSH TABLES WITH READ LOCK; SELECT SLEEP (86400)” przed uruchomieniem mysqldumps. Zabij ten proces po zakończeniu mysqldumps. Jest to pomocne, jeśli baza danych zawiera zarówno InnoDB, jak i MyISAM
  3. Zapisz mysqldumps w datowanych folderach i obróć stare foldery kopii zapasowych.
  4. Załaduj mysqldumps całej instancji do samodzielnych serwerów.

CAVEAT

Tylko opcja 1 przynosi wszystko. Wadą jest to, że mysqldump utworzone w ten sposób można przeładować tylko do tej samej wersji mysql wydania Majot, w której został wygenerowany mysqldump. Innymi słowy, mysqldump z bazy danych MySQL 5.0 nie może zostać załadowany do wersji 5.1 lub 5.5. Powód ? Schemat mysql różni się w zależności od głównych wersji.

Opcje 2 i 3 nie obejmują zapisywania nazw użytkowników i haseł.

Oto ogólny sposób na zrzucenie Grantów SQL dla użytkowników, który jest czytelny i bardziej przenośny

mysql -h... -u... -p... --skip-column-names -A -e"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''" | mysql -h... -u... -p... --skip-column-names -A | sed 's/$/;/g' > MySQLGrants.sql

Opcja 3 nie zapisuje procedur przechowywanych, więc możesz wykonać następujące czynności

mysqldump -h... -u... -p... --no-data --no-create-info --routines > MySQLStoredProcedures.sql &

Inną kwestią, na którą należy zwrócić uwagę, jest InnoDB. Jeśli masz dużą pulę buforów InnoDB, opróżnij ją najlepiej, jak potrafisz, przed wykonaniem jakichkolwiek kopii zapasowych. W przeciwnym razie MySQL spędza czas na opróżnianiu tabel z resztek brudnej strony z puli buforów. Oto, co sugeruję:

Na około godzinę przed wykonaniem kopii zapasowej uruchom to polecenie SQL

SET GLOBAL innodb_max_dirty_pages_pct = 0;

W MySQL 5.5 domyślna wartość innodb_max_dirty_pages_pct wynosi 75. W MySQL 5.1 i starszych domyślna wartość innodb_max_dirty_pages_pct wynosi 90. Ustawienie wartości innodb_max_dirty_pages_pct na 0 przyspieszy opróżnianie brudnych stron na dysk. Zapobiegnie to lub przynajmniej zmniejszy wpływ czyszczenia niekompletnych dwufazowych zatwierdzeń danych InnoDB przed wykonaniem jakiegokolwiek mysqldump względem jakichkolwiek tabel InnoDB.

OSTATECZNE SŁOWO NA mysqldump

Większość ludzi unika mysqldump na rzecz innych narzędzi i te narzędzia są naprawdę dobre.

Takie narzędzia obejmują

  1. MAATKIT (równoległe skrypty zrzutu / przywracania , z Percona [Przestarzałe, ale świetne])
  2. XtraBackup (TopNotch Snapshot Backup from Percona)
  3. CDP R1Soft ( opcja modułu MySQL, która wykonuje migawki w określonym momencie)
  4. MySQL Enterprise Backup (wcześniej InnoDB Hot Backup) [komercyjny])

Jeśli masz ducha prawdziwego MySQL DBA, możesz objąć mysqldump i mieć nad nim pełną biegłość. Niech wszystkie twoje kopie zapasowe będą odzwierciedleniem twoich umiejętności jako MySQL DBA .

RolandoMySQLDBA
źródło
2
+1 za miłe użycie mysqldump, a także za: Jeśli masz ducha prawdziwego MySQL DBA, możesz objąć mysqldump i mieć nad nim pełną kontrolę. Niech wszystkie twoje kopie zapasowe będą odzwierciedleniem twoich umiejętności jako MySQL DBA .... Świetne linie !!!
Abdul Manaf
4
W InnoDB pojedyncze tabele zrzutu dają niespójne kopie zapasowe.
Alain Collins
5
@AlainCollins dlatego uruchamiam mysqldumps na slave replikacji, która jest tylko do odczytu. Gdy Seconds_Behind_Master ma wartość 0, uruchamiasz STOP SLAVE. Teraz masz spójny moment na wykonanie mysqldump w dowolnym z wyżej wymienionych stylów. Zrobiłem to dla internetowych firm handlowych w ciągu ostatnich 5 lat bez jednej skargi do mnie lub właścicieli mojej firmy. Od tego momentu robię równoległe mysqldumps co 10 minut dla tego klienta. Robię to również dla innych klientów, aby zapewnić szybsze okresy tworzenia kopii zapasowych.
RolandoMySQLDBA
Mam 32 GB db, więc opcja 3 jest dokładnie tym, co miałem na myśli! dzięki!
Raymond
Muszę wykonać kopię zapasową i ponownie zaimportować 1 TB danych, aby zmniejszyć bardzo duże ibdata1. W czasach dysków SSD wspieranych przez sprzętową macierz RAID opcja 3 jest dla mnie jedynym rozwiązaniem.
rabudde
18

Spójrz na master replikacji MySQL na slave. Pozwala sklonować bazę danych master na innym serwerze bazy danych z tą samą bazą danych. Obejmuje to tożsamość master i slave. Slave tworzy dokładną kopię głównego serwera bazy danych i / lub jego baz danych. Pomiędzy panem (-ami) i niewolnikiem (-ami) może istnieć relacja jeden-jeden, jeden-wiele, wiele-jeden.

Slave stale odczytuje dziennik binarny w master (dziennik bin przechowuje zapytania zapisane na głównym serwerze bazy danych) i pobiera dane wejściowe do swojego serwera slave bazy danych. (oznacza to, że nie będzie to miało wpływu na twoją główną bazę danych)

Dobra wiadomość jest taka, że ​​nie wpłynie to zbytnio na twój serwer MySQL, ponieważ nie zauważysz żadnych przestojów ani powolnych odpowiedzi na zapytania. Używamy go do baz danych 10 Gb i działa jak urok bez żadnych przestojów.

Replikacja MySQL na tym samym komputerze

poelinca
źródło
choć byłoby to dla mnie skuteczne, myślę, że to może być trochę przesada. Obecnie nie potrzebuję tego poziomu tworzenia kopii zapasowych, chociaż będę o tym pamiętać, jeśli zmienią się wymagania aplikacji.
Patrick
4
+1 za wykonanie kopii zapasowej repliki w celu usunięcia obciążenia We / Wy kopii zapasowej z głównej bazy danych i zmniejszenia potencjalnych problemów związanych z blokowaniem, z jednym znaczącym zastrzeżeniem: należy zachować ostrożność przy opcji „repliki na tej samej maszynie”, co w przypadku operacji na slave może konkurować z urządzeniem nadrzędnym o przepustowość we / wy - upewnij się, że pliki danych urządzenia podrzędnego mają inny dysk / macierz niż urządzenie nadrzędne, aby złagodzić ten problem.
David Spillett
1
To samo dotyczy komentarza Davida Spllleta. Konfiguruję i utrzymuję dziesiątki Master / Slaves z kopiami zapasowymi mysqldump na urządzeniach slave dla My Web Hosting Employer. +1 ode mnie również.
RolandoMySQLDBA
16

Plan A: Zobacz także Xtrabackup z Percona. Umożliwia to tworzenie kopii zapasowych InnoDB online bez znaczącego blokowania.

Plan B: Slave można zatrzymać i można wykonać spójną kopię zapasową na kilka sposobów (kopiowanie plików, mysqldump, xtrabackup itp.)

Plan C: Migawka LVM. Po pewnej tajemniczej konfiguracji czas przestoju dla kopii zapasowej wynosi mniej niż minutę, niezależnie od wielkości bazy danych. Zatrzymujesz mysqld, robisz migawkę, restartujesz mysqld, a następnie kopiujesz migawkę. Ostatni krok może zająć dużo czasu, ale MySQL nie działa.

Plan D: Migawka niewolnika - zero przestojów.

Rick James
źródło
2
Brawo dla wszystkich czterech planów. Mogę dać tylko +0,25 za odpowiedź !!! +1 (4 x 0,25)
RolandoMySQLDBA
15

Najpierw kilka punktów administratora: czy łączysz się, aby zrobić ftp, czy jesteś zalogowany i umiera? Jeśli ssh, pamiętaj o użyciu screena , aby móc wznowić działanie po awarii programu. Jeśli ftp, to upewnij się, że kompresujesz / tar przed wysłaniem.

Spróbuj także parametru --opt lub --quick

--opt Ta opcja włącza zestaw dodatkowych opcji, aby usprawnić operacje zrzutu i przeładowania. W szczególności jest to równoważne z jednoczesnym stosowaniem opcji --add-drop-table, --add-locks, --all, --quick, --extended-insert, --lock-tables i --disable-keys. Zauważ, że ta opcja sprawia, że ​​dane wyjściowe są mniej przenośne i mniej prawdopodobne, że zostaną zrozumiane przez inne systemy baz danych.

--quick Ta opcja informuje mysqldump, aby zapisał dane zrzutu, gdy odczytuje każdy wiersz z serwera, co może być przydatne w przypadku dużych tabel. Domyślnie mysqldump czyta wszystkie wiersze z tabeli do pamięci przed zapisaniem danych wyjściowych; w przypadku dużych tabel wymaga to dużej ilości pamięci, co może spowodować niepowodzenie zrzutu.

David Hall
źródło
1
Czy --opt nie zwiększy rozmiaru pliku, który ostatecznie uzyska dane wyjściowe?
Toby
Doda to trochę - chciałem dodać - szybkie, co jest bardziej odpowiedzią na jego problem ... edycja teraz. Dzięki!
David Hall
+1 za ekran, co całkowicie eliminuje ten problem
Gajusz
+1 za bardzo miłą i zwięzłą odpowiedź na mysqldump --opt i - szybkie wyjaśnienia.
RolandoMySQLDBA
1
--opt jest domyślnie włączony.
Jordan
5

Miałem problemy z przekroczeniem limitu czasu również podczas zrzutów dużych baz danych. W końcu rozwiązałem, jeśli wysyłając indywidualne polecenia dla każdej tabeli w bazie danych i dołączając wszystko do jednego pliku w następujący sposób:

TABLES=`mysql -u $USER -p$PWD -Bse 'show tables' $DB`
for TABLE in $TABLES
do
    mysqldump -u $USER -p$PWD $DB $TABLE >> dump.sql
done
Patrick Heck
źródło
4
Jest to uważane za „niespójną” kopię zapasową, ponieważ po przywróceniu możesz mieć dane w jednej tabeli, które są mapowane na inną, ale nie istnieją.
Morgan Tocker,
3

Myślę, że pytanie dotyczy tego, jak szybciej przywracać z plików zrzutu utworzonych przez mysqldump, a nie innego rozwiązania do tworzenia kopii zapasowych.

Jednym ze sposobów, w jaki można to zrobić, jest utworzenie grup tabel w schemacie i utworzenie osobnego użytkownika bazy danych dla każdej grupy, a następnie użycie uprawnień MySQL, aby nie zezwalać na wstawianie tabel z użyciem tylko jednego użytkownika bazy danych.

Jest to sprawdzona, szybka, prawie równoległa technika, ale nie w 100% pewna, ile czasu zajmie przywrócenie z dużych zrzutów, takich jak 500G lub mniej więcej. Ale moim skromnym zdaniem potrzebujesz czegoś równoległego. Sprawdź poniższy link jako przykład.

[Szybkie, równoległe przywracanie ze zrzutów SQL (mysqldump) dla MySQL] [1]

http://geeksww.com/tutorials/database_management_systems/mysql/tips_and_tricks/fast_parallel_restore_from_sql_dumps_mysqldump_for_mysql.php

„Szybkie, równoległe przywracanie ze zrzutów SQL (mysqldump) dla MySQL”

syed
źródło
2
To jest dokładna kopia twojej odpowiedzi na inne pytanie. Możesz chcieć dostosować to nieco bardziej do tego konkretnego pytania.
Paul White
Pytanie w szczególności NIE dotyczy sposobu szybszego przywracania.
andrew lorien