Projektowanie skalowalnej strategii partycjonowania dla usługi Azure Table Storage

W tym artykule omówiono partycjonowanie tabeli w usłudze Azure Table Storage i strategie, których można użyć w celu zapewnienia wydajnej skalowalności.

Platforma Azure udostępnia magazyn w chmurze, który jest wysoce dostępny i wysoce skalowalny. Podstawowy system magazynowania dla platformy Azure jest udostępniany za pośrednictwem zestawu usług, takich jak Azure Blob Storage, Azure Table Storage, Azure Queue Storage i Azure Files.

Usługa Azure Table Storage jest przeznaczona do przechowywania danych strukturalnych. Usługa Azure Storage obsługuje nieograniczoną liczbę tabel. Każda tabela może być skalowana do ogromnych poziomów i zapewniać terabajty magazynu fizycznego. Aby jak najlepiej wykorzystać tabele, musisz optymalnie partycjonować dane. W tym artykule omówiono strategie, których można użyć do wydajnego partycjonowania danych dla usługi Azure Table Storage.

Jednostki tabeli

Jednostki tabeli reprezentują jednostki danych, które są przechowywane w tabeli. Jednostki tabeli są podobne do wierszy w typowej tabeli relacyjnej bazy danych. Każda jednostka definiuje kolekcję właściwości. Każda właściwość jest definiowana jako para klucz/wartość według jego nazwy, wartości i typu danych wartości. Jednostki muszą definiować następujące trzy właściwości systemowe w ramach kolekcji właściwości:

  • PartitionKey: właściwość PartitionKey przechowuje wartości ciągów identyfikujące partycję, do której należy jednostka. Partycje, jak omawiamy później, są integralną częścią skalowalności tabeli. Jednostki, które mają tę samą wartość PartitionKey , są przechowywane w tej samej partycji.

  • RowKey: właściwość RowKey przechowuje wartości ciągów, które jednoznacznie identyfikują jednostki w każdej partycji. Klucz PartitionKey i RowKey razem tworzą klucz podstawowy dla jednostki.

  • Sygnatura czasowa: właściwość Sygnatura czasowa zapewnia możliwość śledzenia jednostki. Sygnatura czasowa to wartość daty/godziny, która informuje o ostatniej modyfikacji jednostki. Sygnatura czasowa jest czasami określana jako wersja jednostki. Modyfikacje sygnatur czasowych są ignorowane, ponieważ usługa tabel utrzymuje wartość tej właściwości podczas wszystkich operacji wstawiania i aktualizowania.

Klucz podstawowy tabeli

Klucz podstawowy jednostki platformy Azure składa się z połączonych właściwości PartitionKey i RowKey . Dwie właściwości tworzą pojedynczy indeks grupowany w tabeli. Wartości PartitionKey i RowKey mogą mieć rozmiar do 1024 znaków. Puste ciągi są również dozwolone; jednak wartości null nie są dozwolone.

Indeks klastrowany sortuje według klucza partycji w kolejności rosnącej, a następnie według wartości RowKey w kolejności rosnącej. Kolejność sortowania jest obserwowana we wszystkich odpowiedziach na zapytania. Porównania leksykalne są używane podczas operacji sortowania. Wartość ciągu "111" pojawia się przed wartością ciągu "2". W niektórych przypadkach możesz chcieć, aby kolejność sortowania mogła być liczbowa. Aby sortować w kolejności liczbowej i rosnącej, należy użyć ciągów o stałej długości i zerowej. W poprzednim przykładzie "002" pojawia się przed "111".

Partycje tabel

Partycje reprezentują kolekcję jednostek z tymi samymi wartościami PartitionKey . Partycje są zawsze obsługiwane z jednego serwera partycji. Każdy serwer partycji może obsługiwać co najmniej jedną partycję. Serwer partycji ma limit szybkości liczby jednostek, które może obsłużyć z jednej partycji w czasie. W szczególności partycja ma docelową skalowalność 2000 jednostek na sekundę. Ta przepływność może być wyższa podczas minimalnego obciążenia węzła magazynu, ale jest ograniczana, gdy węzeł staje się gorący lub aktywny.

