Redis 자료구조 정리 - String

Recfli·2024년 11월 19일
0

Redis

목록 보기
1/2

자료구조 정리하는 이유?

평소에 DB 관련된 학습에 비해 Redis에 대한 지식이 많이 부족하다 느꼈다. Redis 공식문서와 '하야시 쇼고'의 실전 레디스 책을 보고 자료 구조와 명령어에 대한 의문에 대해서 정리해보고자 한다. 특히나 Redis에선 명령어에 대한 시간 복잡도와 주의사항 애노테이션이 있어 그것도 함께 정리하고자 한다.

SET 명령어, O(1)

ACL Categories: @write, @string, @slow

기본적인 key에 대한 value를 넣는 명령어이며 이미 있는 값이라면 덮어쓰고 덮어쓰기 전 값에 대해서 TTL이 있었다면 해당 TTL은 삭제된다.

그리고 SET은 다양한 옵션에 대해서 지원하는데, TTL(Time To Live) 시간과 NX, XX, KEEPTTL 같은 명령어가 존재한다.

  • EX - seconds 단위로 TTL 설정
  • PX - milliseconds 단위로 TTL 설정
  • EXAT - unix-time-seconds로 설정
  • PXAT - unix-time-milliseconds로 설정
  • NX - key에 해당하는 값이 없었다면 추가
  • XX - key에 해당하는 값이 있었다면 덮어쓰기
  • KEEPTTL - key에 해당하는 TTL 가져오기

주의사항: SET 명령어는 시간복잡도는 O(1)이지만, 메모리를 SWAP까지 사용하거나 AOF, RDB, Replication으로 인한 오버헤드로 느린 쿼리가 될 수 있다.

GET 명령어, O(1)

ACL Categories: @read, @string, @fast

key 값에 해당하는 value 값을 찾아 읽어온다. 값이 존재한다면 value를 반환하고 없다면 nil을 반환한다.

문자열로 취급할 때 사용할 수 있는 명령어

APPEND 명령어, O(1)

ACL Categories: @write, @string, @fast

key 값에 해당하는 value 뒤에 추가적으로 value 값을 추가해서 이어 붙인다. 응답 결과로는 이전 value와 새로 추가된 value가 붙어서 생긴 value의 길이를 반환한다.

STRLEN 명령어, O(1)

ACL Categories: @read, @string, @fast

key 값에 해당하는 value의 문자열 길이를 가져온다. 만약에 문자열 형태가 아니라 다른 타입이라면 error를 리턴한다. 키가 없으면 0을 반환한다.

SETRANGE 명렁어, Amortized O(1)

ACL Categories: @write, @string, @slow

offset로 지정한 특정 위치부터 value를 이어붙인다. 만약에 없다면 padding('\0')으로 빈칸이 앞에 붙은 곳에 value를 붙인다.

숫자로 취급할 때 동작하는 명령어

INCR 명령어, O(1)

ACL Categories: @write, @string, @fast

해당 값이 숫자일 때만 동작을 하며 아니라면 오류를, 해당 값이 없었으면 1로 두고, 있었다면 숫자일 때 해당 값에 +1을 해서 동작한다.

레디스 공식문서상에서는 Counter 혹은 Rate Limiter로 해당 옵션을 사용할 수 있다고 제안한다.

추가적으로 INCRBY와 같은 명령어와 DECR, DECRBY는 방향이 동일하므로 해당 명령어에 대한 설명은 생략한다.

INCRFLOAT 명령어, O(1)

ACL Categories: @write, @string, @fast

FLOAT 형태로 된 value에 대해서 값을 변경할 수 있으며 별도로 DECR없이 음수로 값을 넣으면 해당 value에 대해서 값을 내리고 양수면 값을 올리는 방식으로 동작한다.

이 역시도 String이 FLOAT 형태가 아니면 error를 내보내며, FLOAT형태의 소수점 기준으로 17자리까지의 정밀도를 가진다.

멀티 동작을 지원하는 명령어

MSET 명령어, O(N)

ACL Categories: @write, @string, @slow

위의 시간복잡도에서 N이 의미하는 것은 저장하는 key의 개수이며, 원자성을 띄기 때문에 일부만 업데이트 되는 경우는 없고 항상 성공해서 OK를 내보내는 명령어이다. SET 명령어의 특징인 기존 값이 있다면 덮어쓴다는 점을 주의해야 한다.

