DocumentDB - partycjonowanie
Gdy baza danych zacznie się rozrastać powyżej 10 GB, możesz ją skalować, po prostu tworząc nowe kolekcje, a następnie rozkładając lub dzieląc dane na coraz więcej kolekcji.
Wcześniej czy później pojedynczy zbiór, który ma pojemność 10 GB, nie wystarczy do przechowywania bazy danych. Teraz 10 GB może nie brzmieć jak bardzo duża liczba, ale pamiętaj, że przechowujemy dokumenty JSON, które są zwykłym tekstem i możesz zmieścić wiele zwykłych dokumentów tekstowych w 10 GB, nawet jeśli weźmiesz pod uwagę narzut na indeksy.
Pamięć masowa nie jest jedynym problemem, jeśli chodzi o skalowalność. Maksymalna przepływność dostępna w kolekcji to dwa i pół tysiąca jednostek żądań na sekundę, które uzyskuje się dzięki kolekcji S3. Dlatego jeśli potrzebujesz większej przepustowości, będziesz musiał również skalować w poziomie przez partycjonowanie wielu kolekcji. Nazywa się również partycjonowanie skalowane w poziomiehorizontal partitioning.
Istnieje wiele podejść, których można użyć do partycjonowania danych za pomocą Azure DocumentDB. Oto najczęstsze strategie -
- Partycjonowanie spillover
- Podział zakresu
- Partycjonowanie wyszukiwania
- Hash Partitioning
Partycjonowanie spillover
Partycjonowanie typu spillover jest najprostszą strategią, ponieważ nie ma klucza partycji. Często jest to dobry wybór, gdy nie masz pewności co do wielu rzeczy. Możesz nie wiedzieć, czy kiedykolwiek będziesz musiał przeskalować poza pojedynczą kolekcję lub ile kolekcji będziesz musiał dodać lub jak szybko będziesz musiał je dodać.
Partycjonowanie typu spillover rozpoczyna się od pojedynczej kolekcji i nie ma klucza partycji.
Kolekcja zaczyna się rozrastać, a potem powiększa się trochę bardziej, potem trochę bardziej, aż zbliżasz się do limitu 10 GB.
Gdy osiągniesz 90 procent pojemności, przejdziesz do nowej kolekcji i zaczniesz używać jej do nowych dokumentów.
Gdy baza danych zostanie przeskalowana do większej liczby kolekcji, prawdopodobnie będziesz chciał przejść do strategii opartej na kluczu partycji.
Kiedy to zrobisz, będziesz musiał zrównoważyć swoje dane, przenosząc dokumenty do różnych kolekcji w oparciu o dowolną strategię, do której migrujesz.
Podział zakresu
Jedną z najpopularniejszych strategii jest podział zakresu. W tym podejściu określasz zakres wartości, do których może należeć klucz partycji dokumentu, i kierujesz dokument do kolekcji odpowiadającej temu zakresowi.
Daty są bardzo często używane w tej strategii, gdy tworzysz kolekcję do przechowywania dokumentów mieszczących się w zdefiniowanym zakresie dat. Gdy zdefiniujesz wystarczająco małe zakresy, masz pewność, że żadna kolekcja nigdy nie przekroczy swojego limitu 10 GB. Na przykład może istnieć scenariusz, w którym pojedyncza kolekcja może rozsądnie obsługiwać dokumenty przez cały miesiąc.
Może się również zdarzyć, że większość użytkowników pyta o aktualne dane, które byłyby danymi z tego miesiąca lub być może z ostatniego miesiąca, ale użytkownicy rzadko wyszukują znacznie starsze dane. Zaczynasz więc w czerwcu od kolekcji S3, która jest najdroższą kolekcją, jaką możesz kupić i zapewnia najlepszą wydajność, jaką możesz uzyskać.
W lipcu kupujesz kolejną kolekcję S3 do przechowywania danych z lipca, a także skalujesz dane czerwcowe do tańszej kolekcji S2. Następnie w sierpniu otrzymujesz kolejną kolekcję S3 i przeskalujesz lipiec do S2, a czerwiec aż do S1. Odbywa się to miesiąc po miesiącu, gdzie zawsze masz dostęp do aktualnych danych dla wysokiej przepustowości, a starsze dane są dostępne przy niższej przepustowości.
Tak długo, jak zapytanie dostarcza klucz partycji, tylko kolekcja, która ma zostać odpytana, zostanie zapytana, a nie wszystkie kolekcje w bazie danych, tak jak ma to miejsce w przypadku partycjonowania spillover.
Partycjonowanie wyszukiwania
Dzięki partycjonowaniu wyszukiwania można zdefiniować mapę partycji, która kieruje dokumenty do określonych kolekcji na podstawie ich klucza partycji. Na przykład możesz podzielić według regionu.
Przechowuj wszystkie dokumenty ze Stanów Zjednoczonych w jednej kolekcji, wszystkie dokumenty europejskie w innej kolekcji, a wszystkie dokumenty z dowolnego regionu w trzeciej kolekcji.
Skorzystaj z tej mapy partycji i narzędzia do rozpoznawania partycji wyszukiwania, aby dowiedzieć się, w której kolekcji należy utworzyć dokument i do których kolekcji należy przeszukiwać, na podstawie klucza partycji, który jest właściwością regionu zawartą w każdym dokumencie.
Hash Partitioning
W przypadku partycjonowania mieszającego partycje są przypisywane na podstawie wartości funkcji skrótu, co umożliwia równomierne rozłożenie żądań i danych na wiele partycji.
Jest to powszechnie używane do partycjonowania danych generowanych lub używanych przez dużą liczbę różnych klientów i jest przydatne do przechowywania profili użytkowników, pozycji katalogu itp.
Rzućmy okiem na prosty przykład partycjonowania zakresu przy użyciu RangePartitionResolver dostarczonego przez .NET SDK.
Step 1- Utwórz nowy DocumentClient, a my utworzymy dwie kolekcje w zadaniu CreateCollections. Jeden będzie zawierał dokumenty dla użytkowników, których identyfikatory użytkowników rozpoczynają się od A do M, a drugi dla identyfikatorów użytkowników od N do Z.
private static async Task CreateCollections(DocumentClient client) {
await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
Id = “CollectionAM” });
await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
Id = “CollectionNZ” });
}
Step 2 - Zarejestruj program rozpoznawania zakresu dla bazy danych.
Step 3- Utwórz nowy RangePartitionResolver <string>, który jest typem danych naszego klucza partycji. Konstruktor przyjmuje dwa parametry, nazwę właściwości klucza partycji i słownik, który jest mapą fragmentów lub mapą partycji, która jest tylko listą zakresów i odpowiadających im kolekcji, które wstępnie definiujemy dla programu rozpoznawania nazw.
private static void RegisterRangeResolver(DocumentClient client) {
//Note: \uffff is the largest UTF8 value, so M\ufff includes all strings that start with M.
var resolver = new RangePartitionResolver<string>(
"userId", new Dictionary<Range<string>, string>() {
{ new Range<string>("A", "M\uffff"), "dbs/myfirstdb/colls/CollectionAM" },
{ new Range<string>("N", "Z\uffff"), "dbs/myfirstdb/colls/CollectionNZ" },
});
client.PartitionResolvers["dbs/myfirstdb"] = resolver;
}
Konieczne jest tutaj zakodowanie największej możliwej wartości UTF-8. Albo pierwszy zakres nie pasowałby do żadnego M poza jednym M, podobnie jak Z w drugim zakresie. Możesz więc po prostu pomyśleć o tej zakodowanej wartości jako o symbolu wieloznacznym do dopasowania klucza partycji.
Step 4- Po utworzeniu resolwera zarejestruj go w bazie danych przy użyciu bieżącego DocumentClient. Aby to zrobić, wystarczy przypisać go do właściwości słownika PartitionResolver.
Będziemy tworzyć i wyszukiwać dokumenty w bazie danych, a nie w kolekcji, jak zwykle. Program rozpoznawania nazw użyje tej mapy do kierowania żądań do odpowiednich kolekcji.
Teraz stwórzmy kilka dokumentów. Najpierw utworzymy jeden dla userId Kirk, a potem drugi dla Spocka.
private static async Task CreateDocumentsAcrossPartitions(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create Documents Across Partitions ****");
var kirkDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
"Kirk", title = "Captain" });
Console.WriteLine("Document 1: {0}", kirkDocument.Resource.SelfLink);
var spockDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
"Spock", title = "Science Officer" });
Console.WriteLine("Document 2: {0}", spockDocument.Resource.SelfLink);
}
Pierwszym parametrem jest tutaj łącze do bazy danych, a nie konkretna kolekcja. Nie jest to możliwe bez programu do rozpoznawania partycji, ale z jednym działa po prostu bezproblemowo.
Oba dokumenty zostały zapisane w bazie danych myfirstdb, ale wiemy, że Kirk jest przechowywany w kolekcji od A do M, a Spock jest przechowywany w kolekcji od N do Z, jeśli nasz RangePartitionResolver działa poprawnie.
Nazwijmy je z zadania CreateDocumentClient, jak pokazano w poniższym kodzie.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
await CreateCollections(client);
RegisterRangeResolver(client);
await CreateDocumentsAcrossPartitions(client);
}
}
Po wykonaniu powyższego kodu otrzymasz następujące dane wyjściowe.
**** Create Documents Across Partitions ****
Document 1: dbs/Ic8LAA==/colls/Ic8LAO2DxAA=/docs/Ic8LAO2DxAABAAAAAAAAAA==/
Document 2: dbs/Ic8LAA==/colls/Ic8LAP12QAE=/docs/Ic8LAP12QAEBAAAAAAAAAA==/
Jak widać, linki własne obu dokumentów mają różne identyfikatory zasobów, ponieważ istnieją w dwóch oddzielnych kolekcjach.