Explorar a API de cliente para interagir com a Redis

Concluído

Como mencionado anteriormente, o Redis é um banco de dados NoSQL na memória, que pode ser replicado em vários servidores. É frequentemente usado como um cache, mas pode ser usado como um banco de dados formal ou até mesmo como um agente de mensagens.

O Redis pode armazenar vários tipos de dados e estruturas. Ele suporta vários comandos que você pode emitir para recuperar dados armazenados em cache ou para consultar informações sobre o próprio cache. Os dados com que trabalha são sempre armazenados como pares chave/Valor.

Executar comandos no cache Redis

Geralmente, a aplicação cliente utiliza uma biblioteca de cliente para criar pedidos e executar comandos numa cache de Redis. Pode obter uma lista de bibliotecas de cliente diretamente na página de clientes do Redis. Um cliente de Redis popular de desempenho elevado para a plataforma .NET é o StackExchange.Redis. O pacote está disponível através do NuGet, e você pode adicioná-lo ao seu código .NET usando a linha de comando ou IDE.

Conecte-se ao cache Redis com StackExchange.Redis

Lembre-se de que utilizamos o endereço do anfitrião, o número de porta e uma chave de acesso para ligar a um servidor Redis. O Azure também oferece uma cadeia de conexão para alguns clientes Redis, que agrupa esses dados em uma única cadeia de caracteres.

O que é uma cadeia de ligação?

Uma cadeia de ligação é uma linha de texto que inclui todas as informações necessárias para ligar e autenticar uma cache de Redis no Azure. É semelhante ao seguinte (com os campos cache-name and password-here preenchidos com valores reais):

