Podejścia do shardingu MySQL?


88

Jakie jest najlepsze podejście do dzielenia tabel MySQL na fragmenty. Podejścia, które przychodzą mi do głowy, to:

  1. Fragmentowanie na poziomie aplikacji?
  2. Sharding w warstwie proxy MySQL?
  3. Centralny serwer wyszukiwania do dzielenia na fragmenty?

Czy znasz jakieś ciekawe projekty lub narzędzia w tej dziedzinie?

Odpowiedzi:


116

Najlepszym podejściem do dzielenia tabel MySQL na fragmenty jest nie robienie tego, chyba że jest to całkowicie nieuniknione.

Kiedy piszesz aplikację, zwykle chcesz to zrobić w sposób, który maksymalizuje szybkość i szybkość programisty. Optymalizujesz pod kątem opóźnienia (czas do uzyskania odpowiedzi) lub przepustowości (liczba odpowiedzi na jednostkę czasu) tylko wtedy, gdy jest to konieczne.

Partycjonujesz, a następnie przypisujesz partycje do różnych hostów (= fragmentów) tylko wtedy, gdy suma wszystkich tych partycji nie mieści się już w jednej instancji serwera bazy danych - powodem tego jest albo zapis, albo odczyt.

Przypadek zapisu jest następujący: a) częstotliwość zapisów powoduje trwałe przeciążenie dysków tego serwera lub b) jest wykonywanych zbyt wiele zapisów, co powoduje trwałe opóźnienia replikacji w tej hierarchii replikacji.

Przykładem odczytu dla shardingu jest sytuacja, w której rozmiar danych jest tak duży, że ich zestaw roboczy nie mieści się już w pamięci, a odczyty danych zaczynają trafiać na dysk, zamiast być przez większość czasu obsługiwane z pamięci.

Tylko wtedy, gdy mają do shard to zrobić.


W chwili, gdy odłamki, płacisz za to na wiele sposobów:

Znaczna część twojego SQL nie jest już deklaratywna.

Zwykle w języku SQL mówisz bazie danych, jakie dane chcesz i pozostawiasz optymalizatorowi, aby przekształcił tę specyfikację w program dostępu do danych. To dobrze, ponieważ jest elastyczny, a pisanie takich programów dostępu do danych jest nudną pracą, która szkodzi szybkości.

W środowisku podzielonym na fragmenty prawdopodobnie łączysz tabelę w węźle A z danymi w węźle B lub masz tabelę większą niż węzeł w węzłach A i B i łączysz dane z niej z danymi znajdującymi się w węźle B i C. Zaczynasz ręcznie pisać rozwiązania złączeń oparte na skrótach po stronie aplikacji, aby rozwiązać ten problem (lub wymyślasz na nowo klaster MySQL), co oznacza, że ​​otrzymujesz dużo SQL, które nie są już deklaratywne, ale wyrażają funkcjonalność SQL w sposób proceduralny (np. używasz instrukcji SELECT w pętlach).

Występują duże opóźnienia w sieci.

Zwykle zapytanie SQL można rozwiązać lokalnie, a optymalizator wie o kosztach związanych z dostępem do dysku lokalnego i rozwiązuje zapytanie w sposób minimalizujący związane z tym koszty.

W środowisku podzielonym na fragmenty zapytania są rozwiązywane przez uruchamianie dostępu klucz-wartość w sieci do wielu węzłów (miejmy nadzieję, że w przypadku dostępu do kluczy wsadowych, a nie wyszukiwania pojedynczych kluczy w obie strony) lub przez wypychanie części WHEREklauzuli dalej do węzłów, gdzie mogą zastosować (to jest nazywane „przesunięciem warunku”), lub oba.

Ale nawet w najlepszych przypadkach wiąże się to z większą liczbą połączeń sieciowych w obie strony niż sytuacja lokalna i jest to bardziej skomplikowane. Zwłaszcza, że ​​optymalizator MySQL nie wie w ogóle nic o opóźnieniach w sieci (Ok, klaster MySQL powoli się w tym poprawia, ale dla zwykłego MySQL poza klastrem jest to nadal prawda).

