Redis and

NATS Streaming

Índice

  • Sistema monolítico vs distribuído 
  • Troca de dados
  • Brokers
  • NATS
  • Bancos de Dados
  • SQL vs No-SQL
  • Redis
  • Conclusão e Referências

Sistema Monolítico

  • Várias threads
  • Variáveis globais
  • Um único BD
     

Desvantagens:

  • Difícil de versionar
  • Compartilhamento de recursos

Sistema

BD

Sistema distribuído

  • Contêineres Docker
  • Uso de recursos distintos 


Conexão entre contêineres:

  • Identificação de cada parte para comunicação
  • Topologia de comunicação fixa

Comunicação Síncrona

  • Ideal para comunicação externa ( e. g. GraphQL, REST, etc)
  • Comunicação interna síncrona = sistema acoplado
  • Cascata de falhas

Comunicação Assíncrona

  • Sem necessidade de resposta imediada
  • Sistema desacoplado
  • Maior flexibilidade para cada parte responder a comunicação

Sistemas de Mensageria (Brokers)

  • Toda comunicação interna passa pelo broker
  • Mensagens são publicadas em canais 
  • Cada contêiner se inscreve a certos canais

Vantagens:

  • Facilita a comunicação de contêineres
  • Facilita a inclusão de novos contêineres

Exemplos de Brokers:

  • Apache Kafka, Rabbitmq, NATS Streaming, etc.

NATS Streaming

  • Perimite o armazenamento das mensagens em disco
  • Clientes em várias linguagens
  • Fácil de usar
  • Baixa latência e alta vazão de mensagens

Comparação de vazão com outros brokers

Comparação de latência com outros brokers

Broker Latência*
Apache Kafka ~1600,000 ms
Rabbitmq ~500,000 ms
Kestrel ~220.000 ms
NSD ~70,000 ms
NATS-ruby ~0,540 ms
NATS ~0,325 ms

* Latência para 1.000.000 mensagens

fonte: https://bravenewgeek.com/dissecting-message-queues/

Uso do NATS Streaming

const NATS = require('node-nats-streaming');

const stan = NATS.connect('test-cluster', 'test', {  // abrindo conexão
  url: process.env.NATS_URL
});  

stan.on('connect', async () => {                     // publicando mensagem
  setTimeout(() => {
    stan.publish('new.user', '42', (err, guid) => {
      if (err) console.log("Failed publishing");
      else console.log(`published with guid: ${guid}`);
    });
  }, 5000);
});

// subscrevendo a canal
stan.on('connect', async () => {
const optsAll = stan.subscriptionOptions().setDeliverAllAvailable();

  const new_user_subs = await stan.subscribe('new.user', optsAll);
  const user_ids_subs = {};

  new_user_subs.on('message', async (msg) => {
    console.log(`'new.user': ${msg.getData()}`);

    const uid = Number.parseInt(msg.getData());
    user_ids_subs[uid] = await stan.subscribe(`user.${uid}`, optsAll);
    user_ids_subs[uid].on('message', async (msg) => {
      'do something'
    });
  });
});

Acesso aos Dados

  • Broker =/= BD compartilhado
  • Sem necessidade consultas constantes para entrada de novos dados
  • Como diminuir o número de acessos?

 

Um Banco de Dados por Contêiner

Modelagem de BD

Bancos de Dados SQL

  • PostgreSQL, MariaDB, SQlite
  • Linguagem SQL
  • Consultas diversas

Desvantagens:

  • Alta latência
  • Difícil reestruturação do modelo
SELECT Nome_Artista,Nome 
FROM Artista A,Usuário_Titular S,Escuta E,Toca T,Usuário U  
WHERE E.Usuário_ID = U.Usuário_ID 
  AND E.Música_ID  = T.Música_ID 
  AND T.Artista_ID = A.Artista_ID 
  AND A.cidade     = S.cidade 
  AND U.Usuário_ID = S.Usuário_ID;


