Database/Redis

Redis 야무지게 사용하기

kyoulho 2023. 12. 15. 22:37

Redis


Redis는 In-Memory 데이터 스토어다. 서버 재시작 시 모든 데이터를 유실한다. 복제 기능을 사용해도 사람의 실수 발생 시 데이터 복원은 불가능하다. 때문에 캐시 이외의 용도로 사용한다면 적절한 데이터 백업이 필요하다.

  • 단순한 key-value 구조
  • 평균 작업속도 < 1ms
  • 초당 수백만 건의 작업 가능

 

캐시로 사용하기


캐시란?

데이터의 원래보다 더 빠르고 효율적으로 액세스 할 수 있는 임시 데이터 저장소이다.
같은 데이터에 반복적 액세스가 일어날 때, 원본보다 빠른 접근 속도가 필요할 때, 변하지 않는 데이터일 때 캐시를 사용하면 효율적이다.
 

캐싱 전략

읽기 전략 Look-Aside(Lazy Loading)

레디스를 캐시로 쓸 때 가장 일반적으로 사용하는 방법으로 애플리케이션에서 데이터를 읽는 작업이 많을 때 사용하는 전략이다.

  1. 애플리케이션은 캐시에서 데이터를 먼저 찾는다.
  2. 데이터가 없을 때 데이터베이스에서 데이터를 가져온 뒤 캐시에 저장하는 과정을 거친다.

캐시가 다운 되더라고 DB에서 데이터를 가지고 올 수 있다. 하지만 캐시에 붙어있던 커넥션이 데이터베이스로 몰리는 문제가 발생한다.
이럴 때는 Cache Miss(캐시에 데이터가 없음)가 계속 발생하기 때문에 Cache Warming(데이터를 캐시로 밀어 넣기)을 진행해야 한다.

쓰기 전략 Write-Around & Write-Through

Write-Around는 디비에만 데이터를 저장한다. 캐시 내의 데이터와 디비 내의 데이터가 다를 수 있다는 단점이 있다.
Write-Through는 디비에 데이터를 저장할 때 캐시에 함께 저장한다. 두 단계를 거치기에 상대적으로 느리며 사용되지 않는 데이터가 캐시에 저장될 수 있다는 단점이 있다.
 
 

Redis 데이터 타입