[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False

Gorjeta

A cadeia de ligação deve estar protegida na sua aplicação. Se a aplicação estiver alojada no Azure, pondere utilizar um cofre do Azure Key Vault para armazenar o valor.

Você pode passar essa cadeia de caracteres para StackExchange.Redis para criar uma conexão com o servidor.

Observe que há mais dois parâmetros no final:

  • SSL: Garante que a comunicação é criptografada
  • abortConnection: permite que uma conexão seja criada mesmo que o servidor esteja indisponível naquele momento

Pode anexar vários outros parâmetros opcionais à cadeia para configurar a biblioteca de cliente.

Criar uma ligação

O objeto de cadeia principal em StackExchange.Redis é a classe StackExchange.Redis.ConnectionMultiplexer. Este objeto abstrai o processo de ligação a um servidor Redis (ou a um grupo de servidores). Está otimizado para gerir as ligações de forma eficiente e deve permanecer por perto enquanto precisa de acesso à cache.

Para criar uma instância ConnectionMultiplexer, vai utilizar o ConnectionMultiplexer.Connect estático ou o método ConnectionMultiplexer.ConnectAsync e transmitir uma cadeia de ligação ou um objeto ConfigurationOptions.

Eis um exemplo simples:

using StackExchange.Redis;
...
var connectionString = "[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False";
var redisConnection = ConnectionMultiplexer.Connect(connectionString);
    // ^^^ store and re-use this!!!

Depois de ter um ConnectionMultiplexer, há três coisas principais que você pode querer fazer:

  1. Aceda a uma Base de Dados Redis (o foco deste módulo).
  2. Faça uso dos recursos de editor/subscrito do Redis (fora do escopo deste módulo).
  3. Aceder a um servidor individual para fins de manutenção ou monitorização.

Aceder a uma base de dados Redis

A base de dados do Redis é representada pelo tipo IDatabase. Pode obter uma com o método GetDatabase():

IDatabase db = redisConnection.GetDatabase();

Gorjeta

O objeto retornado é GetDatabase um objeto leve e não precisa ser armazenado. Só é necessário manter o objeto ConnectionMultiplexer ativo.

Quando tiver um objeto IDatabase, pode executar métodos para interagir com a cache. Todos os métodos têm versões síncronas e assíncronas, que retornam Task objetos para torná-los compatíveis com as async palavras-chave e await .

Aqui está um exemplo de armazenamento de uma chave/valor no cache:

bool wasSet = db.StringSet("favorite:flavor", "i-love-rocky-road");

O método StringSet devolve um bool, que indica se o valor foi definido (true) ou não (false). Depois, podemos obter o valor com o método StringGet:

string value = db.StringGet("favorite:flavor");
Console.WriteLine(value); // displays: ""i-love-rocky-road""

Obter e definir valores binários

Lembre-se de que as chaves e os valores de Redis são binary safe. Você pode usar esses mesmos métodos para armazenar dados binários. Existem operadores de conversão implícitos que funcionam com os tipos byte[], para que possa trabalhar com os dados naturalmente:

byte[] key = ...;
byte[] value = ...;

db.StringSet(key, value);
byte[] key = ...;
byte[] value = db.StringGet(key);

Gorjeta

StackExchange.Redis utiliza o tipo RedisKey para representar chaves. Esta classe tem conversões implícitas para e de string e byte[], permitindo a utilização de texto e chaves binárias sem qualquer complicação. Os valores são representados pelo tipo RedisValue. Tal como com o tipo RedisKey, existem conversões implícitas que lhe permitem transmitir string ou byte[].

Outras operações comuns

A interface IDatabase inclui vários outros métodos para trabalhar com a cache de Redis. Há métodos para trabalhar com hashes, listas, conjuntos e conjuntos ordenados.

Aqui estão algumas das operações mais comuns que funcionam com chaves únicas; Você pode ler o código-fonte da interface para ver a lista completa.

Método Description
CreateBatch Cria um grupo de operações que será enviado para o servidor como uma única unidade, mas não processado como tal necessariamente.
CreateTransaction Cria um grupo de operações que será enviado para o servidor como uma única unidade e processado como tal.
KeyDelete Exclui a chave/valor.
KeyExists Devolve se a chave específica existe na cache.
KeyExpire Define uma expiração de time-to-live (TTL) numa chave.
KeyRename Muda o nome de uma chave.
KeyTimeToLive Devolve o TTL de uma chave.
KeyType Devolve a representação da cadeia do tipo do valor armazenado na chave. Os diferentes tipos que podem ser retornados são: string, list, set, zset e hash.

Executar outros comandos

O IDatabase objeto tem um Execute método and ExecuteAsync , que pode ser usado para passar comandos textuais para o servidor Redis. Por exemplo:

var result = db.Execute("ping");
Console.WriteLine(result.ToString()); // displays: "PONG"

Os Execute métodos e ExecuteAsync retornam um RedisResult objeto, que é um titular de dados que inclui duas propriedades:

  • Type, que retorna uma string indicação do tipo do resultado - "STRING", "INTEGER", etc.
  • IsNull, um valor verdadeiro/falso para detetar quando o resultado é null.

Pode utilizar ToString() em RedisResult para obter o valor de retorno real.

Você pode usar Execute para executar quaisquer comandos suportados. Por exemplo, podemos conectar todos os clientes ao cache ("LISTA DE CLIENTES"):

var result = await db.ExecuteAsync("client", "list");
Console.WriteLine($"Type = {result.Type}\r\nResult = {result}");

Os comandos anteriores produzem todos os clientes conectados:

Type = BulkString
Result = id=9469 addr=16.183.122.154:54961 fd=18 name=DESKTOP-AAAAAA age=0 idle=0 flags=N db=0 sub=1 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=subscribe numops=5
id=9470 addr=16.183.122.155:54967 fd=13 name=DESKTOP-BBBBBB age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=client numops=17

Armazene valores mais complexos

O Redis é orientado em torno de cadeias binárias seguras, mas você pode armazenar em cache gráficos de objetos serializando-os para um formato textual; normalmente XML ou JSON. Por exemplo, talvez para as nossas estatísticas, temos um GameStat objeto, que se parece com:

public class GameStat
{
    public string Id { get; set; }
    public string Sport { get; set; }
    public DateTimeOffset DatePlayed { get; set; }
    public string Game { get; set; }
    public IReadOnlyList<string> Teams { get; set; }
    public IReadOnlyList<(string team, int score)> Results { get; set; }

    public GameStat(string sport, DateTimeOffset datePlayed, string game, string[] teams, IEnumerable<(string team, int score)> results)
    {
        Id = Guid.NewGuid().ToString();
        Sport = sport;
        DatePlayed = datePlayed;
        Game = game;
        Teams = teams.ToList();
        Results = results.ToList();
    }

    public override string ToString()
    {
        return $"{Sport} {Game} played on {DatePlayed.Date.ToShortDateString()} - " +
               $"{String.Join(',', Teams)}\r\n\t" + 
               $"{String.Join('\t', Results.Select(r => $"{r.team } - {r.score}\r\n"))}";
    }
}

Podemos utilizar a biblioteca Newtonsoft.Json para transformar uma instância deste objeto numa cadeia:

var stat = new GameStat("Soccer", new DateTime(1950, 7, 16), "FIFA World Cup", 
                new[] { "Uruguay", "Brazil" },
                new[] { ("Uruguay", 2), ("Brazil", 1) });

string serializedValue = Newtonsoft.Json.JsonConvert.SerializeObject(stat);
bool added = db.StringSet("event:1950-world-cup", serializedValue);

Podemos utilizar o processo inverso e obtê-la e transformá-la de novo num objeto.

var result = db.StringGet("event:1950-world-cup");
var stat = Newtonsoft.Json.JsonConvert.DeserializeObject<GameStat>(result.ToString());
Console.WriteLine(stat.Sport); // displays "Soccer"

Limpar a ligação

Depois de concluir a conexão Redis, você pode descartar o ConnectionMultiplexerarquivo . Este comando fecha todas as conexões e desliga a comunicação com o servidor:

redisConnection.Dispose();
redisConnection = null;

Vamos criar um aplicativo e fazer algum trabalho com nosso cache Redis.

Como mencionado anteriormente, o Redis é um banco de dados NoSQL na memória, que pode ser replicado em vários servidores. Muitas vezes é usado como um cache, mas pode ser usado como um banco de dados formal ou até mesmo um agente de mensagens.

O Redis pode armazenar vários tipos de dados e estruturas. Ele suporta vários comandos que você pode emitir para recuperar dados armazenados em cache ou consultar informações sobre o próprio cache. Os dados com que trabalha são sempre armazenados como pares chave/Valor.

Executar comandos no cache Redis

Geralmente, a aplicação cliente utiliza uma biblioteca de cliente para criar pedidos e executar comandos numa cache de Redis. Pode obter uma lista de bibliotecas de cliente diretamente na página de clientes do Redis. Um cliente do Redis popular para JavaScript é o pacote redis, que pode adicionar a um projeto com o comando npm install redis.

Conecte-se ao cache Redis com o pacote redis

A interação com uma cache de Redis é obtida com a classe RedisClient. Na maioria dos cenários, o seguinte código de texto automático é a melhor maneira de criar uma classe RedisClient com ligação a uma cache de Redis no Azure:

const client = redis.createClient(
  port,  // the port number, 6380 by default
  hostname,  // <resourceName>.redis.cache.windows.net
  {
    password: accessKey,  // the primary or secondary access key
    tls: { servername: hostname }
  }
);

Na maioria dos casos, deve evitar criar múltiplas classes RedisClient. Uma única instância da classe RedisClient pode ser passada e utilizada em qualquer parte do seu código em que a Redis seja necessária.

Trabalhar com um banco de dados Redis

Os comandos Redis são representados como métodos com RedisClient os nomes como os próprios comandos. Eis um exemplo de como armazenar um novo valor na cache:

client.set("myKey", "myValue"); // executes "set myKey myValue" on the cache

Todos os métodos de comandos na classe RedisClient são assíncronos e suportam um argumento de chamada de retorno opcional que fornece o resultado. O redis pacote não suporta Promessas (e, portanto,awaitasync/ou encadeamento com.then()) fora da caixa. A forma mais fácil de utilizar os comandos async/await ou .then() com a classe RedisClient é adicionar suporte para Promessas a todo o cliente ao mesmo tempo com a função promisifyAll do pacote bluebird:

var redis = require("redis");
var Promise = require("bluebird");

Promise.promsifyAll(redis);

A promisifyAll função adicionará XXXAsync versões de todos os métodos de comando às RedisClient instâncias, permitindo que você use métodos assíncronos como no exemplo a seguir:

var result = await client.setAsync("myKey", "myValue");

Executar comandos dinamicamente

Você pode enviar comandos dinamicamente usando sendCommand() (ou sendCommandAsync() com bluebird) para enviar qualquer string como um comando para o cache. Por exemplo, seu aplicativo pode apresentar um prompt para enviar comandos diretamente para o cache ou o Redis pode introduzir novos comandos que o redis pacote não suporta. Os argumentos de comandos têm de ser enviados como uma matriz.

// Add a key/value pair
var result = await client.sendCommandAsync("set", ["myKey", "myValue"]);

Limpar a ligação

Depois de terminar a conexão Redis, você deve fechá-la com quit() (ou quitAsync() ao usar o bluebird):

await client.quitAsync();

Vamos criar um aplicativo e fazer algum trabalho com nosso cache Redis.