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 WHERE
klauzuli 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.
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.
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.
To jest to samo, co w rzeczywistości # 2.
źródło
Kilka nowych projektów w tej przestrzeni:
github.com/twitter/gizzard/źródło
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).
źródło
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".
źródło
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:
źródło
PARTITION BY HASH(YEAR...)
przeskanuje wszystkie partycje, jeśli masz zakres dat. Fuj.