Aby lepiej zilustrować koncepcję partycjonowania, na poniższej ilustracji przedstawiono tabelę zawierającą niewielki podzestaw danych na potrzeby rejestracji zdarzeń wyścigu stóp. Na rysunku przedstawiono koncepcyjny widok partycjonowania, w którym element PartitionKey zawiera trzy różne wartości: nazwę zdarzenia połączoną z trzema dystansami (pełny maraton, półmaraton i 10 km). W tym przykładzie użyto dwóch serwerów partycji. Serwer A zawiera rejestracje na półmaraton i 10 km odległości. Serwer B zawiera tylko odległości w pełnym maratonie. Wartości RowKey są wyświetlane w celu zapewnienia kontekstu, ale wartości nie mają znaczenia w tym przykładzie.

Diagram przedstawiający tabelę z trzema partycjami
Tabela z trzema partycjami

Skalowalność

Ponieważ partycja jest zawsze obsługiwana z jednego serwera partycji, a każdy serwer partycji może obsługiwać co najmniej jedną partycję, wydajność obsługi jednostek jest skorelowana z kondycją serwera. Serwery, które napotykają duży ruch dla partycji, mogą nie być w stanie utrzymać wysokiej przepływności. Jeśli na przykład na powyższej ilustracji otrzymano wiele żądań "2011 New York City Marathon__Half", serwer A może stać się zbyt gorący. Aby zwiększyć przepływność serwera, system magazynu równoważy obciążenia partycji na innych serwerach. W rezultacie ruch jest dystrybuowany na wielu innych serwerach. Aby zapewnić optymalne równoważenie obciążenia ruchu, należy użyć większej liczby partycji, aby usługa Azure Table Storage mogła dystrybuować partycje do większej liczby serwerów partycji.

Transakcje grupy jednostek

Transakcja grupy jednostek jest zestawem operacji magazynu, które są implementowane niepodziecznie na jednostkach, które mają tę samą wartość PartitionKey . Jeśli jakakolwiek operacja magazynu w grupie jednostek zakończy się niepowodzeniem, wszystkie operacje magazynu w jednostce zostaną wycofane. Transakcja grupy jednostek składa się z nie więcej niż 100 operacji magazynowania i może być nie więcej niż 4 MiB rozmiar. Transakcje grupy jednostek zapewniają usłudze Azure Table Storage ograniczoną formę semantyki niepodzielności, spójności, izolacji i trwałości (ACID) udostępnianych przez relacyjne bazy danych.

Transakcje grup jednostek zwiększają przepływność, ponieważ zmniejszają liczbę poszczególnych operacji magazynu, które muszą zostać przesłane do usługi Azure Table Storage. Transakcje grup jednostek zapewniają również korzyść ekonomiczną. Transakcja grupy jednostek jest rozliczana jako pojedyncza operacja magazynu niezależnie od liczby operacji magazynu, które zawiera. Ponieważ wszystkie operacje magazynowania w transakcji grupy jednostek mają wpływ na jednostki, które mają tę samą wartość PartitionKey , konieczne jest użycie transakcji grupy jednostek może zwiększyć wybór wartości PartitionKey .

Partycje zakresu

Jeśli używasz unikatowych wartości PartitionKey dla jednostek, każda jednostka należy do własnej partycji. Jeśli używane są unikatowe wartości zwiększające lub zmniejszające się, możliwe, że platforma Azure utworzy partycje zakresu. Zakres partycji grupuje jednostki, które mają sekwencyjne, unikatowe wartości PartitionKey , aby zwiększyć wydajność zapytań zakresu. Bez partycji zakresu zapytanie zakresu musi przekraczać granice partycji lub granice serwera, co może zmniejszyć wydajność zapytań. Rozważmy aplikację korzystającą z poniższej tabeli, która ma rosnącą wartość sekwencji dla elementu PartitionKey:

PartitionKey RowKey
"0001" -
"0002" -
"0003" -
"0004" -
"0005" -
"0006" -

Platforma Azure może zgrupować pierwsze trzy jednostki w partycję zakresu. W przypadku zastosowania zapytania zakresu do tabeli, która używa wartości PartitionKey jako kryteriów i żąda jednostek z "0001" do "0003", zapytanie może działać wydajnie, ponieważ jednostki są obsługiwane z jednego serwera partycji. Nie ma gwarancji, kiedy i jak zostanie utworzona partycja zakresu.

