Replikacja w MySQL istnieje od dłuższego czasu i przez lata stale się poprawiała. To bardziej przypominało ewolucję niż rewolucję. Jest to całkowicie zrozumiałe, ponieważ replikacja jest ważną funkcją, od której zależy wiele osób — musi działać.
W ostatnich wersjach MySQL zaobserwowaliśmy poprawę wydajności replikacji dzięki obsłudze równoległego stosowania transakcji. W MySQL 5.6 zrównoleglenie odbywało się na poziomie schematu - wszystkie transakcje, które zostały wykonane w osobnych schematach, mogły zostać wykonane jednocześnie. Było to dobre ulepszenie w przypadku obciążeń, które miały wiele schematów na jednym serwerze, a obciążenie było mniej więcej równomiernie rozłożone na schematy.
W MySQL 5.7 dodano kolejną metodę zrównoleglania, tzw. „logiczny zegar”. Pozwoliło to uzyskać pewien poziom współbieżności na urządzeniu podrzędnym, nawet jeśli wszystkie dane zostały zapisane w jednym schemacie. Krótko mówiąc, opierało się to na fakcie, że niektóre transakcje były realizowane razem z powodu opóźnienia dodanego przez sprzęt. Możesz nawet dodać to opóźnienie ręcznie, aby uzyskać lepszą równoległość na urządzeniach podrzędnych za pomocą binlog_group_commit_sync_delay.
To rozwiązanie było naprawdę fajne, ale nie pozbawione wad. Każde opóźnienie w zatwierdzeniu transakcji może ostatecznie wpłynąć na części aplikacji dostępne dla użytkownika. Jasne, możesz ustawić opóźnienia w zakresie kilku milisekund, ale nawet wtedy jest to dodatkowe opóźnienie, które spowalnia aplikację.
Ulepszenia wydajności replikacji w MySQL 8.0
MySQL 8.0, który na razie (sierpień 2017) jest nadal w stanie beta, wprowadza kilka ciekawych ulepszeń do replikacji. Pierwotnie został opracowany dla replikacji grupowej (GR), ale ponieważ GR używa pod maską regularnej replikacji, skorzystała z niej „normalna” replikacja MySQL. Wspomniane ulepszenie to informacje o śledzeniu zależności przechowywane w dzienniku binarnym. To, co się dzieje, to fakt, że MySQL 8.0 ma teraz sposób na przechowywanie informacji o tym, które wiersze zostały dotknięte daną transakcją (tzw. writeset) i porównuje zapisy z różnych transakcji. Umożliwia to identyfikację tych transakcji, które nie działały na tym samym podzbiorze wierszy, a zatem mogą być stosowane równolegle. Może to pozwolić na kilkukrotne zwiększenie poziomu zrównoleglania w porównaniu do implementacji z MySQL 5.7. Musisz pamiętać, że w końcu niewolnik zobaczy dane w innym widoku, który nigdy nie pojawił się na urządzeniu głównym. Dzieje się tak, ponieważ transakcje mogą być stosowane w innej kolejności niż na wzorcu. Nie powinno to jednak stanowić problemu. Obecna implementacja replikacji wielowątkowej w MySQL 5.7 może również powodować ten problem, chyba że jawnie włączysz polecenie slave-preserve-commit-order.
Aby kontrolować to nowe zachowanie, zmienna binlog_transaction_dependency_tracking został wprowadzony. Może przyjąć trzy wartości:
- COMMIT_ORDER:to jest domyślne, używa domyślnego mechanizmu dostępnego w MySQL 5.7.
- WRITESET:Umożliwia lepszą równoległość, a urządzenie główne zaczyna przechowywać dane zestawu zapisów w dzienniku binarnym.
- WRITESET_SESSION:Zapewnia to, że transakcje będą wykonywane na urządzeniu podrzędnym w kolejności, a problem z urządzeniem podrzędnym, które widzi stan bazy danych, którego nigdy nie widziano na urządzeniu głównym, zostanie wyeliminowany. Zmniejsza równoległość, ale nadal może zapewnić lepszą przepustowość niż ustawienia domyślne.
Wzorzec
W lipcu na mysqlhighavailability.com Vitor Oliveira napisał post, w którym próbował zmierzyć wydajność nowych trybów. Wykorzystał najlepszy scenariusz - brak jakiejkolwiek trwałości, aby pokazać różnicę między starymi a nowymi trybami. Zdecydowaliśmy się zastosować to samo podejście, tym razem w konfiguracji bardziej rzeczywistej:log_binarny włączony z log_slave_updates. Ustawienia trwałości pozostawiono do wartości domyślnych (więc sync_binlog=1 - to nowe ustawienie domyślne w MySQL 8.0, włączony bufor podwójnego zapisu, włączone sumy kontrolne InnoDB itp.) Jedynym wyjątkiem pod względem trwałości był parametr innodb_flush_log_at_trx_commit ustawiony na 2.
Użyliśmy instancji m4.2xl, 32G, 8 rdzeni (więc slave_parallel_workers było ustawione na 8). Użyliśmy również skryptu sysbench, oltp_read_write.lua. 16 milionów wierszy w 32 tabelach było przechowywanych na woluminie gp2 o pojemności 1000 GB (czyli 3000 IOPS). Przetestowaliśmy wydajność wszystkich trybów dla 1, 2, 4, 8, 16 i 32 równoczesnych połączeń sysbench. Proces wyglądał następująco:zatrzymaj urządzenie podrzędne, wykonaj 100 000 transakcji, uruchom urządzenie podrzędne i oblicz, ile czasu zajmie usunięcie opóźnienia podrzędnego.
Po pierwsze, tak naprawdę nie wiemy, co się stało, gdy sysbench został uruchomiony przy użyciu tylko 1 wątku. Każdy test wykonywano pięć razy po rozgrzewce. Ta konkretna konfiguracja została przetestowana dwa razy - wyniki są stabilne:obciążenie jednowątkowe było najszybsze. Przyjrzymy się temu dokładniej, aby zrozumieć, co się stało.
Poza tym pozostałe wyniki są zgodne z naszymi oczekiwaniami. COMMIT_ORDER jest najwolniejszy, szczególnie dla małego ruchu, 2-8 wątków. WRITESET_SESSION działa zazwyczaj lepiej niż COMMIT_ORDER, ale jest wolniejszy niż WRITESET w przypadku niskiego ruchu współbieżnego.
Jak może mi pomóc?
Pierwsza zaleta jest oczywista:jeśli twoje obciążenie pracą jest powolne, ale twoje serwery podrzędne mają tendencję do cofania się w replikacji, mogą skorzystać na zwiększonej wydajności replikacji, gdy tylko master zostanie uaktualniony do wersji 8.0. Tutaj dwie uwagi:po pierwsze - ta funkcja jest wstecznie kompatybilna i mogą z niej korzystać także niewolnicy 5.7. Po drugie - przypomnienie, że wersja 8.0 jest jeszcze w fazie beta, nie zachęcamy do korzystania z oprogramowania beta na produkcji, chociaż w pilnej potrzebie jest to opcja do przetestowania. Ta funkcja może ci pomóc nie tylko wtedy, gdy twoi niewolnicy są w tyle. Mogą być w pełni nadrobieni, ale kiedy utworzysz nowego niewolnika lub przywrócisz istniejącego, ten niewolnik będzie w tyle. Możliwość korzystania z trybu „WRITESET” znacznie przyspieszy proces udostępniania nowego hosta.
Podsumowując, ta funkcja będzie miała znacznie większy wpływ, niż mogłoby się wydawać. Biorąc pod uwagę wszystkie testy porównawcze pokazujące regresję wydajności, gdy MySQL obsługuje ruch o niskiej współbieżności, wszystko, co może pomóc przyspieszyć replikację w takich środowiskach, jest ogromną poprawą.
Jeśli używasz średniozaawansowanych mistrzów, jest to również funkcja, której należy szukać. Każdy pośredniczący wzorzec dodaje pewną serializację do sposobu obsługi i wykonywania transakcji — w świecie rzeczywistym obciążenie pośredniego wzorca będzie prawie zawsze mniej równoległe niż na wzorcu. Wykorzystanie zestawów zapisu w celu umożliwienia lepszej równoległości nie tylko poprawia zrównoleglenie na pośrednim masterze, ale może również poprawić zrównoleglenie na wszystkich jego urządzeniach podrzędnych. Jest nawet możliwe (chociaż wymagałoby to poważnych testów, aby sprawdzić, czy wszystkie elementy będą pasować prawidłowo) użyć pośredniego mastera 8.0 w celu poprawy wydajności replikacji twoich slave'ów (proszę pamiętać, że slave MySQL 5.7 potrafi zrozumieć dane zbioru zapisu i używać go, nawet jeśli nie może go samodzielnie wygenerować). Oczywiście replikacja z wersji 8.0 do 5.7 brzmi dość skomplikowanie (i to nie tylko dlatego, że wersja 8.0 to wciąż wersja beta). W pewnych okolicznościach może to działać i może przyspieszyć wykorzystanie procesora na twoich urządzeniach podrzędnych 5.7.
Inne zmiany w replikacji MySQL
Wprowadzenie zbiorów zapisu, choć jest to najciekawsze, nie jest jedyną zmianą, jaka zaszła w replikacji MySQL w MySQL 8.0. Przejdźmy przez kilka innych, również ważnych zmian. Jeśli zdarzy ci się użyć mastera starszego niż MySQL 5.0, 8.0 nie będzie obsługiwał formatu dziennika binarnego. Nie spodziewamy się wielu takich konfiguracji, ale jeśli używasz bardzo starego MySQL z replikacją, zdecydowanie nadszedł czas na aktualizację.
Zmieniono wartości domyślne, aby zapewnić możliwie największą bezpieczną replikację:master_info_repository i relay_log_info_repository są ustawione na TABELA. Expire_log_days również został zmieniony - teraz domyślna wartość to 30. Oprócz expire_log_days , dodano nową zmienną, binlog_expire_log_seconds , co pozwala na bardziej szczegółową politykę rotacji dzienników binarnych. Do dziennika binarnego dodano kilka dodatkowych znaczników czasu, aby poprawić obserwowalność opóźnienia replikacji, wprowadzając mikrosekundową ziarnistość.
Oczywiście nie jest to pełna lista zmian i funkcji związanych z replikacją MySQL. Jeśli chcesz dowiedzieć się więcej, możesz sprawdzić dzienniki zmian MySQL. Upewnij się, że sprawdziłeś je wszystkie – do tej pory funkcje zostały dodane we wszystkich wersjach 8.0.
Jak widać, replikacja MySQL wciąż się zmienia i staje się coraz lepsza. Jak powiedzieliśmy na początku, musi to być powolny proces, ale naprawdę wspaniale jest zobaczyć, co nas czeka. Miło jest również zobaczyć, jak praca nad replikacją grupową spływa i jest ponownie wykorzystywana w „zwykłej” replikacji MySQL.