Interacción con Azure Cache for Redis mediante .NET
Normalmente, una aplicación cliente usa una biblioteca cliente para formar las solicitudes y ejecutar comandos en una caché de Redis. Puede obtener una lista de bibliotecas cliente directamente desde la página de clientes de Redis.
Ejecución de comandos en la caché de Redis
Un cliente popular de Redis de alto rendimiento para el lenguaje de .NET es StackExchange.Redis. El paquete está disponible a través de NuGet y se puede agregar al código de .NET mediante la línea de comandos o el IDE. A continuación se muestran algunos ejemplos de cómo usar el cliente.
Conexión a la caché de Redis con StackExchange.Redis
Recuerde que usamos la dirección del host, el número de puerto y una clave de acceso para conectarse a un servidor de Redis. Azure ofrece también una cadena de conexión para algunos clientes de Redis que empaquetan estos datos juntos en una sola cadena. Tiene un aspecto similar al siguiente (con los campos cache-name
y password-here
rellenos con valores reales):
[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False
Puede pasar esta cadena a StackExchange.Redis para crear una conexión al servidor.
Observe que al final hay dos parámetros más:
- ssl: garantiza que la comunicación está cifrada.
- abortConnection: permite crear una conexión incluso aunque el servidor no esté disponible en ese momento.
Existen varios parámetros opcionales que puede anexar a la cadena para configurar la biblioteca cliente.
Creación de una conexión
El objeto de conexión principal de StackExchange.Redis es la clase StackExchange.Redis.ConnectionMultiplexer
. Este objeto resume el proceso de conexión a un servidor de Redis (o grupo de servidores). Se ha optimizado para administrar conexiones de forma eficaz y pretende conservarse mientras tenga acceso a la memoria caché.
Puede crear una instancia de ConnectionMultiplexer
mediante ConnectionMultiplexer.Connect
estático o mediante el método ConnectionMultiplexer.ConnectAsync
, pasando una cadena de conexión o un objeto ConfigurationOptions
.
A continuación se muestra un sencillo ejemplo:
using StackExchange.Redis;
...
var connectionString = "[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False";
var redisConnection = ConnectionMultiplexer.Connect(connectionString);
Una vez que tenga un ConnectionMultiplexer
, hay tres cosas principales que es posible que quiera hacer:
- Acceda a una base de datos de Redis.
- Use las características para publicadores o suscriptores de Redis, que están fuera del ámbito de este módulo.
- Acceda a un servidor individual con fines de mantenimiento o supervisión.
Acceso a una base de datos de Redis
El tipo IDatabase
representa la base de datos de Redis. Puede recuperar uno mediante el método GetDatabase()
:
IDatabase db = redisConnection.GetDatabase();
Sugerencia
El objeto devuelto desde GetDatabase
es un objeto ligero y no necesita almacenarse. Solo necesita que ConnectionMultiplexer
se mantenga activo.
Una vez que tenga un objeto IDatabase
, puede ejecutar métodos para interactuar con la memoria caché. Todos los métodos tienen versiones sincrónicas y asincrónicas que devuelven objetos Task
para que sean compatibles con las palabras clave async
y await
.
A continuación, un ejemplo de almacenamiento de un par clave-valor en la caché:
bool wasSet = db.StringSet("favorite:flavor", "i-love-rocky-road");
El método StringSet
devuelve un bool
que indica si se ha establecido el valor (true
) o no (false
). Se puede recuperar el valor con el método StringGet
:
string value = db.StringGet("favorite:flavor");
Console.WriteLine(value); // displays: ""i-love-rocky-road""
Obtención y establecimiento de valores binarios
Recuerde que las claves y valores de Redis son cadenas seguras binarias. Estos mismos métodos se pueden usar para almacenar datos binarios. Existen operadores de conversión implícitos que funcionan con tipos byte[]
para que pueda trabajar de forma natural con los datos:
byte[] key = ...;
byte[] value = ...;
db.StringSet(key, value);
byte[] key = ...;
byte[] value = db.StringGet(key);
StackExchange.Redis representa claves mediante el tipo RedisKey
. Esta clase tiene conversiones implícitas hacia y desde string
y byte[]
, lo que permite a las claves de texto y las claves binarias utilizarse sin ninguna complicación. Los valores se representan mediante el tipo RedisValue
. Al igual que con RedisKey
, hay conversiones implícitas en marcha que le permiten pasar string
o byte[]
.
Otras operaciones habituales
La interfaz IDatabase
incluye otros métodos para trabajar con la caché de Redis. Hay métodos para trabajar con hashes, listas, conjuntos y conjuntos ordenados.
Estos son algunos de los más comunes que funcionan con claves sencillas, puede leer el código fuente de la interfaz para ver la lista completa.
Método | Descripción |
---|---|
CreateBatch |
Crea un grupo de operaciones que se va a enviar al servidor como una sola unidad, pero que no necesariamente se va a procesar como tal. |
CreateTransaction |
Crea un grupo de operaciones que se va a enviar al servidor como una sola unidad y que se va a procesar como tal. |
KeyDelete |
Elimine el par clave/valor. |
KeyExists |
Devuelve si la clave especificada existe o no en la memoria caché. |
KeyExpire |
Establece una expiración del período de vida (TTL) en una clave. |
KeyRename |
Cambia el nombre de una clave. |
KeyTimeToLive |
Devuelve el período de vida de una clave. |
KeyType |
Devuelve la representación de cadena del tipo del valor almacenado en la clave. Los distintos tipos que se pueden devolver son: cadena, lista, conjunto, zset y hash. |
Ejecución de otros comandos
El objeto IDatabase
tiene un método Execute
y ExecuteAsync
que se puede usar para pasar comandos textuales al servidor de Redis. Por ejemplo:
var result = db.Execute("ping");
Console.WriteLine(result.ToString()); // displays: "PONG"
Los métodos Execute
y ExecuteAsync
devuelven un objeto RedisResult
que es un contenedor de datos que incluye dos propiedades:
Resp2Type
que devuelve unstring
que indica el tipo del resultado:STRING
,INTEGER
, etc.IsNull
un valor true o false para detectar cuándo el resultado esnull
.
Después, puede usar ToString()
en RedisResult
para obtener el valor devuelto real.
Puede usar Execute
para realizar cualquiera de los comandos admitidos: por ejemplo, podemos obtener todos los clientes conectados a la caché ("CLIENT LIST"):
var result = await db.ExecuteAsync("client", "list");
Console.WriteLine($"Type = {result.Resp2Type}\r\nResult = {result}");
Esto genera como salida todos los 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
Almacenamiento de valores más complejos
Redis está orientado en torno a cadenas seguras binarias pero puede almacenar en caché los gráficos de objeto serializándolos en un formato textual: normalmente XML o JSON. Por ejemplo, quizás para nuestras estadísticas, tenemos un objeto GameStats
con el siguiente aspecto:
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"))}";
}
}
Podríamos usar la biblioteca Newtonsoft.Json para convertir una instancia de este objeto en una cadena:
var stat = new GameStat("Soccer", new DateTime(2019, 7, 16), "Local Game",
new[] { "Team 1", "Team 2" },
new[] { ("Team 1", 2), ("Team 2", 1) });
string serializedValue = Newtonsoft.Json.JsonConvert.SerializeObject(stat);
bool added = db.StringSet("event:1950-world-cup", serializedValue);
Podríamos recuperarla y hacer que vuelva a ser un objeto mediante el proceso inverso:
var result = db.StringGet("event:2019-local-game");
var stat = Newtonsoft.Json.JsonConvert.DeserializeObject<GameStat>(result.ToString());
Console.WriteLine(stat.Sport); // displays "Soccer"
Limpieza de la conexión
Cuando la conexión deje de ser necesaria, puede Dispose
ConnectionMultiplexer
. Esto cierra todas las conexiones y apaga la comunicación con el servidor.
redisConnection.Dispose();
redisConnection = null;