Istnienie partycji zakresu dla tabeli może mieć wpływ na wydajność operacji wstawiania w przypadku wstawiania jednostek, które mają rosnące lub malejące wartości PartitionKey . Wstawianie jednostek, które mają rosnące wartości PartitionKey , jest nazywane wzorcem tylko do dołączania. Wstawianie jednostek, które mają malejące wartości, jest nazywane wzorcem tylko do wstępnego. Rozważ, aby nie używać tego rodzaju wzorców, ponieważ ogólna przepływność żądań wstawiania jest ograniczona przez pojedynczy serwer partycji. Wynika to z tego, że jeśli istnieją partycje zakresu, pierwsze i ostatnie (zakres) partycje zawierają odpowiednio najmniej i największe wartości PartitionKey . Dlatego wstawianie nowej jednostki, która ma sekwencyjnie niższą lub wyższą wartość PartitionKey , jest przeznaczona dla jednej z partycji końcowych. Na poniższej ilustracji przedstawiono możliwy zestaw partycji zakresu opartych na poprzednim przykładzie. Jeśli wstawiono zestaw jednostek "0007", "0008" i "0009", zostaną one przypisane do ostatniej (pomarańczowej) partycji.

Diagram przedstawiający zestaw partycji zakresu
Zestaw partycji zakresu

Należy pamiętać, że nie ma negatywnego wpływu na wydajność, jeśli operacje wstawiania używają wartości PartitionKey , które są bardziej rozproszone.

Analizowanie danych

W przeciwieństwie do tabeli w relacyjnej bazie danych, której można użyć do zarządzania indeksami, tabele w usłudze Azure Table Storage mogą mieć tylko jeden indeks. Indeks w usłudze Azure Table Storage zawsze składa się z właściwości PartitionKey i RowKey .

W tabeli platformy Azure nie masz luksusu dostrajania wydajności tabeli przez dodanie większej liczby indeksów lub zmianę istniejącej tabeli po jej wdrożeniu. Dane należy analizować podczas projektowania tabeli. Najważniejsze aspekty, które należy wziąć pod uwagę pod kątem optymalnej skalowalności, a wydajność zapytań i wstawiania to wartości PartitionKey i RowKey . W tym artykule opisano sposób wybierania klucza partycji , ponieważ bezpośrednio odnosi się do sposobu partycjonowania tabel.

Ustalanie rozmiaru partycji

Ustalanie rozmiaru partycji odnosi się do liczby jednostek, które zawiera partycja. Omówiono w temacie Skalowalność, posiadanie większej liczby partycji oznacza lepsze równoważenie obciążenia. Stopień szczegółowości wartości PartitionKey wpływa na rozmiar partycji. Na najbardziej grubym poziomie, jeśli pojedyncza wartość jest używana jako PartitionKey, wszystkie jednostki znajdują się w jednej partycji, która jest bardzo duża. Na najwyższym poziomie szczegółowości klucz partycji może zawierać unikatowe wartości dla każdej jednostki. Wynikiem jest to, że istnieje partycja dla każdej jednostki. W poniższej tabeli przedstawiono zalety i wady zakresu szczegółowości:

Stopień szczegółowości klucza partycji Rozmiar partycji Zalety Wady
Pojedyncza wartość Niewielka liczba jednostek Transakcje wsadowe są możliwe z dowolną jednostką.

Wszystkie jednostki są lokalne i obsługiwane z tego samego węzła magazynu.
Pojedyncza wartość Duża liczba jednostek Transakcje grupy jednostek mogą być możliwe w przypadku dowolnej jednostki. Aby uzyskać więcej informacji na temat limitów transakcji grupy jednostek, zobacz Wykonywanie transakcji grupy jednostek. Skalowanie jest ograniczone.

Przepływność jest ograniczona do wydajności pojedynczego serwera.
Wiele wartości Wiele partycji

Rozmiary partycji zależą od dystrybucji jednostek.
Transakcje wsadowe są możliwe w niektórych jednostkach.

Dynamiczne partycjonowanie jest możliwe.

Zapytania z pojedynczym żądaniem są możliwe (bez tokenów kontynuacji).

Równoważenie obciążenia na większej większa liczba serwerów partycji jest możliwe.
Wysoce nierównomierna dystrybucja jednostek między partycjami może ograniczyć wydajność większych i bardziej aktywnych partycji.
Unikatowe wartości Wiele małych partycji Tabela jest wysoce skalowalna.

Partycje zakresu mogą zwiększyć wydajność zapytań obejmujących wiele partycji.
Zapytania obejmujące zakresy mogą wymagać wizyt na więcej niż jednym serwerze.

