Czy jest lepsze wyjście z dziennika MySQL InnoDB „w przyszłości”?

16

Mam ten błąd InnoDB w MySQL 5.0. Mysqld został zatrzymany czysto, ale później udało mi się utracić ib_logfile0 i ib_logfile1. Teraz po czystym uruchomieniu InnoDB wykonało „odzyskiwanie po awarii”. Przeszedłem przez firmę innodb_force_recovery = 4, naprawiłem zawieszoną tabelę MyISAM, a teraz replika jest gotowa do pracy, oprócz tego. Wielkie zatwierdzone liczby:

111116 15:49:36  InnoDB: Error: page 393457 log sequence number 111 561,760,232
InnoDB: is in the future! Current system log sequence number 70 3,946,969,851.
InnoDB: Your database may be corrupt or you may have copied the InnoDB
InnoDB: tablespace but not the InnoDB log files. See
InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html
InnoDB: for more information.

To jest na serwerze podrzędnym. Powyższy błąd wyrzuca setki. Znalazłem odpowiedź: „wstaw i usuń dane o wartości> 64 GB, aby numer sekwencyjny dziennika został wystarczająco zawyżony”.

http://forums.mysql.com/read.php?22,50163,50163#msg-50163

Ta magiczna liczba 64 GB pochodzi z 4 GB * 16, gdzie „główna liczba” logu tego faceta musiała wzrosnąć z 0 do 15. Mój idzie z 70 do 111 = 164 GB. Zajmie to 5 dni. Będę pracował nad przyspieszeniem mojego skryptu i równoległym uruchomieniem go, aby to przyspieszyć. Tymczasem mam nadzieję, że ktoś inny ma lepszą odpowiedź. To jest głupie.

IcarusNM
źródło
Jedna obiecująca odpowiedź: „Jeśli jest to serwer podrzędny, najlepszym rozwiązaniem byłoby przeniesienie bazy danych na bok i zainstalowanie nowej migawki z serwera głównego”. Niestety istnieje 20 000 tabel w 25 bazach danych, połączenie MyISAM i InnoDB, w produkcji 24x7. Zbyt długo zajęłoby to zamknięcie i wykonanie nowej pełnej replikacji przed ponownym uruchomieniem replikacji.
IcarusNM,
4
Teraz mam 8-rdzeniową maszynę na kolanach w bezcelowym wyścigu, aby tworzyć i usuwać 164 gigabajty danych. Jedyną alternatywą, jaką słyszę, jest zniszczenie wszystkiego na tym niewolniku i rozpoczęcie od nowa. Wszystko, aby skutecznie zmienić jedną liczbę w dwóch plikach. Na pewno jest jakiś inżynier InnoDB z profesjonalną wskazówką. Czy ktoś kiedykolwiek otworzył plik ib_logfile0 w Emacsie, znalazł magiczną liczbę w heksie i po prostu ją zmienił?
IcarusNM,
Oto świetny artykuł na temat kilku sposobów na zrobienie tego. Percona jest zdecydowanie autorytetem w MySQL. percona.com/blog/2013/09/11/…
jbrahy

Odpowiedzi:

10

To była dość rzadka sytuacja. Mam nadzieję, że już nigdy tam nie skończę, z InnoDB „kolejny numer dziennika jest w przyszłości!” błąd. Z powodu moich konkretnych szczegółów odbudowanie / przywrócenie danych mojego serwera było ostatecznością. Niektóre oszustwa w pomaganiu, które były dobrymi pomysłami, ale ostatecznie postanowiłem po prostu ulepszać mój skrypt Perla, aby grać w tę głupią grę i przerzucać tyle koncertów, ile mogłem. Co do cholery, to dobry test warunków skrajnych systemu.

Pamiętaj: celem jest zwiększenie pojedynczego licznika („numeru sekwencji dziennika”), który jest przechowywany gdzieś w nagłówkach ib_logfile0 i ib_logfile1 . Ma to na celu sfałszowanie InnoDB, aby zignorował pozorne wypaczenie czasu i zaczął żyć. Ale nikt nie wie, jak edytować ten numer. A jeśli wiedzą, nikt nie mówi.

Oto mój produkt końcowy. YMMV, ale użycie funkcji REPEAT mysql do wewnętrznego generowania danych jest bardzo wydajne.

 #!/usr/bin/perl
 use DBI;
 $table = shift || die;
 $dbh = DBI->connect("DBI:mysql:junk:host=localhost", "user", "pass"); #Edit "junk" (DB name), user, and pass to suit.
 $dbh->do("DROP TABLE IF EXISTS $table");
 $dbh->do("CREATE TABLE $table (str TEXT) ENGINE=INNODB");
 $sth = $dbh->prepare("INSERT INTO $table (str) VALUES (REPEAT(?,1000000))");
 foreach (1..50) {
    $sth->execute('0123456789');   # 10 MB
 }
 $dbh->do("DELETE FROM $table");