반대로 MSETNX 명령어는 하나라도 이미 존재한다면 동작하지 않는다는 특징이 있으며 존재했을 때 명령어가 취소되면 명령어 실행 전 상태로 돌아간다.

MGET 명령어, O(N)

ACL Categories: @read, @string, @fast

해당 key에 대한 값이 존재한다면 value 값을 가져오고 없으면 nil을 가져온다.


String 자료구조를 사용할 때의 주의사항

시간 동기화

EXAT, PXAT 옵션을 사용할 때에는 설정한 TTL이 NTP의 시간 동기화의 영향을 받아 시간 동기 상태에 대해 주의해야 한다.

Redis는 서버의 시스템 시간을 사용하며 NPT를 통해 시간 동기화가 일어나 시간을 당기거나 미는 경우 그로 인해 키가 일찍 만료되거나 예상시간보다 늦게 만료될 수 있으니 이를 주의하라는 말인 것 같다.

레디스의 키 이름을 짓는 방법

레디스 키 이름을 숫자나 기호만 써도 된다고 하나, user:사용자 번호와 같이 키 이름을 스키마로 대분류하여 콜론 형태로 구별해 각각 데이터를 저장하는 걸 권장한다.

그런데, 개인적으로 알기로는 user하고 userId를 하면 단일 DB 같은 경우엔 문제가 없는데 다중화가 된 경우엔 key 설정에 대해 단순히 AutoIncrement로 설정한 Id를 쓰면 안되는 것으로 알고 있다.

String 형에 저장할 수 있는 것들

String은 문자열, 이진 데이터 등을 위한 자료형이다. 이름은 String이지만, 이진 안전 문자열이기에 이미지나 실행파일, 정수나 부동소수점(소수점 이하 17자리)도 저장이 가능하다.

String 형의 크기는 최대 512MB라고 SETRANGE 명령어 공식문서 상에 나와있다. 그런데, 레디스의 문자열이 SDS에 의해 관리되는데 proto-max-bulk-len 지시자가 4.0.7 버전에 생기면서 최대 크기를 늘릴 수 있다고 한다.

String을 활용하는 방법?

String 자료구조는 각 문자 key value에 대해서 TTL을 설정할 수 있다는 특징이 있다. Hash 자료구조에는 field 별로 TTL을 걸 수 없으니 이 부분을 명확하게 기억하자. 활용처는 다음과 같다.

  • 세션 정보 등에 대한 캐시: 토큰에 대해서 DB에 저장하는 것이 아닌 Redis에 저장함으로써 더 빠른 응답을 내보낼 수 있다.
  • 분산락: 공식문서상에서는 RedLock 알고리즘 방식으로 사용하라고 하나, 해당 알고리즘의 문제점을 명확히 파악하고 사용해야 할 것 같다. 특히나 단일 서버가 아닌 다중 서버에서 특정 자원에 관한 상호배제를 구현할 수 있다는 장점이 있지만 그만큼 SPOF 지점이 될 수 있는 문제가 있다는 점도 이해를 하고 넘어가자.
  • Rate Limiter: 특정 시간 동안 특정 유저의 API에 대한 호출 횟수를 제한하는 용도로 사용하라 수 있다.
  • 재고 관리: INCR, INCRBY 등의 명령어를 통해 재고를 서버상에서 관리하고 나중에 싱크를 맞추는 방식으로 재고 관리에도 활용할 수 있다.

추가로 공부해보면 좋을 만한 자료들:
Redis의 rate limiter 관련 글
https://dev.gmarket.com/69

Redis의 RedLock 관련 주의사항
https://mangkyu.tistory.com/311
https://channel.io/ko/blog/articles/abc2d95c

Redis 재고 관리
https://techblog.woowahan.com/2709/
https://techblog.gccompany.co.kr/redis-kafka%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%84%A0%EC%B0%A9%EC%88%9C-%EC%BF%A0%ED%8F%B0-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EA%B8%B0-feat-%EB%84%A4%EA%B3%A0%EC%99%95-ec6682e39731

참고자료
https://redis.io/docs/latest/develop/use/patterns/distributed-locks/
https://redis.io/docs/latest/commands/
실전 레디스, 하야시 쇼고

profile
성장하고 싶은 신입 BE개발자

0개의 댓글