Transakcje wsadowe nie są możliwe.

Wzorce tylko do dołączania lub tylko do wstępnego mogą mieć wpływ na przepływność wstawiania.

W tabeli przedstawiono, w jaki sposób skalowanie ma wpływ na wartości PartitionKey . Najlepszym rozwiązaniem jest faworyzowanie mniejszych partycji, ponieważ oferują lepsze równoważenie obciążenia. Większe partycje mogą być odpowiednie w niektórych scenariuszach i niekoniecznie są niekorzystne. Jeśli na przykład aplikacja nie wymaga skalowalności, może być odpowiednia pojedyncza duża partycja.

Określanie zapytań

Zapytania pobierają dane z tabel. Podczas analizowania danych dla tabeli w usłudze Azure Table Storage ważne jest, aby rozważyć, które zapytania będą używane przez aplikację. Jeśli aplikacja ma kilka zapytań, może być konieczne ich ustalanie priorytetów, chociaż decyzje mogą być subiektywne. W wielu przypadkach dominujące zapytania są zauważalne w przypadku innych zapytań. Pod względem wydajności zapytania należą do różnych kategorii. Ponieważ tabela ma tylko jeden indeks, wydajność zapytań zwykle jest powiązana z właściwościami PartitionKey i RowKey . W poniższej tabeli przedstawiono różne typy zapytań i ich oceny wydajności:

Typ zapytania Dopasowanie klucza partycji Dopasowanie rowKey Ocena wydajności
Skanowanie zakresu wierszy Exact Częściowe Lepiej z partycjami o mniejszych rozmiarach.

Źle z partycjami, które są bardzo duże.
Skanowanie zakresu partycji Częściowe Częściowe Dobrze z niewielką liczbą serwerów partycji, które są dotykane.

Gorzej w przypadku dotykania większej liczby serwerów.
Pełne skanowanie tabeli Częściowe, brak Częściowe, brak Gorzej w przypadku skanowanego podzestawu partycji.

Najgorsze w przypadku skanowania wszystkich partycji.

Uwaga

Tabela definiuje oceny wydajności względem siebie. Liczba i rozmiar partycji mogą ostatecznie określić sposób wykonywania zapytania. Na przykład skanowanie zakresu partycji dla tabeli, która ma wiele dużych partycji, może działać słabo w porównaniu z pełnym skanowaniem tabeli dla tabeli, która ma kilka małych partycji.

Typy zapytań wymienione w poprzedniej tabeli pokazują postęp z najlepszych typów zapytań do najgorszego typu na podstawie ocen wydajności. Zapytania punktowe to najlepsze typy zapytań do użycia, ponieważ w pełni używają indeksu klastrowanego tabeli. Następujące zapytanie punktowe używa danych z tabeli rejestracji wyścigów stóp:

http://<account>.windows.core.net/registrations(PartitionKey=”2011 New York City Marathon__Full”,RowKey=”1234__John__M__55”)  
  

Jeśli aplikacja używa wielu zapytań, nie wszystkie z nich mogą być zapytaniami punktowym. Jeśli chodzi o wydajność, zapytania zakresu są zgodne z zapytaniami punktów. Istnieją dwa typy zapytań zakresu: skanowanie zakresu wierszy i skanowanie zakresu partycji. Skanowanie zakresu wierszy określa jedną partycję. Ponieważ operacja występuje na jednym serwerze partycji, skanowania zakresów wierszy są zazwyczaj bardziej wydajne niż skanowania zakresu partycji. Jednak kluczowym czynnikiem w wydajności skanowania zakresu wierszy jest to, jak selektywne jest zapytanie. Selektorowość zapytań określa, ile wierszy musi być iterowanych, aby znaleźć pasujące wiersze. Bardziej selektywne zapytania są bardziej wydajne podczas skanowania zakresu wierszy.

Aby ocenić priorytety zapytań, należy wziąć pod uwagę wymagania dotyczące częstotliwości i czasu odpowiedzi dla każdego zapytania. Zapytania, które są często wykonywane, mogą mieć wyższy priorytet. Jednak ważne, ale rzadko używane zapytanie może mieć wymagania dotyczące małych opóźnień, które mogą być wyższe na liście priorytetów.

Wybierz wartość PartitionKey

