Hub de Eventos com Redis

redis-300dpi

 

Motivação

Utilizar o Redis para armazenar e recuperar dados em memória para um cenário real e, utilizar os recursos de PUBLISH e SUBSCRIBE para comunicar assincronamente mensagens entre cliente e servidor, criando assim, um Hub de eventos.

 

O que é o Redis?

Redis, http://redis.io/, é uma estrutura de dados na memória, categorizado como banco de dados não relacional – NOSQL (Not Only SQL). Ele oferece suporte a estruturas como strings, hashes, lists, sets, sorted sets com intervalos de consultas, bitmaps, hyperloglogs e geospatial indexes. Oferece replicação nativa, scripts lua, LRU eviction, transações e diferentes níveis de persistência em disco.

Instalando e configurando

Para iniciar nosso artigo, vamos precisar instalar e configurar o Redis conforme os passos abaixo:

  1. Instalar o chocolatey;
  2. Instalar o Redis 64-bit com o chocolatey;
  3. Instalar e configurar o Redis Desktop Manager;
  4. Iniciar o Redis Server.

1. Instalando o chocolatey

Chocolatey é um gerenciador de pacotes para o Windows ele permite a instalação, configuração e atualizações de programas através de linha de comando. Para instalar o chocolatey abra o cmd.exe ou o powershell.exe com privilégios administrativos, e execute os comandos abaixo:

  • Instalando com o Cmd.exe