SELECT Nome_Artista
FROM Artista,(SELECT DISTINCT Artista_ID,Lista_ID FROM Produz) AS P1
WHERE Artista.Artista_ID = P1.Artista_ID 
AND NOT EXISTS (SELECT * 
		FROM Produz P2
		WHERE P1.Lista_ID = P2.Lista_ID
		AND P2.Artista_ID <> P1.Artista_ID)
AND EXISTS (SELECT * 
            FROM Compõe,Toca T1
            WHERE Compõe.Música_ID = T1.Música_ID 
            AND P1.Lista_ID = Compõe.Lista_ID
            AND NOT EXISTS (SELECT * 
                            FROM Toca T2
                            WHERE T2.Música_ID = Compõe.Música_ID
                            AND T1.Artista_ID <> T2.Artista_ID));

Propriedades ACID

  • Atomicidade
    A transação deve ter todas as suas operações executadas em caso de sucesso ou, em caso de falha, nenhum resultado de alguma operação refletido sobre a base de dados.
  • Consistência
    A transação deve respeitar as regras de integridade dos dados
  • Isolamento
    Cada transação só é efetuada depois que a anterior já ocorreu.
  • Durabilidade
    O resultado de todas transações executadas com sucesso é armazenado em disco.

BDs No-SQL

  • sem linguagem expressiva para consulta de dados
  • permitem que entidades armazenem um número variável de atributos.
  • (e. g. MongoDB, REDIS, Cassandra)

​Vantagens:

  • Menor latência e maior vazão
  • Facilmente particionados

Propriedades BASE

  • sica​ disponibilidade
    O Banco de Dados está disponível na maior parte do tempo
  • Estado maleável
    As transações de escrita não tem garantia que serão feitas instantaneamente e que as replicas do BD terão os mesmo estado ao mesmo tempo.
  • Eventual consistência
    Em algum tempo, todos os dados, em todas as réplicas, terão o mesmo valor (e. g. quando uma leitura for feita)

Comparação entre diferentes SGBDs

[Rabl T, 2012]

Comparação entre diferentes SGBDs

[Rabl T, 2012]

Redis

  • Remote Dictionary Server
  • BD Chave-Valor
  • Baixa latência devido ao funcionamento em memória RAM
  • Possibilita armazenamento em disco para backup
  • Clientes em várias linguagens
  • Comandos de fácil uso

Tipos de Armazenamentos
Strings


redis-cli


redis> SET mykey "Hello"
"OK"

redis> GET mykey
"Hello"


redis> MSET key1 "Hello" key2 "World"
"OK"

redis> MGET key1 key2 nonexisting
1) "Hello"
2) "World"
3) (nil)




Tipos de Armazenamentos
Strings

redis> GET mykey
"Hello"

redis> STRLEN mykey
(integer) 5

redis> APPEND mykey " World"
(integer) 11

redis> SETRANGE mykey 6 "Redis"
(integer) 11

redis> GET mykey
"Hello Redis"









Tipos de Armazenamentos
Strings 

redis> SET mykey "10"
"OK"

redis> INCR mykey
(integer) 11

redis> DECR mykey
(integer) 10

redis> INCRBY mykey 5
(integer) 15

redis> GET mykey
"11"

redis> SET myfloat 10.50
"OK"

redis> INCRBYFLOAT myfloat 0.1
"10.6"









Tipos de Armazenamentos
Chaves

redis> SET key1 "Hello"
"OK"

redis> EXISTS key1
(integer) 1

redis> EXISTS nosuchkey
(integer) 0

redis> TYPE key1
"string"

redis> DEL key1 key2 key3
(integer) 2

Tipos de Armazenamentos
Sets

redis> SADD myset "Hello"
(integer) 1

redis> SADD myset "World"
(integer) 1

redis> SADD myset "World"
(integer) 0

redis> SMEMBERS myset
1) "World"
2) "Hello"

redis> SISMEMBER myset "Hello"
(integer) 1

redis> SCARD myset
(integer) 2


