Partycjonowanie bazy danych okładka

Partycjonowanie bazy danych

Partycjonowanie to jedna ze strategii rozproszenia danych. Polega ona na podziale zbioru danych na wiele maszyn. W odróżnieniu od replikacji partycjonowanie zakłada tylko jedną kopię danych, to znaczy, że dany wpis (wiersz / dokument) będzie tylko na jednym serwerze. Oczywiście replikacja i partycjonowanie idą w parze dla podniesienia dostępności i przepustowości bazy danych. Więcej o replikacji pisałem tutaj

W tym artykule dowiesz się, jakie są strategie partycjonowania, co może pójść nie tak oraz czym jest repartycjonowanie i kiedy trzeba przeprowadzać ten zabieg. Przed Tobą — jako konsumenta bazy czy projektanta aplikacji — mechanika tych zabiegów jest  ukryta przez silnik bazodanowy. Musisz natomiast wiedzieć, jakie są konsekwencje i zalety używania partycji, jeśli chcesz wykorzystać ich potencjał.

Wiele imion, jedno znaczenie

Wyżej opisana definicja ma wiele etykiet, jedną z nich jest „partycja” oraz równie powszechna shard. Możesz spotkać więcej synonimów w zależności od tego, z jaką bazą danych będziesz pracował, zawsze natomiast chodzi o to samo – rozprowadzenie danych na wiele maszyn. 

Synonim partycjiBaza danych
shardMongoDB, Elasticsearch, SolrCloud
regionHBase
tabletBigTable
vnodeCassandra, Riak
vBucketCouchbase

Jakie są cele partycjonowania?

Kiedy podzielisz zbiór danych (na przykład tabelę w relacyjnej bazie) na kilka serwerów, to zwiększysz jej moce przerobowe. Już nie tylko jedna maszyna musi sobie poradzić ze wszystkimi zapisami i odczytami. Dla przykładu, jeśli mamy dane na jednym węźle, który obsługuje 100 zapytań na sekundę, to dzieląc dane na 10 węzłów, przynajmniej w teorii będziemy obsługiwać 1000 zapytań na sekundę. Oczywiście zależy to od faktu, czy dane są równomiernie rozłożone.

W bazach operacyjnych zapytania zwykle dotyczą jednego lub kilku wpisów, natomiast w bazach analitycznych zapytania wymagają przetworzenia wszystkich bądź większości wpisów, a dzięki partycjonowaniu możemy podzielić tę pracę. W tym przypadku zatem partycjonowanie pozwala na zrównoleglenie obliczeń (MPP).

Jak podzielić dane między serwerami?

Jak już wspomniałem, celem partycjonowania jest rozłożenia zapytań na wiele maszyn. Jeśli natomiast dane nie będą rozłożone równomiernie pomiędzy serwerami, to nie wykorzystamy potencjału drzemiącego w partycjonowaniu. Najgorzej jest wtedy, kiedy utrzymujemy kilka maszyn, ale większość odczytów trafia na jedną. Czyli płacimy za kilka blach, a pracuje tylko jedna. Taką sytuację nazywamy hotspot. 

Strategia podziału danych powinna być dostosowana do charakteru naszych danych i zapytań, optymalizujemy bowiem pod równe obciążenie maszyn.

Partycjonowanie danych klucz-wartość

Najbardziej naiwna strategia zakłada, że będziesz losował, na którą partycję chcesz zapisać dane. Nie ma to jednak najmniejszego sensu, ponieważ nie wiesz, na której z nich dane się znajdują, więc w trakcie odczytu musisz sprawdzić wszystkie.

Według funkcji hashującej

Optymalizacją tego podejścia, które z założenia sprawi, że dane będą równomiernie rozłożone, jest wykorzystanie funkcji hashującej i obliczenie reszty z dzielenia przez naszą liczbę partycji. Sprawi to, że odczyt i zapis zawsze będą z tego samego serwera na podstawie identyfikatora wpisu.

Niestety jeśli czytamy nasze dane w jakimś zakresie, to w odczyt będzie zaangażowanych wiele partycji, chociaż mogłaby być jedna. Tutaj wchodzi całe na biało partycjonowanie według zakresu kluczy.

Według zakresu kluczy

Załóżmy, że będziemy partycjonować po miesiącu, zatem kolejne partycje to 2022-04, 2022-05 itd. Dzięki temu odczyty z zakresem będą bardziej efektywne, natomiast jedna partycja będzie  w danym miesiącu bardziej obciążona dla zapisów niż inne. Jeśli partycje są na wielu maszynach, będziemy mieć nierównomierne obciążenie. 