@powershell -NoProfile -ExecutionPolicy Bypass -Command “iex ((new-object net.webclient).DownloadString(‘https://chocolatey.org/install.ps1’))” && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
  • Instalando com o PowerShell.exe (Certifique-se que Get-ExecutionPolicy está pelo menos como RemoteSigned)
iex ((new-object net.webclient).DownloadString(‘https://chocolatey.org/install.ps1’))
  • Instalando com o PowerShell v3+ (Certifique-se que Get-ExecutionPolicy está pelo menos como RemoteSigned)
iwr https://chocolatey.org/install.ps1 -UseBasicParsing | iex

Caso tenha algum problema, pode encontrar maiores informações aqui (https://chocolatey.org/install)

 

2. Instalando o Redis com o chocolatey

Para instalar no Windows, vamos abrir o prompt escolhido para rodar o chocolatey, e digitar a linha abaixo.

C:\> choco install redis-64

Caso tenha algum problema, pode encontrar maiores informações aqui (https://chocolatey.org/packages/redis-64/)

 

3. Instalando o Redis Desktop Manager

Redis Desktop Manager é a ferramenta que iremos utilizar para verificar nossos registros no Redis.

A versão para Windows é encontrada no endereço: (https://redisdesktop.com/download).

Após baixar e instalar no padrão Windows. Next > Next > Finish. Temos esta tela.

RDM

Precisamos configurar o RDM para conectar no servidor do Redis local, iremos iniciar o server no próximo tópico. Mas já é possível deixar configurado o básico no nosso manager. Abaixo um exemplo simples de conexão local:

rdm-connection

 

4. Iniciando o Redis Server

O chocolatey instala todos os programas na pasta C:\ProgramData\chocolatey\lib. Para iniciarmos o servidor redis, vamos acessar a pasta é encontrado na pasta C:\ProgramData\chocolatey\lib\redis-64 e executar o arquivo redis-server.exe.

server-redis

Esta tela nos mostra que o server foi iniciado com sucesso.

 

Usando o armazenamento de memória do Redis

Nesse momento, vamos aprender a utilizar o básico de armazenamento com strings. Inserir, recuperar e deletar chaves no Redis, fazendo assim, um cache de chave/valor. Utilizando os comandos SET (inserir), GET (recuperar) e DEL (Deletar).

Existem outros comandos para manipulação de strings, porém neste momento vamos usar o básico para entender e resolver problemas reais. Todos os exemplos serão feitos no redis-cli.exe, que é o client do Redis no Windows e pode ser encontrado na mesma pasta onde está o redis-server.exe, C:\ProgramData\chocolatey\lib\redis-64.

 

Inserindo registro (SET)

Um bom exemplo para usar com o cache do Redis é quando você precisa usar um carrinho de compra em um e-commerce, ao adicionar os itens no carrinho, você pode adicionar os itens usando o Redis, vamos iniciar o redis-cli.exe e escrever o comando:

set caderno:hora-de-aventura 2000

127.0.0.1:6379> set caderno:hora-de-aventura 2000

OK

127.0.0.1:6379>

Após a execução do comando o Redis retorna um OK, isto quer dizer que o comando foi executado com sucesso e agora temos uma chave chamada “caderno:hora-de-aventura” com o valor “2000”, o valor passado representa R$ 20,00.

OBS .: Utilizar o “:” como delimitador de “namespace”, é bem comum no Redis, e após nosso comando, temos a seguinte imagem no RDM.

rdm-with-key

Você pode especificar para qual “banco” você quer enviar as informações, por padrão, o Redis põe no db0.

Ao lado da nossa chave, temos uma opção chamada TTL que quer dizer Time To Live. É o tempo para expirar a key, se quisermos inserir um registro com tempo para expirar podemos usar o SET com o comando EXPIRE, ou usar o SETEX [key] [tempo] “value”.

 

Expirando um registro usando Time To Live (TTL)

Quando usaríamos esse tempo para a chave expirar? Para não deixar um item no carrinho eternamente sem ação. Vamos então adicionar um outro produto no carrinho, porém desta vez, esse produto irá expirar em 180 segundos – 3 minutos.

127.0.0.1:6379> setex caderno:the-joker 180 2200

OK

127.0.0.1:6379>

Adicionamos um caderno, com nome “the joker” que irá expirar em 180 segundos.

the-joker-rdm

Para mais informações do comando, visite: (http://redis.io/commands/setex).

 

Recuperando registros

Estamos fazendo nossos exemplos todos pelo console do redis, conseguimos visualizar o que estamos inserindo, utilizando o RDM, porém podemos visualizar com o próprio client do redis, utilizando o comando GET.

127.0.0.1:6379> get caderno:hora-de-aventura

“2000”

127.0.0.1:6379>

Recebemos o valor “2000” da chave “caderno:hora-de-aventura”.

 

Deletando registros

Se você não criou uma chave com TTL, ainda assim é possível deletar ela, quando não servir mais pra você, evitando assim deixar registros desnecessários no redis.

127.0.0.1:6379> del caderno:hora-de-aventura

(integer) 1

127.0.0.1:6379>

O resultado “(integer) 1” significa que 1 registro foi alterado com o comando executado.

 

Outras palavras

O Redis oferece muitos outros comandos para manipulação de registros, para uma lista completa e para outros testes, sugiro a leitura da lista de comandos no próprio site do Redis (http://redis.io/commands).

 

Usando PUBLISH/SUBSCRIBE para criar nosso Hub de eventos

Agora que vem a cereja do bolo do artigo, como usar o Redis com Subscribe. O que nada mais é que usá-lo como message broker (https://en.wikipedia.org/wiki/Message_broker).

A abordagem que será mostrada aqui, nada mais é que a mesma do padrão Observer – também conhecido como Dependents Publish-Subscribe –, o que esse padrão faz?

Basicamente ele representa uma relação de 1-N (de um para muitos) entre objetos. Assim, quando um objeto altera o seu estado os objetos dependentes serão notificados/informados/avisados e atualizados de forma automática. O padrão possibilita que objetos sejam avisados da mudança de estado de outros eventos ocorrendo em outro objeto.

Podemos dizer de forma simples que o objetivo principal do padrão Observer é manter a consistência entre objetos relacionados sem criar um código fortemente acoplado.

Então já revemos o que é o padrão Observer, agora é simples pegar essa ideia e utilizar no Redis, pois o subscribe tem a mesma ideia do Observer.

Para trabalhar com o PubSub do Redis, temos os comandos: psubscribe, publish, punsubscribe, subscribe e unsubscribe. Vamos utilizar o PSUBSCRIBE e o PUBLISH.

Uma boa observação sobre psubscribe e subscribe é que o primeiro assina um canal a partir de um padrão, isto quer dizer que, ele faz assinaturas genéricas, aceitando caracteres coringas para nomes de canais. Já o subscribe aceita apenas nomes fixos de canais.

E como poderíamos usar isto em um cenário real? Uma resposta à esta pergunta seria um newsletter. Você pode disponibilizar newsletters específicas em seu site para o visitante ficar por dentro das notícias que você publica. Música, tecnologias, animais, quaisquer outras áreas que seu site possa ter e seu visitante queira ficar por dentro.

Vamos fazer alguns exemplos baseando-se em uma história para ficar mais simples o entendimento.

 

Assinando canais específicos

Visitando alguns fóruns, encontrei um site muito legal e decidi assinar os newletters de música e tecnologia, mesmo o site tendo outras áreas interessantes como “GothamCity” eu decidi escolher apenas música e tecnologia.

No nosso console eu digito a linha abaixo para assinar o canal de música.

127.0.0.1:6379> subscribe musica

Reading messages… (press Ctrl-C to quit)

1) “subscribe”

2) “musica”

3) (integer) 1

Podemos notar que o redis-cli fica esperando alguma coisa, isto se dá ao fato de que o Redis usa comunicação TCP. O client enviou uma resposta para o server e está esperando a resposta, essa resposta virá quando alguém publicar (PUBLISH) no canal de “musica”. Uma clássica comunicação por sockets.

Também assino o canal de tecnologia.

127.0.0.1:6379> subscribe tecnologia

Reading messages… (press Ctrl-C to quit)

1) “subscribe”

2) “tecnologia”

3) (integer) 1

Com isso, eu estou esperando mensagens dos canais: “musica” e “tecnologia”, enquanto isso, soube que o Jack Napier começou a se interessar pela vida do Batman, então ele assinou o canal GothamCity para saber o que tem acontecido na cidade.

127.0.0.1:6379> subscribe gothamCity

Reading messages… (press Ctrl-C to quit)

1) “subscribe”

2) “gothamCity”

3) (integer) 1

 

Assinando todos os canais

Como esse nome não era estranho, descobri que Jack é o alter ego do Coringa e com isso descobri que ele não se contentou em ficar ouvindo apenas o que passa em Gotham e quis saber tudo que o site oferece, então ele assinou para ouvir tudo que vem do site, com isso ele usou o psubscribe *.

127.0.0.1:6379> psubscribe *

Reading messages… (press Ctrl-C to quit)

1) “psubscribe”