Podstawą projektu dowolnej tabeli jest jego skalowalność, zapytania używane do uzyskiwania do niego dostępu i wymagania dotyczące operacji magazynu. Wybrane wartości PartitionKey określają sposób partycjonowania tabeli i typu zapytań, których można użyć. Operacje magazynowania, a zwłaszcza operacje wstawiania, mogą również mieć wpływ na wybór wartości PartitionKey . Wartości PartitionKey mogą wahać się od pojedynczych wartości do unikatowych wartości. Można je również utworzyć przy użyciu wielu wartości. Właściwości jednostki można użyć do utworzenia wartości PartitionKey . Możesz też obliczyć wartość aplikacji. W poniższych sekcjach omówiono ważne zagadnienia.

Transakcje grupy jednostek

Deweloperzy powinni najpierw rozważyć, czy aplikacja będzie używać transakcji grupy jednostek (aktualizacje wsadowe). Transakcje grupy jednostek wymagają, aby jednostki miały taką samą wartość PartitionKey . Ponadto, ponieważ aktualizacje wsadowe są przeznaczone dla całej grupy, opcje wartości PartitionKey mogą być ograniczone. Na przykład aplikacja bankowa, która utrzymuje transakcje gotówkowe, musi wstawić transakcje gotówkowe do tabeli niepodziealnie. Transakcje gotówkowe reprezentują zarówno strony debetowe, jak i kredytowe i muszą być netto do zera. To wymaganie oznacza, że numer konta nie może być używany jako żadna część wartości PartitionKey , ponieważ każda strona transakcji używa różnych numerów kont. Zamiast tego identyfikator transakcji może być lepszym wyborem.

Partycje

Numery partycji i rozmiary wpływają na skalowalność tabeli, która jest ładowana. Są one również kontrolowane przez stopień szczegółowości wartości PartitionKey . Ustalenie klucza partycji na podstawie rozmiaru partycji może być trudne, zwłaszcza jeśli rozkład wartości jest trudny do przewidzenia. Dobrą regułą jest użycie wielu, mniejszych partycji. Wiele partycji tabeli ułatwia usłudze Azure Table Storage zarządzanie węzłami magazynu obsługiwanymi przez partycje.

Wybranie unikatowych lub bardziej precyzyjnych wartości dla klucza partycji powoduje mniejsze, ale więcej partycji. Ogólnie jest to korzystne, ponieważ system może równoważyć obciążenie wielu partycji w celu rozłożenia obciążenia między wiele partycji. Należy jednak wziąć pod uwagę wpływ wielu partycji na zapytania z zakresem wielu partycji. Te typy zapytań muszą odwiedzać wiele partycji, aby spełnić wymagania zapytania. Istnieje możliwość, że partycje są rozproszone na wielu serwerach partycji. Jeśli zapytanie przekracza granicę serwera, należy zwrócić tokeny kontynuacji. Tokeny kontynuacji określają następne wartości PartitionKey lub RowKey , aby pobrać następny zestaw danych dla zapytania. Innymi słowy tokeny kontynuacji reprezentują co najmniej jedno żądanie do usługi, co może obniżyć ogólną wydajność zapytania.

Wybór zapytań to kolejny czynnik, który może mieć wpływ na wydajność zapytania. Wybór zapytań to miara liczby wierszy, które muszą być iterowane dla każdej partycji. Tym bardziej selektywne jest zapytanie, tym bardziej wydajne jest zwracanie żądanych wierszy. Ogólna wydajność zapytań zakresu może zależeć od liczby serwerów partycji, które muszą być dotknięte lub jak selektywne jest zapytanie. Należy również unikać używania wzorców tylko do dołączania lub tylko do dołączania podczas wstawiania danych do tabeli. Jeśli używasz tych wzorców, pomimo tworzenia małych i wielu partycji, możesz ograniczyć przepływność operacji wstawiania. Wzorce tylko do dołączania i tylko do wstępnego są omawiane w partycjach zakresów.

Zapytania

Znajomość zapytań, których będziesz używać, może pomóc określić, które właściwości należy wziąć pod uwagę dla wartości PartitionKey . Właściwości używane w zapytaniach są kandydatami do wartości PartitionKey . Poniższa tabela zawiera ogólne wskazówki dotyczące określania wartości PartitionKey :

Jeśli jednostka... Akcja
Ma jedną właściwość klucza Użyj go jako klucza partycji.
Ma dwie kluczowe właściwości Użyj jednego jako klucza partycji , a drugiego jako klucza wiersza.
Ma więcej niż dwie kluczowe właściwości Użyj klucza złożonego połączonych wartości.

