C# — Utilizando MessagePack com Redis

Elvis Fernandes Dias
5 min readSep 12, 2022

--

Antes de iniciarmos quero especificar aqui o que estou utilizando para o desenvolvimento desse artigo.
Como cache distribuído, estou utilizando redis, sendo executado em container com a imagem oficial, conforme comando abaixo:

Como Redis client, gosto de utilizar o “Another Redis Desktop Manager”, https://github.com/qishibo/AnotherRedisDesktopManager/

A implementação foi realizada com dotnet core 6, utilizando os pacotes listados aqui:

  • MessagePack — 2.4.35
  • StackExchange.Redis — 2.6.48

Para teste de carga utilizei a ferramenta K6 https://k6.io/

Agora vamos ao que importa!

Grande parte das implementações de cache distribuído que já tive contato faz uso da estratégia de serializar em JSON o objeto que se deseja inserir no cache, e a string resultante da serialização é enviada para o cache distribuído, conforme exemplo abaixo, mais especificamente nas linhas 25 e 30.

Essa estratégia funciona bem, mas o que podemos fazer quando precisamos reduzir o consumo de espaço no cache? Ou quando a quantidade de dados trafegados entre a aplicação e o cache é um problema? Por exemplo, o objeto User descrito no código acima ocupa 182 bytes no cache:

E o espaço total utilizado pelo item (estimado), incluindo dados para seu gerenciamento, é de 248 bytes, conforme exibido pelo comando “MEMORY USAGE”, .

Quais seriam as possibilidades para tentar reduzir o espaço utilizado no cache e não ter grandes alterações na aplicação?

Para essa redução de espaço podemos pensar em algumas possibilidades:

  • reduzir as informações salvas, por exemplo, salvando objetos menores, sendo necessário realizar uma análise de quais informações são realmente necessárias de estarem no cache;
  • utilização de outros tipos de dados do redis, como Hash ou List, verificando se esses “data types” são mais adequados para salvar o objeto em questão e se isso tem vantagens no seu contexto;
  • alterar a forma de serialização do objeto para algum mecanismo que gere os dados de forma mais compacta;

Neste artigo vamos abordar a estratégia de utilizarmos outro mecanismo de serialização, no caso o MessagePack.

MessagePack

É um formato de serialização binária, mais compacto que JSON. Por exemplo, o json abaixo tem 233 bytes, porém no formato MessagePack possui 158 bytes, 32% menor.

https://msgpack.org/index.html — Try!

Contudo, nem tudo são flores, pois o formato MessagePack possui algumas limitações, como por exemplo o tamanho de inteiros, que deve ser entre -(2⁶³) até (2⁶⁴)-1. Portanto é importante verificarmos outras informações relevantes sobre o formato nos endereços a seguir:

Comparando tamanho do cache

Agora vamos utilizar o formato MessagePack para armazenarmos os dados no cache distribuído e verificarmos o ganho que temos. Como informado no início do artigo, vamos utilizar o pacote nuget MessagePack, https://github.com/neuecc/MessagePack-CSharp

Para isso, primeiramente precisamos alterar a classe User inserindo alguns atributos utilizados no processo de serialização.

Necessitamos inserir o atributo “MessagePackObject” na definição da classe, e o atributo “Key” nas propriedades que devem ser serializadas. A utilização desses atributos pode ser minimizada, para isso verifique a documentação em https://github.com/neuecc/MessagePack-CSharp#object-serialization

Após as alterações, a classe User ficará como abaixo.

A implementação da API fica bem semelhante à implementação utilizando o JsonSerializer, apenas alterando o processo de serialização e desserialização que podemos observar nas linhas 25 e 30 do código abaixo.

Com essa alteração, o objeto User salvo no Redis passa de 182 bytes para 91 bytes, conforme imagem abaixo:

E o espaço total utilizado pelo item (estimado), sai de 248 bytes para 152 bytes.

Economizamos aproximadamente 60% de espaço no Redis.

Performance

Utilizei o K6 para realizar teste de carga e verificar se existe alguma diferença de desempenho entre as implementações.

Observei uma pequena vantagem para a implementação com o MessagePack, mas em alguns cenários a implementação com JSON foi mais rápida. Contudo esses testes não foram conclusivos, pois, como estamos reduzindo a quantidade de dados trafegados entre a aplicação e o cache e como o teste foi realizado num ambiente com todos os componentes rodando localmente, isso interfere nos resultados obtidos. Sendo assim é necessários a realização de mais testes num ambiente mais controlado.

Para os testes eu executei os scripts abaixo no K6:

Script para teste com JsonSerializer
Script para teste com MessagePack

Dois exemplos dos resultados obtidos:

Resultado do MessagePack
Resultado do JSON

Podemos observar que com 10 VUs (virtual users), foram realizadas 99.111 requisições em 30 segundos com a serialização com MessagePack, contra 87.348 utilizando a serialização com JSON. Mas repito, é necessário mais validações com um ambiente mais controlado, não em uma máquina com vários processos em execução que também podem impactar no resultado, como a minha.

Esses códigos estarão disponíveis no Github abaixo:

https://github.com/ElvisFDias/RedisMsgPackApi

Concluindo, MessagePack não é um tópico novo, mas acredito que vale a pena dar uma estudada e verificar em quais casos pode ser útil.

Espero ter contribuído um pouco, até mais!

--

--

Elvis Fernandes Dias

.Net Developer Graduado em Ciência da Computação e Pós Graduado em Engenharia de Software