Mój sugerowany przepis:

  1. Utwórz bazę danych śmieci
  2. Zapisz powyższy skrypt perla jako junk.pl .
  3. Uruchom junk.pl data1 , junk.pl data2 , junk.pl data3 itd. Naraz , aby uruchomić tyle rdzeni procesora, ile ma serwer bazy danych. Otwieranie wielu muszle i owinąć każdy bieg w pętli bash: while true; do date; junk.pl dataX; done.

Zobacz, jak rośnie LSN, być może w innej pętli:

 silly# echo "SHOW INNODB STATUS \G" | mysql -p'xxxxxx' | grep '^Log seq'
 Log sequence number 124 3871092821
 silly# echo "SHOW INNODB STATUS \G" | mysql -p'xxxxxx' | grep '^Log seq'
 Log sequence number 124 4209892586
 silly# echo "SHOW INNODB STATUS \G" | mysql -p'xxxxxx' | grep '^Log seq'
 Log sequence number 125 85212387

Duża liczba to 32-bitowy INT bez znaku, który zawinie się przy 4 GB, zwiększając za każdym razem mniejszą liczbę. W powyższym przypadku właśnie spadła ze 124 do 125. Twój cel jest ukryty w mysqld.log, który wysłał Ci Googlinga za to śmieszne rozwiązanie. Gdy przekroczysz linię mety, to wszystko! Dmuchaj w rogi! Uwolnij konfetti!

Pasek boczny: odkrył interesujący błąd w mysqld 5.0 z / REPEAT: jeśli przejdziesz do 20 MB, odwróci on wewnętrzny licznik i przewinie do ~ 96 KB. Nigdzie nie ma ostrzeżenia ani błędu. Nie zamierzałem tracić czasu na śledzenie tego. 10 MB działa świetnie. Jeśli osiągniesz inny limit, może narzekać. Mam różne bufory innodb zwiększone z domyślnych. Dopraw do smaku. Jak zawsze obejrzyj mysqld.log w jednym oknie.

IcarusNM
źródło
Sprawdź to percona.com/blog/2013/09/11/…
Jonas Stensved
Dzięki Jonas; to interesujące. Myślę, że mogę trzymać się powyższej metody. Pokazuje użycie gdb przeciwko działającemu mysqld, którego prawdopodobnie nigdy bym nie zaryzykował. Ale tam też są dobre informacje.
IcarusNM,
Z jakiegoś dziwnego powodu, używając MariaDB, nie otrzymuję numerów sekwencji dziennika „mała liczba [spacja] duża liczba” - ale tylko „duża liczba”, więc niestety ta metoda nie zadziałała dla mnie. Oczywiście dziennik jest aktualizowany, po prostu nie wiem, kiedy przestać!
Gwyneth Llewelyn
5

Masz trzy (3) opcje:

OPCJA 01: Wykonaj rsync z Master na Slave (Przestój na Master)

  • Krok 01: Uruchom reset master; na systemie głównym (Zaps Binary Logs)
  • Krok 02: service mysql stopna kapitanie
  • Krok 03: service mysql stopna niewolniku
  • Krok 04: rsync / var / lib / mysql od master do slave
  • Krok 05: service mysql startna kapitanie
  • Krok 06: Użyj pierwszego dziennika binarnego w systemie głównym jako dziennika do rozpoczęcia replikacji. Użyj rozmiaru pliku tego dziennika jako pozycji do rozpoczęcia replikacji
  • Krok 07: service mysql stop --skip-slave-startna niewolniku
  • Krok 08: Uruchom polecenie CHANGE MASTER TO, aby skonfigurować replikację z dziennika i pozycji ustalonej z kroku 06
  • Krok 09: Uruchom start slave;na slave i pozwól replikacji nadrobić zaległości

OPCJA 02: Wykonaj rsync z Master na Slave (minimalny czas przestoju na Master)

  • Krok 01: Uruchomreset master; na systemie głównym (Zaps Binary Logs)
  • Krok 02: service mysql stopna niewolniku
  • Krok 03: rsync / var / lib / mysql od master do slave
  • Krok 04: Powtarzaj krok 03, aż dwa kolejne rsyncs zajmą tyle samo czasu
  • Krok 05: service mysql stopna kapitanie
  • Krok 06: rsync / var / lib / mysql od master do slave
  • Krok 07: service mysql startna kapitanie
  • Krok 08: Użyj pierwszego dziennika binarnego w systemie głównym jako dziennika do rozpoczęcia replikacji. Użyj rozmiaru pliku tego dziennika jako pozycji do rozpoczęcia replikacji
  • Krok 09: service mysql stop --skip-slave-start na niewolniku
  • Krok 10: Uruchom polecenie CHANGE MASTER TO, aby skonfigurować replikację z dziennika i pozycji ustalonej z kroku 08
  • Krok 11: Uruchom start slave;na slave i pozwól replikacji nadrobić zaległości

