Zagadnienia dotyczące kodowania komunikatów
Wiele aplikacji w chmurze używa komunikatów asynchronicznych do wymiany informacji między składnikami systemu. Ważnym aspektem obsługi komunikatów jest format używany do kodowania danych ładunku. Po wybraniu technologii obsługi komunikatównastępnym krokiem jest zdefiniowanie sposobu kodowania komunikatów. Dostępnych jest wiele opcji, ale odpowiedni wybór zależy od przypadku użycia.
W tym artykule opisano niektóre zagadnienia.
Wymagania dotyczące wymiany komunikatów
Wymiana komunikatów między producentem a konsumentem wymaga:
- Kształt lub struktura definiująca ładunek komunikatu.
- Format kodowania reprezentujący ładunek.
- Biblioteki serializacji do odczytu i zapisu zakodowanego ładunku.
Producent komunikatu definiuje kształt komunikatu na podstawie logiki biznesowej i informacji, które chce wysyłać do odbiorców. Aby określić strukturę kształtu, podziel informacje na odrębne lub powiązane tematy (pola). Zdecyduj, jakie są cechy wartości dla tych pól. Rozważmy: Jaki jest najbardziej wydajny typ danych? Czy ładunek zawsze będzie miał pewne pola? Czy ładunek będzie miał jeden rekord czy powtarzający się zestaw wartości?
Następnie wybierz format kodowania w zależności od potrzeb. Niektóre czynniki obejmują możliwość tworzenia wysoce ustrukturyzowanych danych, jeśli są one potrzebne, czas potrzebny na kodowanie i przesyłanie komunikatu oraz możliwość analizowania ładunku. W zależności od formatu kodowania wybierz bibliotekę serializacji, która jest dobrze obsługiwana.
Odbiorca wiadomości musi być świadomy tych decyzji, aby wiedzieć, jak odczytywać komunikaty przychodzące.
Aby przenieść komunikaty, producent serializuje komunikat do formatu kodowania. Po stronie odbiorcy konsument deserializuje ładunek, aby wykorzystać dane. W ten sposób obie jednostki współdzielą model i tak długo, jak kształt nie ulegnie zmianie, obsługa komunikatów będzie kontynuowana bez problemów. Po zmianie kontraktu format kodowania powinien być w stanie obsługiwać zmianę, nie zakłócając działania konsumenta.
Niektóre formaty kodowania, takie jak JSON, opisują się samodzielnie, co oznacza, że można je analizować bez odwoływania się do schematu. Jednak takie formaty zwykle dają większe komunikaty. W przypadku innych formatów dane mogą nie być analizowane tak łatwo, ale komunikaty są kompaktowe. W tym artykule wyróżniono niektóre czynniki, które mogą pomóc w wyborze formatu.
Zagadnienia dotyczące formatu kodowania
Format kodowania definiuje sposób, w jaki zestaw danych strukturalnych jest reprezentowany jako bajty. Typ komunikatu może mieć wpływ na wybór formatu. Komunikaty związane z transakcjami biznesowymi najprawdopodobniej będą zawierać wysoce ustrukturyzowane dane. Ponadto możesz pobrać go później na potrzeby inspekcji. W przypadku strumienia zdarzeń możesz chcieć odczytać sekwencję rekordów tak szybko, jak to możliwe i zapisać je do analizy statystycznej.
Poniżej przedstawiono kilka kwestii, które należy wziąć pod uwagę podczas wybierania formatu kodowania.
Czytelność człowieka
Kodowanie komunikatów może być szeroko podzielone na formaty tekstowe i binarne.
W przypadku kodowania opartego na tekście ładunek komunikatu jest w postaci zwykłego tekstu i dlatego może być sprawdzany przez osobę bez używania żadnych bibliotek kodu. Formaty czytelne dla człowieka są odpowiednie dla danych archiwalnych. Ponadto, ponieważ człowiek może odczytać ładunek, formaty oparte na tekście są łatwiejsze do debugowania i wysyłania do dzienników w celu rozwiązywania problemów z błędami.
Wadą jest to, że ładunek jest zwykle większy. Typowy format tekstowy to JSON.
Szyfrowanie
Jeśli w komunikatach znajdują się poufne dane, należy rozważyć, czy te komunikaty powinny być szyfrowane w całości zgodnie z opisem w wskazówkach dotyczących szyfrowania danych usługi Azure Service Bus w stanie spoczynku. Alternatywnie, jeśli tylko niektóre pola muszą być zaszyfrowane i chcesz zmniejszyć koszty chmury, rozważ użycie biblioteki, takiej jak NServiceBus.
Rozmiar kodowania
Rozmiar komunikatu ma wpływ na wydajność we/wy sieci przez przewody. Formaty binarne są bardziej kompaktowe niż formaty tekstowe. Formaty binarne wymagają bibliotek serializacji/deserializacji. Nie można odczytać ładunku, chyba że został zdekodowany.
Użyj formatu binarnego, jeśli chcesz szybciej zmniejszyć zużycie przewodu i przesyłać komunikaty. Ta kategoria formatu jest zalecana w scenariuszach, w których problemem jest przepustowość magazynu lub sieci. Opcje formatów binarnych obejmują Apache Avro, Google Protocol Buffers (protobuf), MessagePack i Concise Binary Object Representation (CBOR). Zalety i wady tych formatów opisano w tej sekcji.
Wadą jest to, że ładunek nie jest czytelny dla człowieka. Większość formatów binarnych używa złożonych systemów, które mogą być kosztowne do utrzymania. Ponadto potrzebują wyspecjalizowanych bibliotek do dekodowania, które mogą nie być obsługiwane, jeśli chcesz pobrać dane archiwalne.
Opis ładunku
Ładunek komunikatu jest dostarczany jako sekwencja bajtów. Aby przeanalizować tę sekwencję, użytkownik musi mieć dostęp do metadanych opisujących pola danych w ładunku. Istnieją dwa główne podejścia do przechowywania i dystrybucji metadanych:
otagowane metadane. W niektórych kodowaniu, zwłaszcza w formacie JSON, pola są oznaczone typem danych i identyfikatorem w treści komunikatu. Te formaty są samoopisujące, ponieważ można je przeanalizować w słowniku wartości bez odwoływania się do schematu. Jednym ze sposobów zrozumienia pól przez konsumenta jest wykonywanie zapytań o oczekiwane wartości. Na przykład producent wysyła ładunek w formacie JSON. Odbiorca analizuje dane JSON w słowniku i sprawdza istnienie pól, aby zrozumieć ładunek. Innym sposobem jest zastosowanie przez konsumenta modelu danych współużytkowanego przez producenta. Jeśli na przykład używasz statycznie typizowanego języka, wiele bibliotek serializacji JSON może przeanalizować ciąg JSON w klasie typizowanej.
schema. Schemat formalnie definiuje strukturę i pola danych komunikatu. W tym modelu producent i konsument mają umowę za pomocą dobrze zdefiniowanego schematu. Schemat może definiować typy danych, wymagane/opcjonalne pola, informacje o wersji i strukturę ładunku. Producent wysyła ładunek zgodnie ze schematem modułu zapisywania. Odbiorca odbiera ładunek, stosując schemat czytnika. Komunikat jest serializowany/deserializowany przy użyciu bibliotek specyficznych dla kodowania. Istnieją dwa sposoby dystrybucji schematów:
Zapisz schemat jako preambuł lub nagłówek w komunikacie, ale oddzielony od ładunku.
Przechowuj schemat zewnętrznie.
Niektóre formaty kodowania definiują schemat i używają narzędzi, które generują klasy na podstawie schematu. Producent i konsument używają tych klas i bibliotek do serializacji i deserializacji ładunku. Biblioteki zapewniają również kontrole zgodności między schematem zapisu a schematem odczytu. Zarówno protobuf, jak i Apache Avro są zgodne z tym podejściem. Kluczową różnicą jest to, że protobuf ma niezależną od języka definicję schematu, ale Avro używa kompaktowego kodu JSON. Inną różnicą jest sposób, w jaki oba formaty zapewniają sprawdzanie zgodności między schematami odczytującym a zapisującym.
Innym sposobem przechowywania schematu zewnętrznie w rejestrze schematów. Komunikat zawiera odwołanie do schematu i ładunku. Producent wysyła identyfikator schematu w komunikacie, a użytkownik pobiera schemat, określając ten identyfikator z magazynu zewnętrznego. Obie strony używają biblioteki specyficznej dla formatu do odczytywania i zapisywania komunikatów. Oprócz przechowywania schematu rejestr może zapewnić sprawdzanie zgodności, aby upewnić się, że umowa między producentem a konsumentem nie jest uszkodzona, ponieważ schemat ewoluuje.
Przed wybraniem podejścia zdecyduj, co jest ważniejsze: rozmiar transferu danych lub możliwość analizowania zarchiwizowanych danych później.
Przechowywanie schematu wraz z ładunkiem daje większy rozmiar kodowania i jest preferowane dla sporadycznych komunikatów. Wybierz to podejście, jeśli przenoszenie mniejszych fragmentów bajtów ma kluczowe znaczenie lub oczekujesz sekwencji rekordów. Koszt utrzymania zewnętrznego magazynu schematów może być wysoki.
Jeśli jednak dekodowanie ładunku na żądanie jest ważniejsze niż jego rozmiar, dołączenie schematu do ładunku lub podejście oparte na oznakowanych metadanych gwarantuje późniejsze dekodowanie. Może wystąpić znaczny wzrost rozmiaru komunikatów i może mieć wpływ na koszt magazynu.
Wersjonowanie schematu
W miarę zmiany wymagań biznesowych oczekuje się, że kształt zmieni się, a schemat będzie się zmieniał. Przechowywanie wersji umożliwia producentowi wskazanie aktualizacji schematu, które mogą obejmować nowe funkcje. Istnieją dwa aspekty przechowywania wersji:
Użytkownik powinien mieć świadomość zmian.
Jednym ze sposobów jest sprawdzenie wszystkich pól przez odbiorcę w celu określenia, czy schemat został zmieniony. Innym sposobem jest opublikowanie przez producenta numeru wersji schematu z komunikatem. Gdy schemat ewoluuje, producent zwiększa wersję.
Zmiany nie mogą wpływać na logikę biznesową konsumentów ani jej naruszać.
Załóżmy, że pole zostało dodane do istniejącego schematu. Jeśli użytkownicy korzystający z nowej wersji otrzymają dane zgodnie ze starą wersją, ich logika działania może ulec zakłóceniu, jeśli nie będą w stanie zignorować braku nowego pola. Biorąc pod uwagę odwrotny przypadek, załóżmy, że pole zostało usunięte w nowym schemacie. Użytkownicy używający starego schematu mogą nie być w stanie odczytać danych.
Formaty kodowania, takie jak Avro, oferują możliwość definiowania wartości domyślnych. W poprzednim przykładzie, jeśli pole zostanie dodane z wartością domyślną, brakujące pole zostanie wypełnione wartością domyślną. Inne formaty, takie jak protobuf, zapewniają podobne funkcje za pośrednictwem wymaganych i opcjonalnych pól.
Struktura ładunku
Rozważ sposób rozmieszczania danych w ładunku. Czy jest to sekwencja rekordów, czy odrębny pojedynczy ładunek? Struktura ładunku można podzielić na jeden z następujących modeli:
Tablica/słownik/wartość: definiuje wpisy, które przechowują wartości w jednej lub wielowymiarowej tablicy. Wpisy mają unikatowe pary klucz-wartość. Można ją rozszerzyć, aby reprezentować złożone struktury. Niektóre przykłady to: JSON, Apache Avro i MessagePack.
Ten układ jest odpowiedni, jeśli komunikaty są kodowane indywidualnie przy użyciu różnych schematów. Jeśli masz wiele rekordów, dane mogą stać się nadmiarowe, powodując ich puchnięcie.
Dane tabelaryczne: informacje są podzielone na wiersze i kolumny. Każda kolumna wskazuje pole lub temat informacji, a każdy wiersz zawiera wartości dla tych pól. Ten układ jest wydajny w przypadku powtarzającego się zestawu informacji, takich jak dane szeregów czasowych.
CSV jest jednym z najprostszych formatów opartych na tekście. Przedstawia dane jako sekwencję rekordów ze wspólnym nagłówkiem. W przypadku kodowania binarnego apache Avro ma preambułę podobną do nagłówka CSV, ale generuje kompaktowy rozmiar kodowania.
Obsługa bibliotek
Rozważ użycie dobrze znanych formatów zamiast modelu zastrzeżonego.
Dobrze znane formaty są obsługiwane przez biblioteki, które są powszechnie obsługiwane przez społeczność. W przypadku wyspecjalizowanych formatów potrzebne są określone biblioteki. Logika biznesowa może potrzebować obejścia niektórych opcji projektowania interfejsu API udostępnianych przez biblioteki.
W przypadku formatu opartego na schemacie wybierz bibliotekę kodowania, która umożliwia sprawdzanie zgodności między schematem czytnika i modułu zapisywania. Niektóre biblioteki kodowania, takie jak Apache Avro, oczekują, że odbiorca określi zarówno schemat zapisu, jak i schemat odczytu przed deserializacją komunikatu. Ta kontrola zapewnia, że odbiorca zna wersje schematu.
Współdziałanie
Wybór formatów może zależeć od konkretnego obciążenia lub ekosystemu technologii.
Na przykład:
Usługa Azure Stream Analytics ma natywną obsługę plików JSON, CSV i Avro. W przypadku korzystania z usługi Stream Analytics warto wybrać jeden z tych formatów, jeśli to możliwe. Jeśli nie, możesz podać niestandardowy deserializator, ale to dodatkowo komplikuje Twoje rozwiązanie.
JSON to standardowy format wymiany dla interfejsów API REST PROTOKOŁU HTTP. Jeśli aplikacja odbiera ładunki JSON od klientów, a następnie umieszcza je w kolejce komunikatów na potrzeby przetwarzania asynchronicznego, warto użyć kodu JSON do obsługi komunikatów, a nie ponownie zakodować w innym formacie.
Są to tylko dwa przykłady zagadnień dotyczących współdziałania. Ogólnie rzecz biorąc, standardowe formaty będą bardziej współdziałać niż formaty niestandardowe. W opcjach opartych na tekście kod JSON jest jednym z najbardziej współdziałalnych.
Opcje formatów kodowania
Oto kilka popularnych formatów kodowania. Przed wybraniem formatu należy uwzględnić zagadnienia.
JSON
JSON to otwarty standard (IETF RFC8259). Jest to format oparty na tekście, który jest zgodny z modelem tablicy/słownika/wartości.
Kod JSON może służyć do tagowania metadanych i można przeanalizować ładunek bez schematu. Kod JSON obsługuje opcję określania pól opcjonalnych, które ułatwiają zgodność z poprzednimi wersjami i przyszłymi wersjami.
Największą zaletą jest to, że jest powszechnie dostępna. Jest najbardziej interoperacyjny i domyślny format kodowania dla wielu usług przesyłania wiadomości.
Będąc formatem opartym na tekście, nie jest wydajny przy przesyłaniu i nie jest idealnym wyborem w przypadkach, gdy ważna jest oszczędność miejsca. Jeśli zwracasz buforowane elementy bezpośrednio do klienta za pośrednictwem protokołu HTTP, przechowywanie danych JSON może obniżyć koszt deserializacji z innego formatu, a następnie serializowania do formatu JSON.
Użyj formatu JSON dla komunikatów z pojedynczym rekordem lub dla sekwencji komunikatów, w których każdy komunikat ma inny schemat. Unikaj używania formatu JSON dla sekwencji rekordów, takich jak dane szeregów czasowych.
Istnieją inne odmiany kodu JSON, takie jak binarny kod JSON (BSON), który jest kodowaniem binarnym dopasowanym do pracy z bazą danych MongoDB.
wartości Comma-Separated (CSV)
CSV to format tabelaryczny oparty na tekście. Nagłówek tabeli wskazuje pola. Jest to preferowany wybór, w którym komunikat zawiera zestaw rekordów.
Wadą jest brak standaryzacji. Istnieje wiele sposobów wyrażania separatorów, nagłówków i pustych pól.
Protocol Buffers (protobuf)
Protokoły Buffers (lub protobuf) to jest format serializacji, który używa silnie typizowanych plików definicji do definiowania schematów w parach klucz/wartość. Te pliki definicji są następnie kompilowane do klas specyficznych dla języka, które są używane do serializacji i deserializacji komunikatów.
Komunikat zawiera skompresowany mały ładunek binarny, co skutkuje szybszym transferem. Wadą jest to, że ładunek nie jest czytelny dla człowieka. Ponadto ze względu na to, że schemat jest zewnętrzny, nie zaleca się pobierania zarchiwizowanych danych.
Apache Avro
apache Avro to binarny format serializacji, który używa pliku definicji podobnego do protobuf, ale nie ma kroku kompilacji. Zamiast tego serializowane dane zawsze zawierają preambuły schematu.
Preambuła może zawierać nagłówek lub identyfikator schematu. Ze względu na mniejszy rozmiar kodowania firma Avro jest zalecana w przypadku danych przesyłanych strumieniowo. Ponadto, ponieważ ma nagłówek, który ma zastosowanie do zestawu rekordów, jest dobrym wyborem dla danych tabelarycznych.
MessagePack
MessagePack to format binarnej serializacji, który jest zaprojektowany jako kompaktowy przy przesyłaniu danych przez sieć. Nie ma schematów komunikatów ani sprawdzania typów komunikatów. Ten format nie jest zalecany w przypadku magazynu zbiorczego.
CBOR
Zwięzła reprezentacja obiektów binarnych (CBOR) (Specyfikacja) to format binarny, który oferuje mały rozmiar kodowania. Zaletą CBOR w porównaniu do MessagePack jest to, że jest zgodny z IETF w dokumencie RFC7049.