Взаимодействие с кэшем Azure для Redis с помощью .NET

Завершено

Как правило, клиентское приложение использует клиентская библиотека для формирования запросов и выполнения команд в кэше Redis. Список доступных клиентских библиотек можно получить на странице клиентов Redis.

Выполнение команд в кэше Redis

Для языка .NET самым популярным является высокопроизводительный клиент Redis StackExchange.Redis. Этот пакет можно получить с помощью NuGet и добавить в код .NET, используя командную строку или интегрированную среду разработки. Ниже приведены примеры использования клиента.

Подключение к кэшу Redis с помощью StackExchange.Redis

Как вы помните, для подключения к серверу Redis нужны адрес узла, номер порта и ключ доступа. Azure также предлагает строка подключения для некоторых клиентов Redis, которые объединяют эти данные в одну строку. Это выглядит примерно так (с cache-name полями, password-here заполненными реальными значениями):

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

Для создания подключения к серверу строку следует передать в StackExchange.Redis.

Обратите внимание, что в конце есть еще два параметра:

  • ssl — требует шифровать создаваемое подключение;
  • abortConnection — позволяет создать подключение, даже если сервер в данный момент недоступен.

Существует несколько других необязательных параметров, которые можно включить в строку подключения для настройки клиентской библиотеки.

Создание подключения

Основным объектом подключения в библиотеке StackExchange.Redis является класс StackExchange.Redis.ConnectionMultiplexer. Этот объект абстрагирует процесс подключения к серверу (или группе серверов) Redis. Он оптимизирован для эффективного управления подключениями и всегда должен быть доступным при любых действиях с кэшем.

Создать экземпляр ConnectionMultiplexer можно с помощью статического метода ConnectionMultiplexer.Connect или ConnectionMultiplexer.ConnectAsync, передав строку подключения или объект ConfigurationOptions.

Вот простой пример.

using StackExchange.Redis;
...
var connectionString = "[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False";
var redisConnection = ConnectionMultiplexer.Connect(connectionString);

Получив ConnectionMultiplexer, вы можете выполнить три основные действия:

  • Получить доступ к базе данных Redis.
  • Используйте функции издателя или подписчика Redis, которые находятся вне области этого модуля.
  • Обратиться к отдельному серверу для обслуживания или мониторинга.

Получение доступа к базе данных Redis

Тип IDatabase представляет базу данных Redis. Его можно получить с помощью метода GetDatabase():

IDatabase db = redisConnection.GetDatabase();

Совет

Возвращенный из метода GetDatabase объект не требует много места или постоянного сохранения. Достаточно лишь сохранять активное состояние ConnectionMultiplexer.

Получив объект IDatabase, вы можете выполнять его методы для взаимодействия с кэшем. Все методы имеют синхронные и асинхронные версии, возвращающие Task объекты для их совместимости с async ключевыми словами.await

Ниже приведен пример хранения ключа или значения в кэше:

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

Метод StringSet возвращает bool, значение которого сообщает, что значение сохранено успешно (true) или нет (false). Затем это значение можно получить с помощью метода StringGet:

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

Получение и сохранение двоичных значений

Как вы помните, ключи и значения Redis предоставляются в виде двоичных безопасных строк. Это означает, что для хранения двоичных данных можно использовать те же методы. Для работы с типами byte[] существуют операторы неявного преобразования, а значит, с данными можно работать естественным образом:

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

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

StackExchange.Redis представляет ключи через тип RedisKey. Этот класс использует неявные преобразования в string или byte[] и обратно, позволяя использовать текстовые и двоичные значения ключей без сложностей. Значения представлены типом RedisValue . Как и для RedisKey, используются неявные преобразования, позволяющие передавать значение string или byte[].

Другие распространенные операции

Интерфейс IDatabase включает несколько других методов для работы с кэшем Redis. В их число входят методы для работы с хэшами, списками, наборами и упорядоченными наборами.

Вот некоторые наиболее распространенные методы, которые работают с индивидуальными ключами. Полный список методов можно получить, изучив исходный код интерфейса.

Метод Description
CreateBatch Создает группу операций для отправки на сервер в виде одной единицы, но не обязательно обрабатывается как единица.
CreateTransaction Создает группу операций для отправки на сервер в виде одной единицы и обрабатывается на сервере в виде одной единицы.
KeyDelete Удаляет пару "ключ-значение".
KeyExists Возвращает информацию о том, существует ли указанный ключ в кэше.
KeyExpire Задает для ключа срок жизни (TTL).
KeyRename Переименовывает ключ.
KeyTimeToLive Возвращает значение TTL для ключа.
KeyType Возвращает строковое представление типа, который используется для значения ключа. Могут быть возвращены различные типы: строка, список, набор, zset и хэш.

Выполнение других команд

Объект IDatabase имеет Execute метод и ExecuteAsync метод, который можно использовать для передачи текстовых команд серверу Redis. Например:

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

ExecuteAsync Методы Execute возвращают RedisResult объект, который является владельцем данных, который включает два свойства:

  • Resp2Type возвращает string тип результата — STRING, INTEGERи т. д.
  • IsNull содержит значение true или false, которое обозначает, является ли результат null.

Для получения фактического возвращаемого значения можно использовать ToString() для RedisResult.

Метод Execute позволяет выполнить любые поддерживаемые команды — например, получить полный список клиентов, подключенных к кэшу (CLIENT LIST):

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

Это выводит все подключенные клиенты:

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

Хранение более сложных значений

Redis ориентирован на двоичные безопасные строки, но вы можете кэшировать и графы объектов, сериализуя их в текстовый формат (чаще всего применяются XML или JSON). Например, возможно, для нашей статистики у нас есть GameStats объект, который выглядит следующим образом:

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"))}";
    }
}

С помощью библиотеки Newtonsoft.Json мы может преобразовать экземпляр этого объекта в строку:

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);

Получив эту строку из кэша, мы преобразуем ее в объект с помощью обратного процесса:

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

Очистка подключения

Если подключение больше не требуется, можно Dispose ConnectionMultiplexerиспользовать . Это закрывает все подключения и завершает связь с сервером.

redisConnection.Dispose();
redisConnection = null;