Redis
Remote Dictionary Storage의 약자로 모든 데이터를 메모리에 저장하고 조회하는 인메모리 데이터 저장소
오픈 소스로 개발되었으며 메모리 기반 key-value 구조를 가지는 데이터베이스 관리 시스템
- string / bitmap / hash / list / set / sorted set 등 다양한 자료구조를 지원하기 때문에 데이터를 간단하게 저장 / 조회 / 수정할 수 있음
- 메모리에 데이터를 저장하기 때문에 매우 빠른 Read/Write 속도를 가짐
- Master-slave 구조로 여러 노드에 데이터를 분산하여 저장하고, 클러스터링을 지원함으로써 높은 가용성과 확장성을 제공
- 필요에 따라 디스크에 데이터를 저장하여 영속화시킬 수 있음
- 레디스는 정기적으로 Snapshot을 저장하여 데이터베이스의 내용을 디스크에 씀
- 레디스의 재기동시 Snapshot을 불러와 데이터를 복원
- 단, Snapshot 저장시 명령어 수행이 제한되어 BGSAVE 옵션으로 백그라운드에서 스냅샷을 저장할 수 있으나, 자식 프로세스가 생성되기 때문에 메모리 사용량이 두배가 될 수 있음
- 싱글 쓰레드로 동작하기 때문에 요청시 주의가 필요
- Pub/Sub 기능을 활용하여 채널(Channel)과 구독(Subscribe)을 바탕으로 한 메시지 기반의 통신을 효과적으로 구현할 수 있음
자료형에 따른 Redis 기본 명령어
String
SET : key에 value를 저장
SET username "hello"
GET : key에 해당하는 value를 가져옴
GET username
DEL : key를 삭제
DEL username
List
- 양방향 linked list 형태의 자료형
LPUSH / RPUSH : 리스트의 왼쪽(앞) / 오른쪽(뒤)에 데이터 추가
LPUSH fruits "apple" "banana" "cherry"
RPUSH fruits "orange" "pineapple"
LPOP / RPOP : 리스트의 앞 / 뒤에서 데이터 획득 후 삭제
LPOP fruits
RPOP fruits
LINDEX : 리스트의 특정 인덱스에 해당하는 데이터 조회
LINDEX fruits 2
LRANGE : 리스트의 특정 범위에 해당하는 데이터 조회
LRANGE fruits 0 2
LLEN : 리스트의 길이(= 요소의 개수) 조회
LLEN fruits
Set
- 중복을 허용하지 않는 고유한 값을 저장하는 자료형
- 집합이기 때문에 교집합 / 합집합 / 차집합 등을 매우 빠르게 구할 수 있음
SADD : Set에 데이터 추가
SADD my_set "apple" "banana"
SMEMBERS : Set의 모든 멤버 조회
SMEMBERS my_set
SISMEMBER : Set에 특정 멤버가 속해있는지 확인
SISMEMBER my_set "banana"
SREM : Set에서 특정 멤버 제거
SREM my_set "apple"
SCARD : Set의 크기(= 멤버의 개수) 조회
SCARD my_set
SUNION / SINTER / SDIFF : Set의 합집합 / 교집합 / 차집합 구하기
SUNION set1 set2 set3
SINTER set1 set2 set3
SDIFF set1 set2
Sorted Set
- 값과 가중치(score)로 이루어진 정렬된 자료형
- 값은 중복을 허용하지 않지만 가중치는 중복이 가능함
- 가중치를 기준으로 오름차순 정렬됨
ZADD : Sorted Set에 멤버와 스코어 추가
ZADD my_sorted_set 90 "John" 85 "Alice" 92 "Bob"
ZRANGE / ZREVRANGE : Sorted Set의 특정 범위 내 멤버 조회(오름차순 / 내림차순)
ZRANGE my_sorted_set 0 2
ZREVRANGE my_sorted_set 0 2
ZREM : Sorted Set에서 특정 멤버 제거
ZREM my_sorted_set "Alice"
ZSCORE : Sorted Set에서 특정 멤버의 스코어 조회
ZSCORE my_sorted_set "Bob"
ZRANK : Sorted Set에서 특정 멤버의 순위 조회
ZRANK my_sorted_set "John"
ZCARD : Sorted Set의 크기(=멤버의 개수) 조회
ZCARD my_sorted_set
ZUNIONSTORE / ZINTERSTORE : Sorted Set의 합집합 / 교집합을 다른 Sorted Set에 저장
ZUNIONSTORE destination numkeys key1 key2 ...
ZINTERSTORE destination numkeys key1 key2 ...
Hash
- 필드-값 쌍(Field-Value Pair)의 집합으로 이루어진 자료형
- 각 필드와 그에 대응하는 값이 함께 저장됨
- 암호화와는 관계없음
HSET : Hash에 필드-값 쌍을 추가 또는 수정
HSET user:1 name "John"
HMSET : Hash에 여러 개의 필드-값 쌍을 한번에 추가 또는 수정
HMSET user:1 name "John" age 30 email "john@example.com"
HGET : Hash에서 특정 필드의 값을 조회
HGET user:1 name
HMGET : Hash에서 여러 개의 필드에 대한 값을 조회
HMGET user:1 name age
HDEL : Hash에서 특정 필드를 삭제
HDEL user:1 email
HKEYS : Hash의 모든 필드들의 이름 조회
HKEYS user:1
HVALS : Hash의 모든 필드들의 값을 조회
HVALS user:1
HGETALL : Hash의 모든 필드-값 쌍을 조회
HGETALL user:1
CloudStrucutres 라이브러리를 사용한 Redis 활용 예시
CloudStructures는 StackExchange.Redis에 기능을 추가하고 사용하기 편하게 랩핑한 라이브러리
public static class RedisServer
{
public static RedisConnection Connection { get; }
public static RedisServer()
{
var config = new RedisConfig("name", "connectionString");
Connection = new RedisConnection(config);
}
}
RedisConnection 객체는 반드시 static으로 선언되어야함
RedisConfig의 두번째 매개변수인 connectionString에는 Redis 서버의 호스트 이름 / 포트 번호 / 액세스 키 등의 정보를 기입
var key = "test-key";
var defaultExpiry = TimeSpan.FromDays(1);
var redis = new RedisString<T>(RedisServer.Connection, key, defaultExpiry)
RedisString<T> 클래스를 사용하여 Redis 서버에서 string 데이터를 저장하고 관리하기 위한 redis 객체를 생성
T는 데이터의 형식을 나타내며, RedisString 외에도 사용하고자 하는 데이터의 구성에 따라 RedisList / RedisSet / RedisHashSet 등을 사용할 수 있음
await redis.SetAsync(data);
위와 같이 생성해둔 객체의 명령어들을 사용하여 데이터를 관리할 수 있음
CloudStrucutres 라이브러리 문법
String
var v = new RedisString<int>(RedisConnection, "test_key", null);
- v.SetAsync() : SET에 해당
- v.GetAsync() : GET에 해당
- v.DeleteAsync() : DEL에 해당
- v.Increment(Decrement)Async(x) : 기존 값에서 x만큼 증가(감소)
- v.IncrementLimitByMax(Min)Async(x, y) : 기존 값에서 x만큼 늘리지만 y보다 크지는(작지는) 않음
- v.GetWithExpiryAsync() : 키의 유효 기간 획득
- v.GetAndDeleteAsync() : 값 획득 후 삭제
- v.SetAsync(x, null, When.NotExists) : 키가 존재하지 않을 때만 값 저장
List
var v = new RedisList<int>(RedisConnection, key, defaultExpiry);
- v.Left(Right)PushAsync() : LPUSH / RPUSH에 해당
- v.Left(RIght)PopAsync() : LPOP / RPOP에 해당
- v.GetByIndexAsync() : LINDEX에 해당
- v.RangeAsync() : LRANGE에 해당
- v.LenghtAsync() : LLEN에 해당
Set
var v = new RedisSet<int>(RedisConnection, key, defaultExpiry);
- v.AddAsync() : SADD에 해당
- v.MemberAsync() : SMEMBERS에 해당
- v.ContainsAsync() : SISMEMBER에 해당
- v.RemoveAsync() : SREM에 해당
- v.LengthAsync() : SCARD에 해당
- v.CombineAsync() : SUNION / SINTER / SDIFF에 해당
Sorted Set
var v = new RedisSortedSet<int>(RedisConnection, key, defaultExpiry);
- v.AddAsync() : ZADD에 해당
- v.RangeByRankAsync() : ZRANGE / ZREVRANGE에 해당
- v.RemoveAsync() : ZREM에 해당
- v.ScoreAsync() : ZSCORE에 해당
- v.RankAsync() : ZRANK에 해당
- v.LengthAsync() : ZCARD에 해당
- v.CombineAndStoreAsync() : ZUNIONSTORE / ZINTERSTORE에 해당
Hash
var v = new RedisDictionary<int, bool>(RedisConnection, key, defaultExpiry);
- v.SetAsync() : HSET에 해당
- v.GetAsync() : HGET에 해당
- v.DeleteAsync() : HDEL에 해당
- v.KeysAsync() : HKEYS에 해당
- v.ValuesAsync() : HVALS에 해당
- v.GetAllAsync() : HGETALL에 해당
- HMSET과 HMGET에 해당하는 메서드는 발견하지 못함...
Redis를 사용한 Lock
서버가 분산되어있을 경우 같은 유저에 대해 동시에 접근하는 경우가 발생할 수 있음
이를 Redis에서 원자성을 보장하는 명령어인 SETNX를 사용하여 해결 가능
- 유저 접근시 SETNX로 해당 유저에 대한 키값을 생성
- SETNX는 키의 존재 여부를 확인하여 존재하지 않을 때만 해당 키와 값을 저장
- 따라서 이미 키가 존재한다면 같은 유저에 대해 중복 요청이 들어온 것이므로 요청을 처리하지 않아야 함
try
{
var redis = new RedisString<AuthUser>(_redisConn, key, NxKeyTimeSpan());
if (await redis.SetAsync(new AuthUser
{
// emtpy value
}, NxKeyTimeSpan(), StackExchange.Redis.When.NotExists) == false)
{
return false;
}
}
catch
{
return false;
}
return true;
CloudStructures 라이브러리를 활용하여 해당 기능을 구현할 수 있음
- Redis 객체를 생성, 이 때 key는 유저에 따라 달라지는 값
- SetAsync() 메서드로 해당 키를 설정
- 키에 대한 밸류는 필요하지 않으므로 비워둠
- 두번째 매개변수로 NxKeyTimeSpan()을 지정한 것과 같이 키가 만료되는 시간도 설정 가능
- 세번째 매개변수로 지정한 StackExchange.Redis.When.NotExists로 SETNX를 구현
- 키가 존재할경우 false, 아닐 경우 true를 반환하기 때문에 이 값을 통해 중복된 접근인지 아닌지 판별할 수 있음
'개인공부 > Web API 게임 서버 공부' 카테고리의 다른 글
배경지식 - Web 서버 구조 (0) | 2023.04.23 |
---|---|
배경지식 - ZLogger (0) | 2023.04.20 |
배경지식 - ORM (1) | 2023.04.20 |
배경지식 - C# (0) | 2023.04.20 |
배경지식 - ASP.NET (0) | 2023.04.19 |
댓글