평소에 DB 관련된 학습에 비해 Redis에 대한 지식이 많이 부족하다 느꼈다. Redis 공식문서와 '하야시 쇼고'의 실전 레디스 책을 보고 자료 구조와 명령어에 대한 의문에 대해서 정리해보고자 한다. 특히나 Redis에선 명령어에 대한 시간 복잡도와 주의사항 애노테이션이 있어 그것도 함께 정리하고자 한다.
기본적인 key에 대한 value를 넣는 명령어이며 이미 있는 값이라면 덮어쓰고 덮어쓰기 전 값에 대해서 TTL이 있었다면 해당 TTL은 삭제된다.
그리고 SET은 다양한 옵션에 대해서 지원하는데, TTL(Time To Live) 시간과 NX, XX, KEEPTTL 같은 명령어가 존재한다.
주의사항: SET 명령어는 시간복잡도는 O(1)이지만, 메모리를 SWAP까지 사용하거나 AOF, RDB, Replication으로 인한 오버헤드로 느린 쿼리가 될 수 있다.
key 값에 해당하는 value 값을 찾아 읽어온다. 값이 존재한다면 value를 반환하고 없다면 nil을 반환한다.
key 값에 해당하는 value 뒤에 추가적으로 value 값을 추가해서 이어 붙인다. 응답 결과로는 이전 value와 새로 추가된 value가 붙어서 생긴 value의 길이를 반환한다.
key 값에 해당하는 value의 문자열 길이를 가져온다. 만약에 문자열 형태가 아니라 다른 타입이라면 error를 리턴한다. 키가 없으면 0을 반환한다.
offset로 지정한 특정 위치부터 value를 이어붙인다. 만약에 없다면 padding('\0')으로 빈칸이 앞에 붙은 곳에 value를 붙인다.
해당 값이 숫자일 때만 동작을 하며 아니라면 오류를, 해당 값이 없었으면 1로 두고, 있었다면 숫자일 때 해당 값에 +1을 해서 동작한다.
레디스 공식문서상에서는 Counter 혹은 Rate Limiter로 해당 옵션을 사용할 수 있다고 제안한다.
추가적으로 INCRBY와 같은 명령어와 DECR, DECRBY는 방향이 동일하므로 해당 명령어에 대한 설명은 생략한다.
FLOAT 형태로 된 value에 대해서 값을 변경할 수 있으며 별도로 DECR없이 음수로 값을 넣으면 해당 value에 대해서 값을 내리고 양수면 값을 올리는 방식으로 동작한다.
이 역시도 String이 FLOAT 형태가 아니면 error를 내보내며, FLOAT형태의 소수점 기준으로 17자리까지의 정밀도를 가진다.
위의 시간복잡도에서 N이 의미하는 것은 저장하는 key의 개수이며, 원자성을 띄기 때문에 일부만 업데이트 되는 경우는 없고 항상 성공해서 OK를 내보내는 명령어이다. SET 명령어의 특징인 기존 값이 있다면 덮어쓴다는 점을 주의해야 한다.
반대로 MSETNX 명령어는 하나라도 이미 존재한다면 동작하지 않는다는 특징이 있으며 존재했을 때 명령어가 취소되면 명령어 실행 전 상태로 돌아간다.
해당 key에 대한 값이 존재한다면 value 값을 가져오고 없으면 nil을 가져온다.
EXAT, PXAT 옵션을 사용할 때에는 설정한 TTL이 NTP의 시간 동기화의 영향을 받아 시간 동기 상태에 대해 주의해야 한다.
Redis는 서버의 시스템 시간을 사용하며 NPT를 통해 시간 동기화가 일어나 시간을 당기거나 미는 경우 그로 인해 키가 일찍 만료되거나 예상시간보다 늦게 만료될 수 있으니 이를 주의하라는 말인 것 같다.
레디스 키 이름을 숫자나 기호만 써도 된다고 하나, user:사용자 번호와 같이 키 이름을 스키마로 대분류하여 콜론 형태로 구별해 각각 데이터를 저장하는 걸 권장한다.
그런데, 개인적으로 알기로는 user하고 userId를 하면 단일 DB 같은 경우엔 문제가 없는데 다중화가 된 경우엔 key 설정에 대해 단순히 AutoIncrement로 설정한 Id를 쓰면 안되는 것으로 알고 있다.
String은 문자열, 이진 데이터 등을 위한 자료형이다. 이름은 String이지만, 이진 안전 문자열이기에 이미지나 실행파일, 정수나 부동소수점(소수점 이하 17자리)도 저장이 가능하다.
String 형의 크기는 최대 512MB라고 SETRANGE 명령어 공식문서 상에 나와있다. 그런데, 레디스의 문자열이 SDS에 의해 관리되는데 proto-max-bulk-len 지시자가 4.0.7 버전에 생기면서 최대 크기를 늘릴 수 있다고 한다.
String 자료구조는 각 문자 key value에 대해서 TTL을 설정할 수 있다는 특징이 있다. Hash 자료구조에는 field 별로 TTL을 걸 수 없으니 이 부분을 명확하게 기억하자. 활용처는 다음과 같다.
추가로 공부해보면 좋을 만한 자료들:
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/
실전 레디스, 하야시 쇼고