Jeśli istnieje więcej niż jedno zapytanie o taką samą dominującą skalę, możesz wstawić informacje wiele razy, używając innych potrzebnych wartości RowKey . Aplikacja będzie zarządzać pomocniczymi (lub wyższymi itd.) wierszami. Możesz użyć tego typu wzorca, aby spełnić wymagania dotyczące wydajności zapytań. W poniższym przykładzie użyto danych z przykładu rejestracji wyścigu stóp. Ma ona dwa dominujące zapytania:

  • Wykonywanie zapytań według liczby bib
  • Wykonywanie zapytań według wieku

Aby obsłużyć oba dominujące zapytania, wstaw dwa wiersze jako transakcję grupy jednostek. W poniższej tabeli przedstawiono właściwości PartitionKey i RowKey dla tego scenariusza. Wartości RowKey zapewniają prefiks dla analizy biznesowej i wieku, aby aplikacja mogła odróżnić te dwie wartości.

PartitionKey RowKey
2011 New York City Marathon__Full BIB:01234__John__M__55
2011 New York City Marathon__Full AGE:055__1234__John__M

W tym przykładzie transakcja grupy jednostek jest możliwa, ponieważ wartości PartitionKey są takie same. Transakcja grupy zapewnia niepodzielność operacji wstawiania. Chociaż można użyć tego wzorca z różnymi wartościami PartitionKey , zalecamy użycie tych samych wartości w celu uzyskania tej korzyści. W przeciwnym razie może być konieczne napisanie dodatkowej logiki w celu zapewnienia niepodzielnych transakcji, które używają różnych wartości PartitionKey .

Operacje magazynu

Tabele w usłudze Azure Table Storage mogą napotkać obciążenie nie tylko z zapytań. Mogą również napotkać obciążenie operacji magazynu, takich jak operacje wstawiania, aktualizacji i usuwania. Zastanów się, jakiego typu operacje magazynowania będą wykonywane w tabeli i z jaką szybkością. Jeśli te operacje są wykonywane rzadko, być może nie musisz się nimi martwić. Jednak w przypadku częstych operacji, takich jak wykonywanie wielu wstawiania w krótkim czasie, należy wziąć pod uwagę sposób, w jaki te operacje są obsługiwane w wyniku wybranej wartości PartitionKey . Ważnymi przykładami są wzorce tylko do dołączania i tylko do dołączania. Wzorce tylko do dołączania i tylko do wstępnego są omawiane w partycjach zakresów.

W przypadku używania wzorca tylko do dołączania lub z prepend-only należy użyć unikatowych wartości rosnących lub malejących dla klucza partycji w kolejnych wstawiania. Jeśli połączysz ten wzorzec z częstymi operacjami wstawiania, tabela nie będzie mogła obsłużyć operacji wstawiania z dużą skalowalnością. Skalowalność tabeli ma wpływ, ponieważ platforma Azure nie może równoważyć obciążenia żądań operacji do innych serwerów partycji. W takim przypadku warto rozważyć użycie wartości losowych, takich jak wartości identyfikatora GUID. Następnie rozmiary partycji mogą pozostać małe i nadal utrzymywać równoważenie obciążenia podczas operacji magazynowania.

Testowanie obciążenia partycji tabeli

Jeśli wartość PartitionKey jest złożona lub wymaga porównania z innymi mapowaniami PartitionKey , może być konieczne przetestowanie wydajności tabeli. Test powinien sprawdzić, jak dobrze partycja działa w przypadku obciążeń szczytowych.

Aby wykonać test przeciążeniowy

  1. Twórca tabeli testowej.
  2. Załaduj tabelę testową przy użyciu danych, aby zawierała jednostki z wartością PartitionKey , która będzie docelowa.
  3. Użyj aplikacji do symulowania szczytowego obciążenia tabeli. Należy zastosować pojedynczą partycję przy użyciu wartości PartitionKey z kroku 2. Ten krok jest inny dla każdej aplikacji, ale symulacja powinna zawierać wszystkie wymagane zapytania i operacje magazynu. Może być konieczne dostosowanie aplikacji tak, aby była przeznaczona dla jednej partycji.
  4. Sprawdź przepływność operacji GET lub PUT w tabeli.