구조예제Best Practice
String"I am a default datatype"단순 증감 연산, 카운팅
Bitmaps101001110010010101001데이터 저장공간 절약
정수로 된 데이터만 카운팅 가능
Lists[A -> B -> C -> A -> D]Blocking 기능을 이용해 Event Queue로 사용
키가 있을 때만 데이터 저장 가능(LPUSHX / RPUSHX 명령어)
Hashes{"Name":"kyo", "Birthday": "0707"} 
Sets{A,B,C,D,E,F} 
Sorted Sets{"LG":1, "KT":2, "SSG":3} 
HyperLogLogs00110101 11001110 10101010대용량 데이터를 카운팅할 때 적절(오차 0.81%)
Set과 비슷하지만 저장되는 용량은 매우 작음(12KB 고정되어 저장)
Streams{"ID":"15891235", {"f1":"v1',"f2":"v2"}}로그를 저장하기 가장 적절한 자료구조
append-only
시간 범위로 검색 / 신규 추가 데이터 수신
/ 소비자별 다른 데이터 수신(소비자 그룹)

 

 

데이터 영구 저장


RDB

시간 단위로 파일을 저장할 수 있다.
자동: redis.conf 파일에서 SAVE 옵션
수동: BGSAVE 커맨드를 이용해 CLI 창에서 수동으로 RDB 파일 저장

AOF(Append Only File)

파일 크기 기준으로 압축되는 시점을 지정할 수 있다.
자동: redis.conf 파일에서 auto-aof-rewrite-percentage 옵션
수동: BGREWRITEAOF 커맨드를 이용해 CLI 창에서 수동으로 AOF 파일 재작성
 

RDB vs AOF 선택 기준

백업은 필요하지만 어느 정도의 데이터 손실이 발생해도 괜찮은 경우
RDB 단독 사용한다. redis.conf 파일에서 SAVE 옵션을 적절히 사용한다.
ex) SAVE 900 1 (900초 동안 1개 이상 키가 변경되었을 때 RDB 파일을 재작성하라)
 
 
장애 상황 직전까지의 모든 데이터가 보장되어야 할 경우
AOF 사용한다. APPENDFSYNC 옵션이 everysec인 경우 최대 1초 사이의 데이터 유실 가능이 있다.
 
제일 강력한 내구성이 필요한 경우
RDB & AOF 동시 사용
 


Redis 아키텍처


Replication 구성

마스터와 복제본만 존재하는 단순한 복제 연결이다. 레디스의 복제는 비동기식으로 동작하는데 마스터에서 복제본으로 데이터가 잘 전달되었는지 확인하지 않는다. 이 구조는 마스터에 장애 발생 시 수동으로 변경해야 할 작업들이 많다. 리플리카 노드에 직접 접속해서 복제를 끊어야 하고 어플리케이션에서에 연결 설정을 변경해서 배포하는 작업이 필요하다.


Sentinel 구성

3대 이상의 홀수로 센티넬 노드가 존재한다. 센티넬 노드는 다른 노드를 감시한다. 마스터가 비정상 상태일 때 과반수 이상의 센티넬이 동의하면 페일오버한다. 연결 정보를 변경할 필요가 없다.


Cluster 구성

데이터가 여러 마스터 노드에 자동으로 분할되어 저장(샤딩)되는 구조이다. 모든 노드가 서로를 감시하여 마스터가 비정상 상태일 때 자동 페일오버한다. 최소 3대의 마스터 노드가 필요하고 마스터 노드마다 리플리카 노드를 하나씩 추가하는게 일반적인 구조이다.
 
HA기능(자동 페일오버)이 필요하다면 Sentinel, 서비스의 확장을 위해 스케일아웃까지 필요하다면 Cluster, 단순 복제 기능만 필요하다면 Replication, 복제도 필요 없다면 Stand-Alone
 
 

Redis 운영 꿀팁과 장애 포인트


사용하면 안되는 커맨드

Redis는 Single Thread로 동작한다. 한 사용자가 오래 걸리는 커맨드를 실행한다면 나머지 모든 요청들은 대기하게 된다.

  • keys * -> scan으로 대체
  • Hash나 Sorted Set 등 자료구조는 하나의 키의 최대 100개 이상 저장하지 않기
  • hgetall -> hscan
  • del -> unlink

장애를 막을 수 있는 기본 설정값 변경

STOP-WRITES-ON-BGSAVE-ERROR = NO
 RDB 파일 저장 실패 시 redis로드의 모든 write를 막을 지에 대한 설정으로 기본은 yes이다.

 
MAXMEMORY-POLICY = ALLKEYS-LRU

 메모리가 가득 찼을 때 레디스에 새로운 데이터를 입력에 대한 정책 설정이다. 기본은 noeviction으로 메모리가 가득 차면 더 이상 저장하지 않게 된다. Expire Time 설정하여 volatile-lru(가장 최근에 사용하지 않은 키부터 삭제)나 allkeys-lru(모든 키에 대해 lru 방식으로 키를 삭제)를 권장한다.
 

TTL 값을 너무 작게 설정한 경우

 TTL 값을 너무 작게 설정한 경우 캐시 스탬피드(Cache Stampede)가 발생할 수 있다. 캐시에 많은 요청이 동시에 들어올 때 발생하는 현상을 가리키는 용어로 캐시에서 특정 데이터를 가져오는 동안 여럿이 동시에 해당 데이터를 요청할 때 발생한다.
 Look-Aside 전략에서 레디에서 데이터가 응답을 받은 여러 서버가 동시에 디비에서 같은 데이터를 조회하고 레디스로 같은 데이터를 저장하는 문제가 발생할 수 있다.
 

복제 사용 시 MaxMemory 설정 주의

RDB 저장과 AOF 재작성 시 포크를 통해 자식 프로세스를 생성한다. 원래의 프로세스는 계속해서 일반적인 요청을 받아 데이터를 처리하고 자식 프로세스는 데이터를 파일로 저장하게 된다. 이때 서버의 메모리 사용률이 2배로 증가하는 상황이 발생할 수 있다. 복제 연결을 처음 시도하거나 연결이 끊겨 재시도를 할 때에 새로 파일을 저장하는 과정을 거친다.
 따라서 MaxMemory는 실제 메모리의 절반 정도로 설정하는 게 좋다.
 

물리적으로 사용되고 있는 메모리를 모니터링

  • used_memory: 논리적으로 레디스가 사용하는 메모리
  • used_memory_rss: OS가 레디스에 할당하기 위해 사용한 물리적 메모리 양(더 중요!!)

used_memory와 rss의 차이가 클 때 fragmentation이 크다고 말하는데 주로 삭제되는 키가 많을 때 증가한다. 특정 시점에 키가 피크를 찍고 다시 삭제되는 경우와 TTL로 인해 삭제가 과도하게 많을 경우에 발생한다. 이때 activefrag라는 기능을 잠시 켜두면 도움이 된다.