2) “*”

3) (integer) 1

 

Publicando mensagens

O PUBLISH não faz ideia de quem vai receber o que ele envia, ele apenas, envia. E com essa ideia, vamos enviar para os canais que conhecemos. Que são: musica, tecnologia e gothamCity.

127.0.0.1:6379> publish musica “stompin’ at the savoy – Jim Hall”

(integer) 2

127.0.0.1:6379>

O resultado foi “(integer) 2”, o redis-cli nos informa que 2 assinantes receberam essa mensagem.

Quem assinou o canal de “musica” – no caso, eu.

jim-hall

E quem usou o psubscribe para ouvir tudo – no caso, o coringa.

jim-hall-2

Publicando para o canal de tecnologia.

127.0.0.1:6379> publish tecnologia “Hub de eventos com Redis”

(integer) 2

127.0.0.1:6379>

Novamente 2 assinantes recebem a mensagem, tecnologia.

hub-de-eventos-redis

E o canal que escuta tudo.

hub-de-eventos-redis-2

Publicando para o canal de GothamCity.

127.0.0.1:6379> publish gothamCity “Gotham esta em paz”

(integer) 2

127.0.0.1:6379>

O canal de Gotham recebe a mensagem, aqui o coringa lê a mensagem por dois lugares, pelo canal específico – GothamCity.

gotham

E pelo canal que escuta tudo.

gotham-2

E se houver alguma publicação para um canal que ninguém assinou?

127.0.0.1:6379> publish MundiPagg “Converta mais e aumente as vendas do seu e-commerce”

(integer) 1

127.0.0.1:6379>

Apenas um canal é capaz de ouvir a mensagem.

mundi

Assim descobrimos como utilizar o recurso de PubSub do Redis, utilizando apenas a linha de comando. Abaixo segue alguns exemplos de código que automatizam nossos exemplos acima, tanto com cache, quanto com o PubSub.

 

Escrevendo o código