Aby sprawdzić przepływność, porównaj wartości rzeczywiste z określonym limitem pojedynczej partycji na jednym serwerze. Partycje są ograniczone do 2000 jednostek na sekundę. Jeśli przepływność przekroczy 2000 jednostek na sekundę dla partycji, serwer może działać zbyt gorąco w ustawieniu produkcyjnym. W takim przypadku wartości PartitionKey mogą być zbyt grube, aby nie było wystarczającej liczby partycji lub partycje są zbyt duże. Może być konieczne zmodyfikowanie wartości PartitionKey , aby partycje będą dystrybuowane między więcej serwerów.

Równoważenie obciążenia

Równoważenie obciążenia w warstwie partycji występuje, gdy partycja jest zbyt gorąca. Gdy partycja jest zbyt gorąca, partycja, w szczególności serwer partycji, działa poza docelową skalowalność. W przypadku usługi Azure Storage każda partycja ma docelową skalowalność 2000 jednostek na sekundę. Równoważenie obciążenia odbywa się również w warstwie rozproszonego systemu plików (DFS).

Równoważenie obciążenia w warstwie systemu plików DFS dotyczy obciążenia we/wy i wykracza poza zakres tego artykułu. Równoważenie obciążenia w warstwie partycji nie występuje natychmiast po przekroczeniu wartości docelowej skalowalności. Zamiast tego system czeka kilka minut przed rozpoczęciem procesu równoważenia obciążenia. Dzięki temu partycja stanie się naprawdę gorąca. Nie jest konieczne tworzenie partycji z wygenerowanymi obciążeniami, które wyzwala równoważenie obciążenia, ponieważ system automatycznie wykonuje zadanie.

Jeśli tabela została zagruntowana pewnym obciążeniem, system może być w stanie zrównoważyć partycje na podstawie rzeczywistego obciążenia, co skutkuje znacznie różnymi rozkładami partycji. Zamiast zawęzić partycje, rozważ napisanie kodu obsługującego przekroczenie limitu czasu i błędy zajętości serwera. Błędy są zwracane, gdy system jest równoważeniem obciążenia. Dzięki obsłudze tych błędów przy użyciu strategii ponawiania próby aplikacja może lepiej obsługiwać obciążenia szczytowe. Strategie ponawiania prób zostały omówione bardziej szczegółowo w poniższej sekcji.

W przypadku równoważenia obciążenia partycja stanie się w trybie offline przez kilka sekund. W okresie offline system ponownie przypisuje partycję do innego serwera partycji. Należy pamiętać, że dane nie są przechowywane przez serwery partycji. Zamiast tego serwery partycji obsługują jednostki z warstwy systemu plików DFS. Ponieważ dane nie są przechowywane w warstwie partycji, przenoszenie partycji na różne serwery jest szybkim procesem. Ta elastyczność znacznie ogranicza przestoje, jeśli istnieje, że aplikacja może napotkać.

Strategia ponawiania prób

Aplikacja musi obsługiwać błędy operacji magazynu, aby zapewnić, że nie utracisz żadnych aktualizacji danych. Niektóre błędy nie wymagają strategii ponawiania. Na przykład aktualizacje, które zwracają błąd 401 Brak autoryzacji, nie korzystają z ponawiania próby wykonania operacji, ponieważ prawdopodobnie stan aplikacji nie zmieni się między ponownymi próbami rozwiązania błędu 401. Jednak błędy, takie jak serwer zajęty lub limit czasu, są związane z funkcjami równoważenia obciążenia platformy Azure, które zapewniają skalowalność tabeli. Gdy węzły magazynu obsługujące jednostki stają się gorące, platforma Azure równoważy obciążenie przez przeniesienie partycji do innych węzłów. W tym czasie partycja może być niedostępna, co powoduje błędy zajętości serwera lub przekroczenia limitu czasu. Po pewnym czasie partycja zostanie ponownie włączona, a aktualizacje wznowione.

Strategia ponawiania prób jest odpowiednia dla błędów zajętości serwera lub przekroczenia limitu czasu. W większości przypadków można wykluczyć błędy na poziomie 400 i niektóre błędy na poziomie 500 z logiki ponawiania prób. Błędy, które można wykluczyć, obejmują 501 Nie zaimplementowano i 505 Wersja HTTP nie jest obsługiwana. Następnie można zaimplementować strategię ponawiania prób dla maksymalnie 500 błędów na poziomie, takich jak Serwer zajęty (503) i Limit czasu (504).