Partycjonowanie według indeksu pomocniczego (drugorzędnego)

Indeksy pomocnicze nie identyfikują jednoznacznie wpisu, tylko przyspieszają przeszukiwanie i odczyt. Innymi słowy, indeks pomocniczy to tylko pointer do wpisu (wiersza, dokumentu). Dla kolejnego przykładu załóżmy, że mamy tabelę z ofertami turystycznymi i  indeksujemy kolumnę „kraj”. 

Mamy dwie możliwości partycjonowania tej tabeli. Możemy na jednej partycji przechowywać wskaźniki do wszystkich wpisów. Oznacza to, że w trakcie zapisu może zaistnieć potrzeba włożenia danych do dwóch partycji. Po pierwsze same dane do jednej z nich, a  wskaźnik do partycji, która zarządza indeksem. Niesie to za sobą dodatkowe trudności podczas przeprowadzania transakcji, bowiem partycje mogą być na różnych serwerach. Natomiast podczas odczytu wystarczy, że odpytamy jedną partycję, a ona już będzie wiedziała, skąd wyciągnąć dane.

Po drugie możemy podzielić indeks na wiele partycji i przechowywać wskaźnik oraz dane na tej samej. Czyli wszystkie wpisy dla [„Polska”, „Niemcy”] będą na jednej partycji, a [„Egipt”, „Tunezja”] na drugiej. 

Rebalansowanie partycji, czyli jak zaprowadzić nowy ład

Kiedy zmieniamy liczbę instancji obliczeniowych w naszym klastrze i korzystamy z partycjonowania danych, na pewno będzie trzeba część danych przenieść. Przecież nowy serwer nie powinien stać pusty, a skoro odjęliśmy liczbę węzłów, trzeba podzielić dane z tego porzuconego. Również jeśli wybraliśmy nie do końca trafną strategię partycjonowania, przez którą jedna lub część maszyn jest bardziej obciążona, będziemy marnować wiele zasobów. Jak widzisz, jest wiele powodów, dla których trzeba przesiedlić dane z jednej maszyny na drugą, kiedy korzystamy z partycjonowania. Proces ten nazywamy rebalansowaniem.

Nadrzędnym celem partycjonowania są równomiernie rozłożone dane. Dobrze by było, gdyby proces ten trwał jak najkrócej, najlepiej bez czasu niedostępności, więc będzie nam zależało, aby przenieść jak najmniej danych.

Repartycjonowanie to kosztowna operacja, obciąża same węzły oraz sieć. Wykonana w złym momencie, to znaczy podczas intensywnego użycia bazy, może tylko pogorszyć sytuację. Jest to argument przeciwko automatycznemu repartycjonowaniu bazy. 

Strategie repartycjonowania

Repartycjonowanie może odbywać się na podstawie rozmiaru partycji, kiedy określimy jej minimalną i maksymalną pojemność. Po przekroczeniu tych granic partycja albo podzieli się na pół, albo swoje dane wyśle do innych, a sama się usunie. W tym podejściu liczba partycji jest wprost proporcjonalna do ilości danych.

Alternatywnie liczba partycji może być wprost proporcjonalna do liczby węzłów. Cassandra na przykład domyślnie zakłada 256 partycji dla każdego węzła. Nie będziemy już zatem przenosić pojedynczych wpisów, a całe partycje. W takim wypadku, kiedy dołożymy dodatkową maszynę, zostanie ona wypełniona równomiernie poprzez zabranie odpowiedniej liczby partycji z istniejących węzłów.

Podsumowanie

Partycjonowanie zwiększa moce przerobowe bazy danych. Te korzyści przychodzą wraz z dodatkową złożonością. Żeby wykorzystać potencjał partycji, trzeba wybrać odpowiedni podział danych, co może być wróżeniem z fusów, jeśli dopiero zaczynamy tworzyć system. 

Jeśli się dobrze nie wstrzelimy z początkowymi założeniami, to po czasie będzie trzeba uruchomić proces równomiernego rozłożenia danych zwany repartycjonowaniem. Nie jest to jedyny powód, dla którego będziemy zmuszeni do wykonania tego zabiegu. Również zmiana liczby serwerów sprowokuje taką operację.

Źródła 

  1. Designing Data Intensive Applications – M. Kleppmann
  2. Partycja (baza danych) – pl.frwiki.wiki

Udostępnij ten wpis


Dobrnąłeś do końca. Jeśli ten artykuł był dla Ciebie wartościowy i chcesz otrzymywać informacje o kolejnych, to zapraszam Cię do zapisania się do listy mailingowej. Gwarantuję zero spamu.

Radek.

Inne artykuły