Jak mogę skonfigurować MySQL Innodb do obsługi 1000 wstawek na godzinę?

10

Mam bardzo ruchliwą stronę internetową, na której co godzinę można wstawić tysiące nowych rekordów.

Ten jeden błąd paraliżuje witrynę:

PDOException: SQLSTATE[40001]: Serialization failure: 1213 
Deadlock found when trying to get lock; 
try restarting transaction: INSERT INTO {location_instance} 
(nid, vid, uid, genid, lid) VALUES (:db_insert_placeholder_0, 
:db_insert_placeholder_1, :db_insert_placeholder_2, 
:db_insert_placeholder_3, :db_insert_placeholder_4); 
Array ( [:db_insert_placeholder_0] => 1059 [:db_insert_placeholder_1] => 
1059 [:db_insert_placeholder_2] => 0 [:db_insert_placeholder_3] => 
cck:field_item_location:1059 [:db_insert_placeholder_4] => 1000 )

Byłbym bardzo zaskoczony, gdyby MySQL nie mógł poradzić sobie z tego typu obciążeniem. Zatem moje pytania brzmią: czy jest to problem z bazą danych i jak mogę skonfigurować MySQL, aby mógł obsługiwać tak duży ruch?

Mam kopię mojej witryny skonfigurowaną na serwerze programistycznym ze skryptami symulującymi obciążenie treści dodawanej do witryny. Korzystam z Ubuntu, stosu LAMP, z 16 GB pamięci RAM.

Trzeba przyznać, że nie mam zbyt dużej wiedzy na temat baz danych. W rzeczywistości zaczynam od domyślnego pliku my.cnf, który jest dołączany po zakończeniu instalacji „apt-get install”. Wszystkie tabele są Innodb. Jakie początkowe ustawienia konfiguracji i podejście poleciłbyś rozpocząć, aby rozwiązać ten problem?

Daj mi znać, jakich dodatkowych informacji możesz potrzebować.

Dzięki

użytkownik658182
źródło
Zaczynasz z domyślnym plikiem my.cnf do produkcji? Człowieku, musisz to bardziej zoptymalizować. Więcej szczegółów w mojej odpowiedzi. :-)

Odpowiedzi:

11

Masz do czynienia z impasem, a nie problemem wąskiego gardła w zakresie wydajności.

Jeśli masz tysiąc nowych rekordów na godzinę, jesteś daleko od osiągnięcia limitów MySQL. MySQL może obsłużyć co najmniej 50 razy ładunek.

Zakleszczenia są powodowane przez kod aplikacji i nie są winą serwera bazy danych. Zakleszczeń nie można naprawić po stronie serwera MySQL, z wyjątkiem niektórych szczególnych sytuacji.

InnoDBmoże wyświetlić szczegółowe informacje o zakleszczeniu, uruchamiając SHOW ENGINE INNODB STATUSpo znaku zachęty MySQL lub za pomocą mysql -uroot -p... -e "SHOW ENGINE INNODB STATUS".

Jednak pokazuje to tylko ostatni zakleszczenie, które wystąpiło, nie ma dziennika zakleszczenia.

Na szczęście istnieje narzędzie pt-deadlock-logger, które zajmuje się tym problemem, dba o InnoDBstatus odpytywania i zapisuje wszystkie szczegółowe informacje o zakleszczeniu, zanim zostanie odświeżone z nowym impasem.

Dzielność
źródło
Dobrze wiedzieć! Widzę w poleceniu show status informacje na temat blokady oraz powiązane zapytanie i tabelę. Biorąc pod uwagę, że jest to w moim kodzie, jak mogę użyć tych informacji z polecenia status, aby rozpocząć debugowanie problemu? Zapytanie PDO PHP jest dość proste - podłącz, przygotuj, uruchom, powtórz. Z przyjemnością opublikuję dowolny kod lub komunikat o stanie, jeśli to pomoże.
user658182
@ user658182 sprawdź ten post na przepełnieniu stosu, jak radzić sobie z zakleszczeniami: jak uniknąć zakleszczenia mysql podczas próby uzyskania blokady
Valor
1
@ max-vernon dzięki za edycję składni, wyraźnie angielski to nie jest mój język ojczysty :-).
Valor
1
-e „POKAŻ STATUS INNODBU SILNIKA”
glif
8

Może to być tak proste, jak jedna część kodu prowadząca transakcję:

insert into t1...
insert into t2...
commit;

podczas gdy inna część kodu modyfikuje te same tabele w innej kolejności:

delete from t2 where...
delete from t1 where...
commit;

Jeśli obie transakcje przebiegają w tym samym czasie, może wystąpić wyścig: pierwsza transakcja nie może zostać zmodyfikowana, t2ponieważ jest zablokowana przez drugą transakcję; podczas gdy druga transakcja jest podobnie blokowana, ponieważ t1jest blokowana przez pierwszą transakcję. MySQL wybiera jedną transakcję jako „ofiarę”, w przypadku której INSERT / UPDATE / DELETE kończy się niepowodzeniem. Aplikacja musi wychwycić ten błąd i ponowić instrukcję - może po przerwie, aby druga transakcja miała czas na zakończenie. Nie ma to nic wspólnego z ograniczeniami pojemności, po prostu niefortunne taktowanie, które może być zaostrzone przez sposób ułożenia kodu. Przełączaj DELETE w transakcji nr 2 lub INSERT w transakcji nr 1, a wtedy nie będzie konfliktu - każda transakcja będzie oczekiwać na dostęp do potrzebnych tabel.

W MySQL 5.6 można uruchomić z włączoną opcją innodb_print_all_deadlocks , aby zbierać informacje o wszystkich zakleszczeniach (nie tylko ostatnich) w dzienniku błędów MySQL.

[Obowiązkowe zastrzeżenie: Jestem pracownikiem Oracle. Powyższe jest moim osobistym poglądem, a nie oficjalnym oświadczeniem.]

Max Webster
źródło