Para nosso console, vamos precisar de um client para usar no Visual Studio, vamos usar o RedisBoost (https://github.com/andrew-bn/RedisBoost).

Preparando o Visual Studio

  • File > New > Project > Console Application;
  • Instalar o RedisBoost pelo nuget
    • (PM> Install-Package RedisBoost).

 

ConnectionString

<connectionStrings>

<add name=”Redis” connectionString=”data source=localhost:6379;initial catalog=0″ />

</connectionStrings>

 

Código Redis com Cache

 // Redis com cache
 private static void RedisCache(string connectionString) {
 using (var pool = RedisClient.CreateClientsPool()) {
 IRedisClient redisClient;

 // Chave
 var cadernoHoraDeAventura = "caderno:hora-de-aventura";
 var cadernoTheJoker = "caderno:the-joker";

 // Cria o client
 using (redisClient = pool.CreateClientAsync(connectionString).Result) {
 // Faz de forma assincrona o inserir no Redis
 redisClient.SetAsync(cadernoHoraDeAventura, "2000").Wait();
 Console.WriteLine("Item {0} adicionado com sucesso ao carrinho!", cadernoHoraDeAventura);

 // Get Item
 var redisHoraDeAventura = redisClient.GetAsync(cadernoHoraDeAventura).Result.As<string>();
 Console.WriteLine("Valor {0} do item {1}.", redisHoraDeAventura, cadernoHoraDeAventura);

 // Deletando a chave
 var resultHoraDeAventuraDelete = redisClient.DelAsync(cadernoHoraDeAventura).Result;
 Console.WriteLine("Chave {0} foi deletada? {1}", cadernoHoraDeAventura, Convert.ToBoolean(resultHoraDeAventuraDelete));

 // Inserindo
 redisClient.SetAsync(cadernoTheJoker, "2200").Wait();
 Console.WriteLine("Item {0} adicionado com sucesso ao carrinho!", cadernoTheJoker);

 // Get Item
 var redisTheJoker = redisClient.GetAsync(cadernoTheJoker).Result.As<string>();
 Console.WriteLine("Valor {0} do item {1}.", redisTheJoker, cadernoTheJoker);

 // Adicionando o tempo para expirar no caderno:the-joker
 redisClient.ExpireAsync(cadernoTheJoker, 180);
 Console.WriteLine("Chave {0} com TTL de 180 segundos.", cadernoTheJoker);
 Console.Read();
 }
 }
 }

Resultado

resultado-1

 

Código Redis com Subscribe

 // Redis com PubSub
 private static void RedisPubSub(string connectionString, string channel) {
 using (var pool = RedisClient.CreateClientsPool()) {
 IRedisClient redisClient;

 // Cria o client
 using (redisClient = pool.CreateClientAsync(connectionString).Result) {
 // Usando o PSubscribe para escutar canais específicos e genéricos
 using (var subscriber = redisClient.PSubscribeAsync(channel).Result) {

 Console.WriteLine("Ouvindo o canal {0}", channel);

 // Obtendo a primeira mensagem do canal, utilizando o subscriber
 var channelMessage = subscriber.ReadMessageAsync(ChannelMessageType.Message | ChannelMessageType.PMessage).Result;

 // Se não tiver nenhuma mensagem, fica esperando
 while (channelMessage.Value.As<string>() != null) {
 var messageFomChannel = channelMessage.Value.As<string>();
 Console.WriteLine("Mensagem: {0}", messageFomChannel);
 channelMessage = subscriber.ReadMessageAsync(ChannelMessageType.Message | ChannelMessageType.PMessage).Result;
 }
 }
 }
 }
 }

Ao iniciar o console do subscribe, devemos escrever qual canal ele vai ouvir, com isso podemos abrir quantos canais quisermos, para seguir com os mesmos exemplos acima, vamos iniciar quatro instâncias com os mesmos nomes dos canais acima.

Canal de música

canal-musica

 

Canal de tecnologia

canal-tecnologia

 

Canal de GothamCity

canal-gotham

 

Canal Genérico

canal-generico

 

Código Redis com Publisher

 private static void RedisPublisher(string connectionString) {
 using (var pool = RedisClient.CreateClientsPool()) {
 IRedisClient redisClient;

 // Cria o client
 using (redisClient = pool.CreateClientAsync(connectionString).Result) {

 string[] channels = { "musica", "tecnologia", "gothamCity", "MundiPagg" };
 string[] messages = { "stompin' at the savoy - Jim Hall", "Hub de eventos com Redis",
 "Gotham esta em paz", "Converta mais e aumente as vendas do seu e-commerce" };


 // Publicando mensagens para os canais do array
 for (int i = 0; i < channels.Length; i++) {
 Console.WriteLine("Publicando no canal {0} a mensagem {1}", channels[i], messages[i]);
 redisClient.PublishAsync(channels[i], messages[i]).Wait();
 }

 Console.WriteLine("Mensagens enviadas! :)");
 Console.Read();

 }
 }
 }
 }

Resultado da publicação

O código acima publica as mensagens nos respectivos subscribes, o resultado final é este.

Publisher

resultado-publicacao

 

Subscribes

subscribes

 

O Redis tem muitos recursos legais que podem e devem ser explorados, os exemplos e explicações são simples, porém, traçam um caminho para você começar a usar essa ferramenta incrível. Para outros exemplos, acessem o link no final do artigo.

E assim finalizo e espero ter explicado de forma simples, clara e objetiva como utilizar o Redis como um hub de eventos. Mostrando a ideia e como utiliza-lo como cache e o principal, como usar o subscribe dele. Qualquer dúvida, crítica ou sugestão, sinta-se à vontade para entrar em contato.

Até a próxima! 🙂

 

Informações do Autor

Autor
Charles Lomboni
Desenvolvedor .NET na MundiPagg

Desenvolvedor .NET e SharePoint, entusiasta por segurança, tecnologias e música. Desde 2009 vem adquirindo experiência em diversos desafios. Reconhecido por alguns prêmios como o Jaccques Franquelin Award 2013, com o sistema Techchannel, um “youtube” para ensino, feito em Sharepoint. Atualmente faz parte do time Authorizer da MundiPagg/Stone, onde se diverte todo dia programando.

Fontes do artigo:

Contatos:

  • Twitter: @charleslomboni
  • Skype: charleslomboni
  • E-mail: charleslomboni@gmail.com / clomboni@stone.com.br

Referências:

Publicado em agosto 12, 2016, em C#, Outros e marcado como , , , , , , . Adicione o link aos favoritos. 2 Comentários.

Deixe um comentário