Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Muitos aplicativos de nuvem usam mensagens assíncronas para trocar informações entre componentes do sistema. Um aspecto importante do sistema de mensagens é o formato usado para codificar os dados de conteúdo. Depois que você escolher uma tecnologia de sistema de mensagens, a próxima etapa será definir como as mensagens serão codificadas. Há muitas opções disponíveis, mas a escolha certa depende do seu caso de uso.
Este artigo descreve algumas dessas considerações.
Necessidades de troca de mensagens
Uma troca de mensagens entre um produtor e um consumidor precisa do seguinte:
- Uma forma ou uma estrutura que define o conteúdo da mensagem.
- Um formato de codificação para representar a carga útil.
- Bibliotecas de serialização para ler e gravar o conteúdo codificado.
O produtor da mensagem define a forma da mensagem com base na lógica de negócios e nas informações que deseja enviar aos consumidores. Para estruturar a forma, divida as informações em assuntos discretos ou relacionados (ou campos). Decida as características dos valores para esses campos. Considere as perguntas a seguir.
- Qual é o tipo de dados mais eficiente?
- O conteúdo sempre tem campos específicos?
- O conteúdo tem um único registro ou um conjunto repetido de valores?
Em seguida, escolha um formato de codificação, dependendo de suas necessidades. Fatores específicos incluem a capacidade de criar dados altamente estruturados se você precisar, o tempo necessário para codificar e transferir a mensagem e a capacidade de analisar a carga. Em seguida, escolha um formato de codificação que atenda às suas necessidades.
O consumidor deve entender essas decisões para ler corretamente as mensagens de entrada.
Para transferir mensagens, o produtor serializa a mensagem em um formato de codificação. No final do recebimento, o consumidor desserializa o conteúdo para acessar os dados. Esse processo garante que ambas as entidades compartilhem o mesmo modelo. Enquanto a forma permanecer inalterada, as mensagens continuarão sem problemas. Quando o contrato é alterado, o formato de codificação deve ter a capacidade de lidar com a alteração sem interromper o consumidor.
Alguns formatos de codificação, como JSON, são autodescrevendo, o que significa que eles podem ser analisados sem fazer referência a um esquema. No entanto, esses formatos geralmente produzem mensagens maiores. Outros formatos podem não analisar dados tão facilmente, mas resultam em mensagens mais compactas. Este artigo descreve os principais fatores para ajudá-lo a escolher o formato certo.
Considerações sobre o formato de codificação
O formato de codificação define como um conjunto de dados estruturados é representado como bytes. O tipo de mensagem pode influenciar a escolha do formato. As mensagens relacionadas a transações comerciais provavelmente contêm dados altamente estruturados. Além disso, talvez você queira recuperar os dados estruturados posteriormente para fins de auditoria. Para um fluxo de eventos, recomendamos ler uma sequência de registros o mais rápido possível e armazená-la para análise estatística.
Considere os seguintes fatores ao escolher um formato de codificação.
Capacidade de leitura humana
A codificação de mensagens pode ser amplamente dividida em formatos binários e baseados em texto.
Com a codificação baseada em texto, o conteúdo da mensagem está em texto sem formatação, para que uma pessoa possa inspecioná-la sem usar bibliotecas de código. Essa abordagem facilita a leitura e a compreensão dos dados. Formatos legíveis por humanos são adequados para dados de arquivamento. Como um humano pode ler a carga, os formatos baseados em texto são mais fáceis de depurar e enviar para logs para solucionar problemas de erros.
A desvantagem da codificação de texto é que a carga útil tende a ser maior. O tamanho da carga geralmente pode ser reduzido por meio de um processo de minificação, desde que possa ser revertido para a legibilidade humana quando necessário. Formatos comuns baseados em texto são JSON e YAML.
Criptografia
Se houver dados confidenciais nas mensagens, considere se essas mensagens devem ser criptografadas em sua totalidade. Como alternativa, se apenas campos específicos precisarem ser criptografados e você preferir reduzir os custos de nuvem, considere usar uma biblioteca como o NServiceBus.
Tamanho da codificação
O tamanho da mensagem afeta o desempenho de entrada/saída de rede em todo o fio. Os formatos binários são mais compactos do que os formatos baseados em texto. Formatos binários exigem bibliotecas de serialização e desserialização. A carga só pode ser lida quando decodificada.
Use um formato binário se quiser reduzir o volume de transmissão e transferir mensagens mais rapidamente. Essa categoria de formato é recomendada em cenários em que o armazenamento ou a largura de banda de rede é uma preocupação. As opções de formatos binários incluem o Apache Avro, os Buffers de Protocolo do Google (protobuf), o MessagePack e o CBOR (Representação Concisa de Objetos Binários). Os prós e contras desses formatos são descritos posteriormente em Opções para formatos de codificação.
A desvantagem do formato binário é que o conteúdo não é legível por humanos. A maioria dos formatos binários usa sistemas complexos que podem ter uma manutenção cara. Além disso, elas precisam de bibliotecas especializadas para decodificar, o que pode não ter suporte se você quiser recuperar dados de arquivamento.
Para formatos não binários, um processo de minificação remove espaços e caracteres desnecessários, preservando a conformidade com a especificação do formato. Essa abordagem ajuda a reduzir o tamanho da codificação sem alterar a estrutura. Avalie os recursos do codificador para tornar a minificação o padrão. Por exemplo, o JsonSerializerOptions.WriteIndented
do System.Text.Json.JsonSerializer
do .NET controla a minificação automática ao criar texto JSON.
Compreendendo a carga útil
Um conteúdo de mensagem chega como uma sequência de bytes. Para analisar essa sequência, o consumidor precisa ter acesso aos metadados que descrevem os campos de dados no conteúdo. As duas principais abordagens para armazenar e distribuir metadados são:
Metadados marcados. Em alguns formatos de codificação, notadamente JSON, os campos são marcados com o tipo de dados e o identificador, dentro do corpo da mensagem. Esses formatos são autodescritivos porque podem ser analisados em um dicionário de valores sem a necessidade de se referir a um esquema. Uma forma para o consumidor entender os campos é consultar os valores esperados. Por exemplo, o produtor envia carga em JSON. O consumidor analisará o JSON em um dicionário e verificará a existência de campos para entender o conteúdo. Outra maneira é o consumidor aplicar um modelo de dados que o produtor compartilha. Por exemplo, se você usar uma linguagem tipada estaticamente, muitas bibliotecas de serialização JSON poderão analisar uma cadeia de caracteres JSON em uma classe tipada.
Esquema. Um esquema define formalmente a estrutura e os campos de dados de uma mensagem. Nesse modelo, o produtor e o consumidor têm um contrato por meio de um esquema bem definido. O esquema pode definir os tipos de dados, os campos obrigatórios ou opcionais, as informações de versão e a estrutura do conteúdo. O produtor envia o conteúdo de acordo com o esquema do gravador. O consumidor recebe o conteúdo aplicando um esquema de leitor. A mensagem é serializada e desserializada usando as bibliotecas específicas de codificação. Esquemas podem ser distribuídos de duas maneiras:
Armazene o esquema como um preâmbulo ou cabeçalho na mensagem, mas separadamente do conteúdo.
Armazenar o esquema externamente.
Alguns formatos de codificação definem o esquema e usam ferramentas que geram classes com base no esquema. O produtor e o consumidor usam essas classes e bibliotecas para serializar e desserializar o conteúdo. As bibliotecas também fornecem verificações de compatibilidade entre o esquema de escritor e o esquema de leitura. O protobuf e o Apache Avro seguem essa abordagem. A principal diferença é que o protobuf tem uma definição de esquema independente de linguagem e o Avro usa JSON compacto. Outra diferença está na maneira como os dois formatos fornecem verificações de compatibilidade entre os esquemas de leitor e de autor.
Outra maneira de armazenar o esquema externamente é em um registro de esquema. A mensagem contém uma referência ao esquema e à carga útil. O produtor envia o identificador de esquema na mensagem. O consumidor recupera o esquema especificando esse identificador de um repositório externo. Ambas as partes usam uma biblioteca específica de formato para ler e gravar mensagens. Além de armazenar o esquema, um registro pode fornecer verificações de compatibilidade para garantir que o contrato entre o produtor e o consumidor não seja interrompido à medida que o esquema evolui.
Antes de escolher uma abordagem, decida se o tamanho dos dados de transferência ou a capacidade de analisar os dados arquivados posteriormente é mais importante.
Armazenar o esquema junto com a carga produz um tamanho de codificação maior e é ideal para mensagens intermitentes. Escolha essa abordagem se a transferência de partes menores de bytes for crucial ou se você esperar uma sequência de registros. O custo para manter um repositório de esquema externo pode ser alto.
No entanto, se a decodificação sob demanda do conteúdo for mais importante do que o tamanho, incluir o esquema com o conteúdo ou a abordagem de metadados marcados garantirá a decodificação posteriormente. Pode haver um aumento significativo no tamanho da mensagem que afeta o custo do armazenamento.
Versão de esquema
À medida que os requisitos de negócios mudam, é esperado que a forma mude e o esquema evolua. O controle de versão permite que o produtor indique as atualizações de esquema que possam incluir novos recursos. O controle de versão tem dois aspectos principais:
O consumidor deve acompanhar e entender as alterações.
Uma forma é que o consumidor verifique todos os campos para determinar se o esquema foi alterado. Outra maneira é que o produtor publique um número de versão de esquema com a mensagem. Quando o esquema evolui, o produtor incrementa a versão.
As alterações não devem afetar nem interromper a lógica de negócios dos consumidores.
Suponha que um campo seja adicionado a um esquema existente. Se os usuários que utilizam a nova versão receberem uma carga de acordo com a versão antiga, a sua lógica pode falhar se eles não puderem ignorar a ausência do novo campo. Agora considere o cenário oposto. Se um campo for removido no novo esquema, os consumidores que usam o esquema antigo poderão não conseguir ler os dados.
Formatos de codificação, como o Avro, fornecem a capacidade de definir valores padrão. No exemplo anterior, se o campo for adicionado com um valor padrão, o campo ausente será preenchido com o valor padrão. Outros formatos, como o protobuf, fornecem uma funcionalidade semelhante por meio de campos obrigatórios e opcionais.
Estrutura do conteúdo
Considere se os dados na carga são estruturados como uma sequência de registros ou como uma única carga discreta. A estrutura de carga útil pode ser categorizada em um dos seguintes modelos:
Matriz/dicionário/valor: Define entradas que contêm valores em uma ou múltiplas matrizes multidimensionais. As entradas têm pares chave/valor exclusivos. O modelo pode ser estendido para representar estruturas complexas. Alguns exemplos incluem JSON, Apache Avro e MessagePack.
Esse layout será adequado se as mensagens forem codificadas individualmente com esquemas diferentes. Se você tiver vários registros, a carga poderá ser excessivamente redundante. Essa redundância pode causar sobrecarga no conteúdo.
Dados tabulares: As informações são divididas em linhas e colunas. Cada coluna indica um campo ou o assunto das informações e cada linha contém valores para esses campos. Esse layout é eficiente para um conjunto repetido de informações, como dados de série temporal.
Comma-Separated Values (CSV) é um dos formatos mais simples baseados em texto. Ele apresenta os dados como uma sequência de registros com um cabeçalho comum. Para codificação binária, o Apache Avro tem um preâmbulo semelhante a um cabeçalho CSV, mas que gera um tamanho de codificação mais compacto.
Suporte à biblioteca
Você deve usar formatos bem conhecidos em vez de um modelo proprietário. Formatos conhecidos são apoiados por meio de bibliotecas que contam com suporte universal da comunidade. Com formatos especializados, você precisa ter bibliotecas específicas. Sua lógica de negócios pode precisar resolver algumas das escolhas de design de API fornecidas pelas bibliotecas.
Para um formato baseado em esquema, escolha uma biblioteca de codificação que faça verificações de compatibilidade entre o leitor e o esquema de gravador. Bibliotecas de codificação específicas, como Apache Avro, esperam que o consumidor especifique tanto o esquema de gravação quanto o de leitura antes de desserializar a mensagem. Essa verificação garante que o consumidor esteja ciente das versões de esquema.
Interoperabilidade
Sua escolha de formatos pode depender da carga de trabalho específica ou do ecossistema de tecnologia.
Por exemplo:
O Azure Stream Analytics tem suporte nativo para JSON, CSV e Avro. Quando sua carga de trabalho usa o Stream Analytics, faz sentido escolher um desses formatos.
O JSON é um formato de troca padrão para APIs REST HTTP. Se o aplicativo receber cargas JSON dos clientes e, em seguida, os colocar em uma fila de mensagens para processamento assíncrono, talvez faça sentido usar JSON para o sistema de mensagens em vez de codificar novamente em um formato diferente.
Esses são apenas dois exemplos de considerações sobre interoperabilidade. Formatos padronizados geralmente são mais interoperáveis do que formatos personalizados. Em opções baseadas em texto, o JSON é um dos mais interoperáveis.
Opções de formatos de codificação
Os seguintes formatos de codificação populares são usados para representação e transmissão de dados. Leve em conta as considerações antes de escolher um formato.
JSON
O JSON é um padrão aberto, com seu formato definido pela IETF (Internet Engineering Task Force) no RFC 8259. JSON é um formato baseado em texto que segue o modelo de matriz/dicionário/valor.
O JSON pode ser usado para marcar metadados e você pode analisar o conteúdo sem um esquema. O JSON dá suporte à opção de especificar campos opcionais, o que ajuda na compatibilidade com versões anteriores e futuras.
A maior vantagem é que ele está universalmente disponível. JSON é o formato de codificação mais interoperável e o padrão para muitos serviços de mensagens.
Como o JSON é um formato baseado em texto, ele não é eficiente na transmissão e não é ideal quando o armazenamento é uma preocupação. Use técnicas de minificação quando possível. Se você retornar itens armazenados em cache diretamente para um cliente por meio de HTTP, o armazenamento de JSON poderá economizar o custo de desserialização de outro formato e, em seguida, serializar para JSON.
Use o JSON para mensagens de registro único ou para uma sequência de mensagens em que cada mensagem tem um esquema diferente. Evite usar o JSON para uma sequência de registros, como para dados de série temporal.
Há outras variações de JSON, como BSON (binário). BSON é uma codificação binária alinhada para trabalhar com o MongoDB.
CSV
O CSV é um formato de tabela baseado em texto. O cabeçalho da tabela indica os campos. O CSV é adequado para mensagens que contêm um conjunto de registros.
A desvantagem do CSV é a falta de padronização. Há várias maneiras de expressar separadores, cabeçalhos e campos vazios.
Buffers de protocolo
Protocol Buffers (ou protobuf) é um formato de serialização que usa arquivos de definições fortemente tipadas para definir esquemas em pares de chave/valor. Em seguida, esses arquivos de definição são compilados em classes específicas de linguagem que são usadas para serializar e desserializar as mensagens.
A mensagem contém uma carga binária pequena e compactada, que resulta em uma transferência de dados mais rápida. A desvantagem é que a carga não é legível por humanos. Além disso, como o esquema é armazenado externamente, esse formato não é ideal para cenários que exigem que você recupere dados arquivados.
Apache Avro
O Apache Avro é um formato de serialização binária que usa um arquivo de definição semelhante ao protobuf, mas sem uma etapa de compilação. Em vez disso, os dados serializados sempre incluem um preâmbulo de esquema.
O preâmbulo pode conter o cabeçalho ou um identificador de esquema. Devido ao seu tamanho de codificação menor, o Avro é recomendado para transmitir dados. Além disso, como ele tem um cabeçalho que se aplica a um conjunto de registros, ele é adequado para dados tabulares.
Apache Parquet
Apache Parquet é um formato de arquivo de armazenamento columnar normalmente associado ao Apache Hadoop e estruturas de processamento de dados relacionadas.
O Apache Parquet dá suporte à compactação de dados e tem recursos limitados para evolução do esquema. Esse formato normalmente é usado quando outras tecnologias de Big Data em sua carga de trabalho exigem isso para criação ou consumo de dados.
MessagePack
MessagePack é um formato de serialização binária projetado para ser compacto para transmissão pelo fio. MessagePack não tem definição de esquema e verificação de tipo. Esse formato não é recomendado para o armazenamento em massa.
CBOR
CBOR (Especificação) é um formato binário que fornece um tamanho de codificação pequeno. A vantagem de usar CBOR sobre MessagePack é sua conformidade com o IETF em RFC7049.