Tracisz dużo możliwości ekspresji SQL.

Ok, to prawdopodobnie mniej ważne, ale ograniczenia klucza obcego i inne mechanizmy SQL zapewniające integralność danych nie są w stanie objąć wielu fragmentów.

MySQL nie ma API, które pozwala na asynchroniczne zapytania, które są sprawne.

Gdy dane tego samego typu znajdują się w wielu węzłach (np. Dane użytkownika w węzłach A, B i C), zapytania poziome często muszą być rozwiązywane w odniesieniu do wszystkich tych węzłów („Znajdź wszystkie konta użytkowników, które nie były zalogowane od 90 dni albo więcej"). Czas dostępu do danych rośnie liniowo wraz z liczbą węzłów, chyba że można zapytać o wiele węzłów równolegle, a wyniki są agregowane w miarę ich pojawiania się („Map-Reduce”).

Warunkiem wstępnym jest asynchroniczny interfejs komunikacyjny API, który nie istnieje dla MySQL w dobrym stanie. Alternatywą jest dużo rozwidleń i połączeń w procesach potomnych, czyli odwiedzanie świata ssania na przepustce sezonowej.


Po rozpoczęciu fragmentowania struktura danych i topologia sieci stają się widoczne jako punkty wydajności aplikacji. Aby aplikacja działała w miarę dobrze, musi być tego świadoma, a to oznacza, że ​​tak naprawdę tylko fragmentowanie na poziomie aplikacji ma sens.

Pytanie brzmi bardziej, jeśli chcesz automatycznie shardować (na przykład określić, który wiersz trafia do którego węzła, np. Przez haszowanie kluczy podstawowych) lub jeśli chcesz podzielić funkcjonalnie w sposób ręczny („Tabele powiązane z historią użytkownika xyz idą do tego master, podczas gdy tabele związane z abc i def idą do tego mastera ”).

Funkcjonalne fragmentowanie ma tę zaletę, że jeśli zostanie wykonane prawidłowo, przez większość czasu jest niewidoczne dla większości programistów, ponieważ wszystkie tabele związane z ich historią użytkownika będą dostępne lokalnie. To pozwala im jak najdłużej korzystać z deklaratywnego SQL, a także spowoduje mniejsze opóźnienia w sieci, ponieważ liczba transferów między sieciami jest minimalna.

Funkcjonalne fragmentowanie ma tę wadę, że nie pozwala na to, aby żadna pojedyncza tabela była większa niż jedna instancja i wymaga ręcznej uwagi projektanta.

Funkcjonalne fragmentowanie ma tę zaletę, że jest stosunkowo łatwe do wykonania w istniejącej bazie kodu z kilkoma zmianami, które nie są zbyt duże. Witryna http://Booking.com robiła to wiele razy w ciągu ostatnich lat i działała dobrze.


Powiedziawszy to wszystko, patrząc na twoje pytanie, wydaje mi się, że zadajesz niewłaściwe pytania lub całkowicie nie rozumiem twojego stwierdzenia problemu.


2
To jest dobra odpowiedź. Chcę jednak zwrócić uwagę, że fragmentowanie jest naprawdę potrzebne tylko w przypadku aplikacji o dużej objętości i istnieje prawdopodobieństwo, że generują one pewien dochód. Zewnętrzna aplikacja dzieląca na fragmenty poradzi sobie ze wszystkimi problemami związanymi z łączeniami, transakcjami typu cross-shard itp. A jeśli uzyskasz dobrą, zachowa integralność „relacyjnej” bazy danych. Inne aplikacje, masz rację, po prostu zmienią twoją bazę danych w parę klucz-wartość, a tym samym pokonają cel SQL.
chantheman

3
Nie spotkałem jeszcze aplikacji dzielącej się na fragmenty, komercyjnej lub nie, która skutecznie ukrywa fakt, że dane są teraz rozproszone w sieci i podlegają opóźnieniom lub niespójności z powodu braku oczekiwania wywołanego opóźnieniem. Jeśli dzielisz na fragmenty, aplikacja zauważy i będzie wymagać zmian. Równie dobrze możesz mieć nad tym kontrolę. Nie ma srebrnej kuli, ale jest dużo oleju wężowego.
Isotopp

1
Powinieneś sprawdzić dbShards. Skaluje się lepiej niż liniowo na liczbę dodanych „fragmentów”. Będziesz potrzebował bardzo niewielkich, jeśli w ogóle, zmian po stronie aplikacji i tak, Twoja aplikacja nie zna różnicy. Po prostu wysyła i odbiera transakcje tak samo, jak w przypadku ODBC lub JDBC. dbShards umożliwia również wskazówki dotyczące fragmentów, jeśli chcesz mieć większą kontrolę nad transakcją. Możesz dokładnie powiedzieć dbShards, z jakiego fragmentu chcesz pisać lub czytać.
chantheman

1
@Gigala no cóż, spędzanie czasu na komponowaniu tak dobrze zdefiniowanej odpowiedzi, niezależnie od jej szerokości, też nie jest konieczne, ale cieszę się, że tak się stało, bo ta odpowiedź okazała się dla mnie pomocna. Nie zniechęcaj użytkowników, aby nie „myśleli nieszablonowo” podczas udzielania odpowiedzi.
mewm

12
  1. Fragmenty na poziomie aplikacji: dbShards to jedyny znany mi produkt, który obsługuje fragmenty na poziomie aplikacji. Na stronie jest kilka dobrych artykułów. Z definicji fragmentowanie uwzględniające aplikacje będzie bardziej wydajne. Jeśli aplikacja dokładnie wie, gdzie iść z transakcją, bez konieczności jej wyszukiwania lub przekierowywania przez serwer proxy, sama w sobie będzie szybsza. Szybkość jest często jednym z głównych problemów, jeśli nie jedynym problemem, gdy ktoś szuka fragmentów.

  2. Niektórzy ludzie „shardują” za pomocą proxy, ale moim zdaniem jest to sprzeczne z celem shardingu. Używasz tylko innego serwera do informowania transakcji, gdzie znaleźć dane lub gdzie je przechowywać. Dzięki fragmentacji uwzględniającej aplikacje Twoja aplikacja sama wie, dokąd się udać. Dużo bardziej wydajne.

  3. To jest to samo, co w rzeczywistości # 2.


gdzie gdzieś używane są dbShardy w produkcji? również nie jest to oprogramowanie typu open source.
sheki

Również podejście 2 i 3 może być inne, jeśli serwer proxy wyszukuje na podstawie skrótu zamiast bazy danych lub magazynu.
sheki

1
dbShards jest w produkcji z różnymi klientami, ale nie, nie jest to oprogramowanie typu open source. Myślę, że nie znajdziesz dobrego produktu do dzielenia na fragmenty oprogramowania typu open source. I tak, masz rację, że hash może być użyty do wyszukiwania, ale w takim przypadku nadal musisz zrobić jeszcze jedno „zatrzymanie”, aby przenieść transakcję do bazy danych. Dlatego sharding „świadomy aplikacji” prawie zawsze będzie szybszy.
chantheman,

Ale tak jak powiedziałem, jeśli możesz uzyskać aplikację dzielącą na fragmenty, która utrzymuje integralność relacji, będziesz w dobrej formie. Wspominam o dbShardach, ponieważ jest to jedyny, o którym wiem, że tak. A skoro tak, to skaluje prędkość zapisu i odczytu liniowo. Dodajesz 4 „shardy” lub dzielisz jeden serwer MySQL na 4 i będzie on działał 4 razy szybciej.
chantheman

7

Czy znasz jakieś ciekawe projekty lub narzędzia w tej dziedzinie?

Kilka nowych projektów w tej przestrzeni:

  • citusdata.com
  • spockproxy.sourceforge.net
  • github.com/twitter/gizzard/

5

Zapytanie odłamkowe to oparte na OLAP rozwiązanie do dzielenia na fragmenty dla MySQL. Umożliwia zdefiniowanie kombinacji tabel podzielonych na fragmenty i tabel nie podzielonych na fragmenty. Tabele nie podzielone na fragmenty (takie jak tabele odnośników) można dowolnie łączyć z tabelami podzielonymi na fragmenty, a tabele podzielone na fragmenty można łączyć ze sobą, o ile tabele są połączone kluczem fragmentu (bez fragmentu krzyżowego lub łączeń własnych, które przekraczają granice fragmentu). Będąc rozwiązaniem OLAP, Shard-Query zwykle ma minimalny czas odpowiedzi wynoszący 100 ms lub mniej, nawet w przypadku prostych zapytań, więc nie będzie działać w przypadku OLTP. Shard-Query jest przeznaczony do równoległego analizowania dużych zbiorów danych.

Istnieją również rozwiązania do dzielenia na fragmenty OLTP dla MySQL. Zamknięte rozwiązania źródłowe obejmują ScaleDB , DBShards . Rozwiązanie OLTP typu open source obejmuje JetPants , Cubrid lub Flock / Gizzard (infrastruktura Twittera).


3

Poziom aplikacji oczywiście.

Najlepsze podejście, jakie kiedykolwiek znalazłem w tej książce

Wysoka wydajność MySQL http://www.amazon.com/High-Performance-MySQL-Jeremy-Zawodny/dp/0596003064

Krótki opis: możesz podzielić swoje dane na wiele części i przechowywać około 50 części na każdym serwerze. Pomoże ci to uniknąć drugiego największego problemu związanego z shardowaniem - przywrócenia równowagi. Po prostu przenieś część z nich na nowy serwer i wszystko będzie dobrze :)