OPCJA 03: Użyj XtraBackup

To narzędzie programowe nie tylko utworzy nie rzucającą się w oczy kopię działającego wzorca, ale także utworzy odpowiednie pliki ib_log. Będziesz musiał skonfigurować replikację

Publikowałem już na StackExchange na ten temat

Robiłem te rzeczy wiele razy dla firmy hostingowej mojego pracodawcy. Jeden klient miał 3,7 TB do przeniesienia i zajęło to około 16 godzin. 64 GB jest bardzo małe w porównaniu.

RolandoMySQLDBA
źródło
W OPCJI 02 krok 05 mówisz, aby uruchomić master. Kiedy to zostało zatrzymane? Rsync na żywo na żywo jest odważny. Jestem pod wrażeniem. I na szczęście używam innodb_file_per_table. Ale w końcu musisz ugryźć kulę i zatrzymać mistrza na tyle długo, aby uruchomić ostatni rsync przed rozpoczęciem replikacji. Z tej możliwości mogę skorzystać, ale jest to bardzo aktywny DBMS. Zajrzę do XtraBackup, aby uzyskać moje informacje.
IcarusNM,
@IcarusNM: Ach, literówka. Poprawiłem to. Dziękuję Ci !!!
RolandoMySQLDBA 17.11.11
OPCJA 02 prawdopodobnie nadal wymaga trochę pracy. Np. Powinieneś zrobić krok 2 przed krokiem 1. Prawdopodobnie chcesz gdzieś tam RESETOWAĆ SLAVE. Literówka w kroku 4. I mówisz „pierwszy dziennik binarny” w kroku 5, ale tak naprawdę masz na myśli „tylko” lub „ostatni” dziennik binarny. I powinieneś użyć mysqlbinlog do ustalenia pozycji dziennika, a nie rozmiaru pliku. A wszystko to nadal nie zadziała, dopóki w pewnym momencie nie zatrzymasz mistrza. Opieranie pozycji dziennika / czasu na zakończeniu rsync jest co najwyżej ryzykowne.
IcarusNM,
Przez ostatnie 4 lata robiłem OPCJĘ 2 z klientami DB Hosting, którzy mają dane w zakresie TeraByte. Działa za każdym razem na działającym serwerze. Jedynym prawdziwym błędem, jaki możesz popełnić, jest niewolnik. Ten błąd polegałby na tym, czy replikacja została poprawnie skonfigurowana, czy nie. Ponadto RESET SLAVEjest przydatny, szczególnie jeśli zgromadziłeś wiele GB dzienników przekazywania. Po zakończeniu procesu rsync i ponownym ustanowieniu replikacji pamiętaj, że polecenie CHANGE MASTER TO usunie również dzienniki przekazywania.
RolandoMySQLDBA 17.11.11
mmm ... dziwne. skonfigurowałem mojego slave'a za pomocą xtrabackup (jak zawsze) i nadal dostaję te błędy dziennika (Percona MySQL 5.5.x) ... Wygląda na to, że coś poszło nie tak na tym slave'u i muszę to zrobić ponownie.
harald
2

Dowiedziałem się, że istnieje fajniejszy sposób na rozwiązanie tego problemu w przypadku tabel podzielonych na partycje. Musiałem usunąć partycje sprzed kilku lat i musiałem je dodać na 2014 r. Prawie wszystkie partycje zgłaszają ten błąd, więc także stare. Bardzo nieprzyjemny wypadek.

Tak więc podczas gdy DROPPING jest stary i używa REORGANIZE partycji MAXVALUE (ostatniej), utworzy nowe pliki, które są w porządku, więc otrzymuję coraz mniej ostrzeżeń. Tymczasem pomaga zwiększyć licznik sekwencji logów, więc nie muszę wstawiać fałszywych danych. To się dzieje na głównym serwerze btw ...

Więc to:

ALTER TABLE Events DROP PARTITION p1530 , p1535 , p1540 , p1545 , 
p1550, p1555 , p1560 , p1565 , p1570 , p1575 , p1580 , p1585 , p1590 , 
p1595 , p1600 , p1605 , p1610 , p1615 , p1620 , p1625 , p1630 , p1635 , 
p1640 , p1645 , p1650 , p1655 , p1660 , p1665 , p1670 , p1675 , p1680 , 
p1685 , p1690 , p1695 , p1700 , p1705 , p1710 , p1715 , p1720 , p1725 , 
p1730 , p1735 , p1740 , p1745 , p1750 , p1755 , p1760 , p1765 , p1770 , 
p1775 , p1780 , p1785 , p1790 , p1795 , p1800 , p1805 , p1810 , p1815 , 
p1820 , p1825 , p1830 , p1835 , p1840;

