.NET을 사용하여 Azure Cache for Redis와 상호 작용

완료됨

일반적으로 클라이언트 애플리케이션은 클라이언트 라이브러리를 사용하여 요청을 작성하고 Redis 캐시에서 명령을 실행합니다. Redis 클라이언트 페이지에서 직접 클라이언트 라이브러리 목록을 가져올 수 있습니다.

Redis 캐시에서 명령 실행

.NET 언어를 위한 인기 있는 고성능 Redis 클라이언트는 StackExchange.Redis입니다. 패키지는 NuGet을 통해 사용할 수 있으며 명령줄 또는 IDE를 사용하여 .NET 코드에 추가할 수 있습니다. 다음은 클라이언트를 사용하는 방법의 예입니다.

StackExchange.Redis를 사용하여 Redis 캐시에 연결

Redis 서버에 연결할 때 호스트 주소, 포트 번호 및 액세스 키를 사용합니다. Azure는 일부 Redis 클라이언트에 이 데이터를 단일 문자열로 번들하는 연결 문자열도 제공합니다. 다음과 비슷합니다(cache-namepassword-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.Connect 또는 ConnectionMultiplexer.ConnectAsync 메서드를 사용하여 ConnectionMultiplexer 인스턴스를 만들고, 연결 문자열 또는 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가 있으면 다음과 같은 3가지 기본 작업을 수행할 수 있습니다.

  • Redis 데이터베이스에 액세스. 여기서는 이 부분을 집중적으로 살펴보겠습니다.
  • Redis의 게시자/구독자 기능을 사용합니다. 이 모듈의 범위를 벗어납니다.
  • 유지 관리 또는 모니터링을 위해 개별 서버에 액세스.

Redis 데이터베이스에 액세스

Redis 데이터베이스는 IDatabase 형식으로 표현됩니다. GetDatabase() 메서드를 사용하여 검색할 수 있습니다.

IDatabase db = redisConnection.GetDatabase();

GetDatabase에서 반환된 개체는 경량의 개체이며 저장할 필요가 없습니다. ConnectionMultiplexer만 활성 상태로 유지하면 됩니다.

IDatabase 개체가 있으면 캐시와 상호 작용하는 메서드를 실행할 수 있습니다. 모든 메서드는 asyncawait 키워드와 호환되도록 Task 개체를 반환하는 동기 및 비동기 버전을 갖고 있습니다.

다음은 캐시에 키/값을 저장하는 예제입니다.

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

StringSet 메서드는 값이 설정되었는지(true) 아니면 설정되지 않았는지(false) 나타내는 bool을 반환합니다. 그 후 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.RedisRedisKey 형식을 사용하여 키를 나타냅니다. 이 클래스는 stringbyte[]로 또는 그 반대로 암묵적 변환을 제공하며, 컴파일 없이 텍스트 및 이진 키를 모두 사용할 수 있습니다. 값은 RedisValue 형식으로 표현됩니다. RedisKey와 마찬가지로, string 또는 byte[]를 전달할 수 있도록 암시적 변환이 제공됩니다.

기타 일반 작업

IDatabase 인터페이스는 Redis 캐시와 함께 작동하는 여러 다른 메서드를 포함하고 있습니다. 해시, 목록, 집합 및 정렬된 집합과 함께 작동하는 메서드가 있습니다.

다음은 단일 키와 함께 작동하는 보다 일반적인 메서드이며, 전체 목록을 보려면 소스 코드를 참조하세요.

메서드 Description
CreateBatch 서버에 단일 단위로 전송되지만 반드시 단위로 처리되지는 않는 작업 그룹을 만듭니다.
CreateTransaction 서버에 단일 단위로 전송되고 서버에서 단일 단위로 처리되는 작업 그룹을 만듭니다.
KeyDelete 키/값을 삭제합니다.
KeyExists 지정된 키가 캐시에 있는지 여부를 반환합니다.
KeyExpire 키에서 TTL(Time to Live) 만료를 설정합니다.
KeyRename 키의 이름을 바꿉니다.
KeyTimeToLive 키의 TTL을 반환합니다.
KeyType 키에 저장된 값 형식의 문자열 표현을 반환합니다. 반환 가능한 형식은 문자열, 목록, 집합, zset 및 해시입니다.

기타 명령 실행

IDatabase 개체는 텍스트 명령을 Redis 서버에 전달할 수 있는 ExecuteExecuteAsync 메서드를 갖고 있습니다. 예:

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

ExecuteExecuteAsync 메서드는 다음 두 속성을 포함하는 데이터 보유자인 RedisResult 개체를 반환합니다.

  • “STRING”, “INTEGER” 등 결과의 형식을 나타내는 string을 반환하는 Type입니다.
  • 결과가 null인 것을 감지하는 true/false 값인 IsNull.

RedisResult에서 ToString()을 사용하여 실제 반환 값을 가져올 수 있습니다.

Execute를 사용하여 지원되는 명령을 수행할 수 있습니다. 예를 들어 캐시("클라이언트 목록")에 연결된 모든 클라이언트를 가져올 수 있습니다.

var result = await db.ExecuteAsync("client", "list");
Console.WriteLine($"Type = {result.Type}\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"

연결 정리

Redis 연결이 끝나면 ConnectionMultiplexerDispose할 수 있습니다. 그러면 모든 연결이 닫히고 서버와의 통신이 종료됩니다.

redisConnection.Dispose();
redisConnection = null;