Gorąco polecam zakup go i przeczytanie części "Skalowanie mysql".


Książka, którą poleciłeś, ma 8 lat… czy obejmuje fragmenty związane z dzisiejszymi technologiami?
rafian

1
Opisuje kilka podstawowych podejść do skalowania mysql. AFAIK nic się nie zmieniło w skalowaniu mysql. Te same techniki fragmentowania i replikacji na poziomie aplikacji są obecnie szeroko stosowane.
Andrey Frolov

Mogę się mylić, ale przeprowadziłem mnóstwo badań na ten temat w ciągu ostatniego tygodnia i wygląda na to, że sam mySQL wprowadził wiele zmian w ciągu ostatnich 8 lat, szczególnie w zakresie partycjonowania i buforowania. W tym roku pojawiła się nowa wersja: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/… Nie czytałem tego, ale myślę, że obejmuje nowe dostępne modele replikacji.
NateDSaint

4
Książki… dlaczego nie wyjaśnić tego tutaj.
DDD

2

Wydaje się, że od 2018 roku istnieje natywne rozwiązanie MySql. Tak naprawdę jest co najmniej 2 - klaster InnoDB i klaster NDB (istnieje wersja komercyjna i społecznościowa).

Ponieważ większość osób korzystających z wersji społecznościowej MySql jest lepiej zaznajomiona z silnikiem InnoDB, należy to zbadać w pierwszej kolejności. Obsługuje replikację i partycjonowanie / fragmentowanie po wyjęciu z pudełka i jest oparty na routerze MySql dla różnych opcji routingu / równoważenia obciążenia.

Składnia tworzenia tabel wymagałaby zmiany, na przykład:

    CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATETIME) PARTITION BY HASH ( YEAR(col3) );

(to tylko jeden z czterech typów partycjonowania )

Jedno bardzo ważne ograniczenie:

Klucze obce InnoDB i partycjonowanie MySQL nie są kompatybilne. Tabele InnoDB podzielone na partycje nie mogą zawierać odwołań do kluczy obcych ani kolumn, do których odwołują się klucze obce. Tabele InnoDB, które mają klucze obce lub do których się odwołują, nie mogą być partycjonowane.


Pamiętaj, że PARTITION BY HASH(YEAR...)przeskanuje wszystkie partycje, jeśli masz zakres dat. Fuj.
Rick James
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.