Tipos de Armazenamentos
Sets

redis> SMEMBERS myset
1) "World"
2) "Hello"

redis> SADD myotherset "Hello" "there"
(integer) 1

redis> SINTER myset myotherset
1) "Hello"

redis> SDIFF myset myotherset
1) "World"



Tipos de Armazenamentos
Sorted Sets

redis> ZADD myzset 1 "one" 2 "two" 3 "three"
(integer) 3

redis> ZADD myzset 1 "uno"
(integer) 1

redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"

redis> ZRANGE myzset 2 3
1) "three"

Tipos de Armazenamentos
(Linked) Lists

redis> RPUSH mylist "one"
(integer) 1

redis> RPUSH mylist "two"
(integer) 2

redis> RPUSH mylist "three"
(integer) 3

redis> RPOP mylist
"three"

redis> LRANGE mylist 0 -1
1) "one"
2) "two"

redis> LPOP mylist
"one"

redis> LRANGE mylist 0 -1
1) "two"

Tipos de Armazenamentos
Hashes

redis> HMSET myhash field1 "Hello" field2 "World"
"OK"

redis> HMGET myhash field1 field2 nofield
1) "Hello"
2) "World"
3) (nil)

redis> HKEYS myhash
1) "field1"
2) "field2"

redis> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"

Modelo Conceitual

Modelo Entidade Relacionamento

Modelo
Físico

  • SQL: Linguagem SQL
  • Chave-Valor: o BD não tem implementação do modelo antes da entrada de dados.
    O usuário escolhe seguir o modelo
  • SQL: Necessita definir chaves primárias, atributos, chaves estrangeiras, etc.
  • Chave-Valor: Cada atributo tem uma chave
  • recomenda-se usar chaves do formato "Id_Entidade:Nome_atributo"
    (e. g. "84EC29A:Endereço" )

Modelo Lógico

Melhores Casos de uso de SGBDs Chave-Valor

  • Sistemas onde as consultas já são conhecidas previamente
  • Necessidade de baixa latência

Melhores práticas

  • Trocar Leitura e Escrita por  comandos específicos
    (e. g. INCR )
  • Armazenar atributos que são sempre processados juntos na mesma chave

Redis e
NATS Streaming
em Conjunto

Redis

Os dados que cada contêiner precisa consultar para fazer suas operações são armazenados em instâncias distintas do redis

Uma para cada contêiner

NATS Streaming

Qualquer ação realizada por um contêiner que afeta o resto do sistema gera um evento que é enviado para o broker.

Uma única instância do broker administra o envio e recebimento de todo o sistema

Orquestração

  • Um microsserviço principal envia comandos para o resto do sistema
  • Outros microsserviços só realizam ações quando requisitado
  • sistema mais acoplado, maior suscetível a cascata de falhas

Coreografia

  • Todos os microsserviços recebem eventos
  • Cada microsserviço responde ao evento de maneira diferente
  • sistema mais independente, com maior tolerância a falhas locais

Estilos de Organização de Microsserviços

Arquitetura de Microsserviços Reativa

  • Organizada baseada em Coreografia
  • Uso de Broker para envio e recebimento de eventos
  • Uso de BD local para acesso fácil e rápido a dados mais utilizados
  • Cada ação no sistema gera um evento
  • Cada serviço escolhe processar ( ou não ) esse evento de forma distinta
  • Dados essenciais para cada microsserviço armazenados em um BD de baixa latência

Referencias

Solving big data challenges for enterprise application performance management (2012)
Rabl T, Gómez-Villamor S, Sadoghi M, Muntés-Mulero V, Jacobsen H, Mankovskii S

Dissecting Message Queues - 2014, Tyler Treat - https://bravenewgeek.com/dissecting-message-queues/

 

 

Guias?,Tutoriais?
redis.io/commands

nats.io

 

Fim

fernando.scattone@usp.br

 Gitlab - @fernandofreire

Redis and NATS streaming

By Fernando Freire Scattone