I to:

ALTER table Events REORGANIZE PARTITION p3000 INTO (
PARTITION p3500 VALUES LESS THAN (TO_DAYS('2013-01-01')),
PARTITION p3510 VALUES LESS THAN (TO_DAYS('2013-01-04')),
PARTITION p3520 VALUES LESS THAN (TO_DAYS('2013-01-07')),
PARTITION p3530 VALUES LESS THAN (TO_DAYS('2013-01-10'))
...
PARTITION p4740 VALUES LESS THAN (TO_DAYS('2014-01-08')),
PARTITION p9000 VALUES LESS THAN MAXVALUE)

To skutecznie usunie każdą partycję ze zmiany i odtworzy ją z tymczasową kopią zawartości tego, co tam było. Możesz to zrobić według tabeli, jeśli chcesz, moja aplikacja na to pozwala, więc nie musisz się martwić o zsynchronizowane kopie zapasowe itp.

Teraz do końca tabeli, ponieważ nie dotknąłem wszystkich partycji w tym procesie, niektóre zostaną z ostrzeżeniem o sekwencji dziennika, dla tych, które są uszkodzone, ale objęte tą reorganizacją, prawdopodobnie uruchomię to:

ALTER TABLE Events REBUILD PARTITION p0, p1;

albo to

ALTER TABLE Events OPTIMIZE PARTITION p0, p1;

Pomyślałem, że możesz to zrobić przy użyciu zwykłych tabel waniliowych, tymczasowo dodawać partycje za pomocą skrótu, a później je usuwać (lub zachować je, zdecydowanie zalecam partycje).

Używam jednak mariadb, nie mysql (więc XtraDB)

Być może to pomaga komuś. Nadal go uruchamiam, jak dotąd tak dobrze. Wydaje się, że zmiana SILNIKA również wykonuje tę pracę, więc przenoszę ją między MyIsam a nimi z powrotem do InnoDB.

Jest to dość logiczne, jeśli zmienisz SILNIK, tabela zniknie z innodb, więc nie będzie już problemem.

ALTER TABLE Events ENGINE=MyISAM;
ALTER TABLE Events ENGINE=InnoDB;

wydaje się, że tutaj działa. Mogę potwierdzić kilka rzeczy na partycjonowanych tabelach:

  • ALTER TABLE xyz ENGINE = InnoDB jest bardzo wolny, do Arii (mariadb) dwa razy szybszy, ale ogólnie powolny sposób na zwiększenie licznika sekwencji logów
  • ALTER TABLE xyz REBUILD PARTITION ALL to najszybszy sposób na „naprawienie” tabel i pomoc w zwiększeniu licznika
  • ALTER TABLE xyz ANALYZE PARTITION ALL jest powolny w porównaniu do poprzedniej i nie przepisuje partycji, które sprawdzają się poprawnie. REBUILD zapewnia przepisanie schematu tabeli tymczasowej.

Użyłem ostatnich na kilku stołach. Ostrzeżenia pojawiają się, gdy próbuje otworzyć pliki i jest jeden dla każdej definicji partycji, którą otwiera z problemami z licznikami. Prawie przewrócił się dzisiaj na ladzie dla ostatnich stołów. Myślę, że kiedy wszystko zostanie przetworzone, trzeba opróżnić dzienniki binarne.

aktualizacja : Mogę podsumować kilka rzeczy, teraz udało mi się rozwiązać ten problem.

  • Moja awaria została spowodowana reorganizacją partycji na stole w formacie Aria (MariaDB).
  • (dla mnie) przebudowa partycji działała najlepiej i najszybciej, aby uzyskać wyrównanie sekwencji. Zmiana silnika jest wolna i musisz zrobić to dwa razy, aby wpłynąć na innodb. zmiana na innoDB jest dość wolna w porównaniu do MyIsam lub Aria.
  • Uaktualniłem do MariaDB 5.3, a nie do 5.5 (było: 5.2) i działa dobrze. Myślę, że jest zbyt wiele problemów z arią, partycjami w 5.5 (i potwierdzonymi błędami), aby używać tej kombinacji.
  • Naprawdę powinien istnieć lepszy sposób na zresetowanie licznika sekwencji dziennika.
Glenn Plas
źródło
W MariaDB możesz szybko zmieniać wszystkie tabele, używając USE INFORMATION_SCHEMA; SELECT CONCAT("ALTER TABLE `", TABLE_SCHEMA,"`.`", TABLE_NAME, "` REBUILD PARTITION ALL;") AS MySQLCMD AS MySQLCMD FROM TABLES;(źródło: dba.stackexchange.com/questions/35073/... ) i przekształcić go w plik, który ma zostać wykonany jako seria poleceń.
Gwyneth Llewelyn