Redis
in Computer Science on Database
Redis
같은 팀원이자 나의 멘토이신 Chester
의 레디스 강의 정리
https://db-engines.com/en/ranking
위 사이트는 DB 랭킹인데 Redis가 8위에 랭크된 것을 볼 수 있다.
특징
Redis는
In-memory
DB이다.Redis는
Single Thread
이다.메인 메모리에만 놓고, 휘발성으로 사용한다. 즉 영구적으로 저장할 데이터를 저장할 목적으로 Redis를 사용하지않는 편이 좋다.
물론 데이터를 저장하는 방법으로 RDB,AOF를 제공하기는 하는데, 무거워서 잘안쓰고 애초에 Redis의 목적과도 안맞아서 잘 안쓴다고 한다.
Key,Value로 이루어져있다. Key를 기반으로 조회를 함.
Redis Collection이 존재 (String,List(Dequeue),Set,Hash)
SortedSet이라는 기능을 제공하는데, 게임쪽에서 랭킹을 메길 때 사용한다고 한다. Key를 기준으로 정렬을 수행. 자바의 TreeSet이랑 비슷한듯?
Redis 공식 사이트에 명령어 마다 Time Complexity를 보여주기 때문에 보고 사용할 것.
https://redis.io/commands 도큐먼트가 잘되어있다.
한 명령어가 실행 중일 때 다른 명령어는 Queue에 쌓여서 대기한다. 때문에 특정 명령의 처리가 느리다면 다른 명령들도 영향을 받는다.
그래서 가급적이면 사용하지 말아야할 명령어 중 KEYS라는 명령어가 있다. Redis에 저장된 모든 명령어를 가져오는 명령어인데 시간 복잡도 또한 O(N)이다.
SingleThread
기반이므로 TPS 2만정도에서 부하를 받기 때문에 확장성을 고려해야한다.Redis에서 확장을 하는 세 가지 방법이 존재한다.
- Master - Slave 구조에서 Slave를 여러개 둔다. Write는 Master에서만 일어나고 Read는 Slave에서만 일어난다. 문제는 Write가 많이 일어나면 적절하지 못함.
- 여러 인스턴스를 두고 해싱을 통해 레디스로 접근하게 해주는 방법이 있는데 비공식
- 레디스를 여러 인스턴스 노드로 만들어서 클러스터링하는 기술이 생겼다. Redis Cluster라고 부르는 기능이다. 키를 해싱하고 각각의 노드에 접근할 수 있게 해준다.
Redis에서는 성능이 커널과 종속되는 경우가 많기 때문에 모니터링을 하기 원하면 OS를 모니터링하는게 더 빠를 수 있다고 한다.
Pub/Sub 모델을 제공하는데, 이는 채널로 연결된다. MQ와 유사해보이지만 다른점은 메시지의 유실에 대한 처리를 하지 않는다는 점이다. 그리고 Kafka 보다 속도가 빠르다고 한다 (Wow)
Redis에서는 Transaction 기능이 존재한다. 낙관적 Lock을 사용한다.
여러 대의 서버가 하나의 데이터에 접근할 경우 Distributed Lock을 제공한다. 이름은 Redlock
싱글 쓰레드라고 하더라도 여러 서버의 명령의 순서를 보장하지는 않는다. 이때 1번 서버가 값을 변경하고 2번 서버가 값을 변경하는 명령어를 같은 시점에 보낼 때 RaceCondition이 발생할 수 있고 이를 막기 위해 Redis에서 제공하는 Trasaction 기능을 사용할 수 있다.
레디스 클러스터
M-S 구조에서 센티넬이 주키퍼와 비슷한 역할을 수행하여 Fail-Over가 가능하다.
앱서버와 마스터 사이에는 DNS가 존재하고 마스터가 죽으면 슬레이브의 주소를 DNS에 등록시켜서 Master로 승격시킨다.
레디스 클러스터에서는 센티넬과 DNS가 필요없고, 다음과 같은 구조를 갖는다.
Slot이 일반적으로 16000개 정도 존재하는데, 일반적으로 N 등분을 하여 분배한다.
앱서버에서 들어온 Key를 해싱하여 해당하는 M-S에 들어간다.
Redis에서는 키를 가급적 많이 나누는 것이 좋다고 한다.
RDB, AOF에 관하여
Full-BackUp - DB의 전체 데이터를 저장
Increamental-BackUp - 어떤 시점으로부터 발생하는 DML, DDL을 순차적으로 쿼리나 로우데이터로 저장
Redis의 RDB는 Full-BackUp을 사용.
RDB는 Redis의 프로세스를 그대로 Fork뜨기 때문에 메모리 사용량이 X2가 된다.
만약 Fork할 때 메모리가 부족하다면 메모리 확보가 될 때 까지 계속 실패함.
그리고 Fork 뜨기 때문에 OOM이 발생할 수도 있다.
해당 시점의 Redis의 데이터를 파일로 남기는 용도로 사용한다.
당연히 시점이 지나도 파일과 현재 Redis 영구 데이터간의 싱크는 발생하지 않는다.
그래서 AOF라는 기능이 존재한다.
AOF는 Increamental-BackUp를 사용한다.
AOF는 점진적으로 기록한다. 특정 시점 이후 명령어들을 기록하기 때문에 Redis와 영구 데이터간의 싱크를 맞춰놓을 수 있다.
일반적으로 DB를 저장하는 방식이 처음에 Full-BackUp을 하고 그 다음부터 Increamental-BackUp를 사용한다고 한다.
카카오에서 Redis를 요청하면 기본적으로 AOF로 설정해준다고 한다.
문제는 AOF의 경우 명령이 많을 경우 FailOver에 많은 시간이 걸릴 수 있기 때문에 체스터
는 가급적이면 Master-Slave로 요청하는 편이 좋다고 추천해주셨다.
왜냐하면 Master-Slave는 싱크를 비동기로 맞추는데 이 시간이 매우 짧고, 그래서 Master가 죽었을 때 Slave를 마스터로 승격시키는 비용이 AOF로 매 명령어 마다 저장하는 것 보다 더 저렴하기 때문이라고 한다.
그러나 Redis의 사용 목적이 영구 데이터 저장이 아닌 만큼 가급적이면 이 기능은 꼭 필요한 경우가 아니라면 사용하지 않는 편이 좋다고 한다.
Redis의 메모리 세그멘테이션이란?
직역하면 메모리 파편화
레디스에서는 데이터를 작게, 일정한 크기로 잡는 것이 좋다.
작고 일정하게 잡음으로써 메모리 파편화를 막을 수 있다.