Możesz wybrać jedną z trzech typowych strategii ponawiania prób dla aplikacji:

  • Brak ponawiania: nie jest podejmowana żadna próba ponawiania.
  • Naprawiono wycofywanie: operacja jest ponawiana N razy ze stałą wartością wycofywania.
  • Wycofywanie wykładnicze: Operacja jest ponawiana n razy z wartością wycofywania wykładniczego.

Strategia Bez ponawiania prób jest prostym (i wymijanym) sposobem obsługi błędów operacji. Jednak strategia Nie ponawiania nie jest bardzo przydatna. Nie nakładanie żadnych ponownych prób stwarza oczywiste ryzyko, gdy dane nie są prawidłowo przechowywane po operacjach, które zakończyły się niepowodzeniem. Lepszą strategią jest użycie strategii stałej wycofywania. zapewnia możliwość ponawiania prób operacji z tym samym czasem trwania wycofywania.

Jednak strategia nie jest zoptymalizowana pod kątem obsługi wysoce skalowalnych tabel. Jeśli wiele wątków lub procesów czeka na ten sam czas, mogą wystąpić kolizje. Zalecana strategia ponawiania jest taka, która używa wycofywania wykładniczego, w którym każda próba ponawiania jest dłuższa niż ostatnia próba. Jest podobny do algorytmu unikania kolizji używanego w sieciach komputerowych, takich jak Ethernet. Wycofywanie wykładnicze używa współczynnika losowego, aby zapewnić dodatkową wariancję do wynikowego interwału. Wartość wycofywania jest następnie ograniczona do minimalnych i maksymalnych limitów. Poniższa formuła może służyć do obliczania następnej wartości wycofywania przy użyciu algorytmu wykładniczego:

y = Rand(0.8z, 1.2z)(2x-1

y = Min(zmin + y, zmax

Gdzie:

z = domyślne wycofywanie w milisekundach

zmin = domyślne minimalne wycofywanie w milisekundach

zmax = domyślne maksymalne wycofywanie w milisekundach

x = liczba ponownych prób

y = wartość wycofywania w milisekundach

Mnożniki 0,8 i 1,2 używane w funkcji Rand (losowe) generują losową wariancję domyślnego wycofywania w ±20% oryginalnej wartości. Zakres ±20% jest akceptowalny dla większości strategii ponawiania prób i zapobiega dalszym kolizjom. Formułę można zaimplementować przy użyciu następującego kodu:

int retries = 1;  
  
// Initialize variables with default values  
var defaultBackoff = TimeSpan.FromSeconds(30);  
var backoffMin = TimeSpan.FromSeconds(3);  
var backoffMax = TimeSpan.FromSeconds(90);  
  
var random = new Random();  
  
double backoff = random.Next(  
    (int)(0.8D * defaultBackoff.TotalMilliseconds),   
    (int)(1.2D * defaultBackoff.TotalMilliseconds));  
backoff *= (Math.Pow(2, retries) - 1);  
backoff = Math.Min(  
    backoffMin.TotalMilliseconds + backoff,   
    backoffMax.TotalMilliseconds);  
  

Podsumowanie

Aplikacja w usłudze Azure Table Storage może przechowywać ogromną ilość danych, ponieważ usługa Table Storage zarządza partycjami i przypisuje je ponownie w wielu węzłach magazynu. Partycjonowanie danych służy do kontrolowania skalowalności tabeli. Planuj z wyprzedzeniem podczas definiowania schematu tabeli, aby upewnić się, że implementujesz wydajne strategie partycjonowania. W szczególności przeanalizuj wymagania, dane i zapytania aplikacji przed wybraniem wartości PartitionKey . Każda partycja może zostać ponownie przypisana do różnych węzłów magazynu, ponieważ system reaguje na ruch. Użyj testu przeciążeniowego partycji, aby upewnić się, że tabela ma poprawne wartości PartitionKey . Ten test pomaga określić, kiedy partycje są zbyt gorące i pomaga wprowadzić niezbędne korekty partycji.

Aby upewnić się, że aplikacja obsługuje sporadyczne błędy i że dane są utrwalane, należy użyć strategii ponawiania z wycofywaniem. Domyślne zasady ponawiania używane przez bibliotekę klienta usługi Azure Storage mają wycofywanie wykładnicze, które pozwala uniknąć kolizji i maksymalizować przepływność aplikacji.