레디스 운용 관리
데이터 영속성
- 레디스는 인메모리 DB 특성 상 기본적으로 모든 데이터를 메모리에서 처리하기 떄문에 서버가 재시작되면 데이터가 유실 될 수 있다.
- 캐시로 사용한다면 성능상의 이슈는 발생할 수 있지만 데이터 휘발성이 큰 문제가 되지 않는다.
- 그러나 캐시 미스로 인해 RDBMS에 다시 데이터를 요청할 때 성능에 어느 정도 영향을 미치는지, 과부하가 발생하지 않는지 등을 충분히 검토해야 한다.
- 캐시가 아닌 데이터 저장소처럼 데이터 영속성을 전제로 운영하는 경우
- 영속성을 위한 설정이 있지만, 영속성 관련 기능을 모두 활성화하는 것은 권장하지 않는다.
- 성능과 내구성의 타협점을 찾고 그에 맞춰 설정해야 한다.
- 레디스는 snapshot과 AOF 두가지 방법으로 데이터 영속성 보장
- snapshot, AOF, snapshot + AOF, 영속성을 사용하지 않는 4가지 방법이 있고, 이 방식을 사용해 백업을 만들 수 있다.
- 기본적으로 snapshot 이 기본값으로 설정되어 있음
스냅샷
- 특정 시점의 DB 내에 있는 내용을 RDB(Redis Database)라는 형식의 파일로 저장
- 수동에 경우 SAVE(동기), BGSAVE(비동기) 명령어 사용
- SAVE 명령어는 동일한 스레드내에 RDB 파일을 생성하기 때문에 Dump 중에 다른 요청은 차단되므로 실제 운영에선 사용하지 않는다.
- BGSAVE는 RDB 덤프하기 위한 자식 프로세스를 포크처리하여 생성한 후 자식 프로세스가 데이터 세트 전체를 임시 RDB 파일로 덤프한다.
- 이후 덤프처리가 완료되면 RDB 파일 이름 변경
- 자동으로 설정하면 정해진 시간 내에 최소 몇개의 키가 변경되었는지 기준 설정
- RDB 파일을 덤프하기 위한 자식 프로세스를 생성할 때는 CoW(Copy On Write) 메커니즘을 사용해 메모리를 확보
- RDB 파일은 Amazon S3 등에 저장하여 운영할 수 있으며, 복원을 위해 지정한 디렉터리에 배치하여 실행
- 그 외 파일 압축, 체크섬 등 튜닝할 수 있다.
- 백그라운드에서 snapshot 처리에 실패하게 되면, 기본적으로 쓰기 작업 요청을 수락하지 않는다.
AOF(Append Only File)
- snapshot의 단점은 레디스에 장애가 발생하면 이전 snapshot 이후 데이터는 당연히 손실된다.
- 반면 AOF는 거의 실시간 백업 처럼 작성중인 파일 끝에 계속 추가하여 기록하기 때문에 내구성이 높다.
- AOF는 자동 생성만 할 수 있다.
snapshot과 AOF 비교
- snapshot 장점
- 특정 시점의 상태를 덤프하며 파일 크기가 작다
- 자식 프로세스의 포크 처리 시에만 성능 영향을 미치며 나머지 처리는 백그라운드에서 수행되어 성능에 미치는 영향이 작다
- snapshot 단점
- 데이터 손실 가능
- AOF 장점
- 데이터 내구성이 높다
- AOF 단점
- 트랜잭션 로그를 REDO 로그 형태로 기록하며, 실제 데이터를 기록하지 않기 떄문에 같은 데이터 세트라도 AOF 파일 크기가 더 커질 수 있다.
- snapshot 보다 성능 저하에 미치는 영향이 더 크며 레디스 서버를 시작할 때 파일 로딩에 시간이 걸릴 수 있다.
데이터 삭제 패턴
- 데이터 손실될 수 있는 상황
- 엔진 재시작
- 레디스 서버 전체 장애
- 명령어 실행(DEL, FLUSHALL, UNLINK ..)
- TTL 만료 (EXPIRE, SET 명령어의 EX 옵션)
- 강제 제거
- 비동기 레플리케이션
- 레디스 클러스터의 네트워크 단절
- 기타 (키 이름 재설정 등)
- 레디스 레플리카는 비동기 형태를 취하기 때문에 반영되지 않은 상태에서 마스터가 다운되면 데이터 손실이 발생할 수 있다.
- 네트워크 단절 영향이 있을 수 있다.
- AWS Elasticache 관리형에 경우 데이터 삭제 복원에 대해 이해 필요
- 장애 감지 및 자동 복구
- ElastiCache는 기본 노드(Primary)나 읽기 전용 복제본(replica)에서 장애가 발생하면 이를 자동으로 감지하고, 해당 노드를 오프라인 상태로 전환한 뒤 새 노드를 생성하고 동기화
- 읽기 전용 복제본이 장애 시, 동일한 가용 영역(AZ)에서 대체 노드를 자동으로 생성. 이 기간에도 애플리케이션은 다른 복제본과 기본 노드 사용 가능
- 자동 장애 조치(Automatic Failover)
- 다중 AZ 구성에서는 기본 노드에 장애가 발생하면 가장 최신 데이터를 가진 읽기 전용 복제본이 자동으로 Primary로 승격
- 기존 엔드포인트를 계속 사용할 수 있어 애플리케이션 변경 불필요
- 장애 감지~복구까지 일반적으로 6분 이내 완료. 장애 조치 중에는 아웃풋 메시지로 상태 변경을 알리므로 모니터링 가능
- 재해 복구/데이터 손실 가능성
- Redis 복제는 비동기식이므로, 장애 시점에 따라 소량의 데이터가 손실 가능
- ElastiCache는 복제 지연이 가장 짧은 최신 복제본을 Primary로 선택해 데이터 손실을 최소화
- 전체 클러스터 장애(모든 노드에 장애 발생)와 같은 극히 드문 경우에는 데이터가 완전히 손실될 수 있으며, 이 경우 백업 또는 스냅샷으로 복구해야 한다.
- 백업 및 복원
- 관리 콘솔 또는 API를 통해 자동 또는 수동 백업(스냅샷)을 설정할 수 있으며 장애나 데이터 손실 시, 이전 시점의 데이터로 클러스터를 복원 가능
- 운영 자동화
- 노드의 상태 감지, 장애 복구, 패치, 백업, 가용성 유지 등은 AWS가 자동화하여 관리합니다.
- 장애 조치 시 주의 사항
- 고객이 직접 실행하는 노드 재부팅은 자동 장애조치를 트리거하지 않습니다.
- 장애 감지 및 자동 복구
모범사례
TTL 설정
- 레디스를 캐시 서버로 사용하는 경우, 기본적으로 데이터가 소실되어도 큰 문제가 없는 데이터 저장
- 데이터 키에는 캐시에 보관할 최소 시간을 TTL로 설정하고, 시간이 지나면 만료되도록 설정하며 TTL을 통해 데이터가 노후화되는 것을 방지할 수 있다.
제거 정책 설정
- 메모리 사용량이 maxmemory 지시자로 설정된 값에 도달하면, 레디스는 메모리 확보를 위해 키를 제거한다.
- 제거 방식은 maxmemory-policy 지시자로 설정된 정책에 따라 결정
- TTL이 설정된 키를 대상으로 volatile- 로 시작하는 정책 선택
- 데이터 저장소로 사용하는 경우, 모든 키를 대상으로 allkeys- 로 시작하는 정책 선택
- LRU, LFU, 랜덤, TTL 기반으로 한 정책 선택은 데이터 특성을 고려하여 설정해야 한다.
백업
- 백업 방법으로 AOF, snapshot 중 snapshot을 사용하는 경우 메모리 확보, 생성 시점, 레플리카로부터 생성하기 등 설정을 할 수 있다.
- 포크를 통해 생성된 새로운 스레드로 RDB 파일이 생성되는 방식으로 메모리 할당은 CoW 방식 사용
- CoW(Copy on Write) 란, 메모리 할당 및 사용을 최적화하기 위한 기법
- 데이터의 복사가 요청될 때 실제로는 복사를 즉시 수행하지 않고, 원본 데이터와 복사본이 메모리를 공유하도록 하다가 실제 내용이 변경(쓰기)될 때 그 시점에 복사를 수행하는 방식
- 새로운 스레드는 부모 스레드와 같은 범위의 메모리 영역을 사용하며 마스터와 레플리카에 변경이 발생하면 개별적으로 메모리 영역을 준비해 분리하여 사용
- 관리형 서비스에 경우 데이터 이외 용도로 사용하는 메모리 영역을 예약할 수 있으며 25% 정도의 메모리만 확보해도 충분
- ElastiCache는 reserved-max-memory-percent 지시자를 제공하며 메모리가 부족할 때 포크없이 스냅샷을 생성할 수 있다.
커넥션 풀링
- 매번 새롭게 연결을 만들면 그에 따른 비용과 오버헤드가 발생하기 때문에 클라이언트에서 커넥션 풀링 기능을 제공한다.
- 연결 재사용으로 처리 효율성을 높일 수 있다
- 최대 동시 연결수는 maxclients 지시자로 설정 가능하며 기본값은 10,000 이다.
- 관리형에 경우 65,000으로 고정되어 변경할 수 없는 경우도 있다.
- 레디스가 열 수 있는 파일 디스크립터의 최대 개수는 커널에 의해 소프트 제한이 걸려 ㅣㅇㅆ다.
- 클라이언트의 최대 개수에 32를 더한 값이 상한선으로 결정된다
- 32는 데이터의 영속성, 소켓의 리스닝, 로그 파일등의 내부 작업을 위해 필요한 개수
재시도 처리
- 클라이언트와 서버간 통신이 일시적으로 중단되었을 때 클라이언트 측에서 재시도 처리를 수행하는 것이 효과적일 수 있다.
- 재시도 횟수, 타임아웃 값, 재시도 간격, 횟수 등의 설정을 중요한 요소로 고려해야 한다.
- 재시도 방법은 지수 백오프 알고리즘에 기반한 방법이 좋다.
- 지수 백오프 알고리즘이란 대기 시간(wait time)*을 점진적으로(지수적으로) 증가시키는 재시도 전략으로
- 대기 시간 = 기본 대기 시간 × 2^ 재시도 횟수 공식 사용
기타 모범 사례
- 클라이언트 측에 설정된 소켓 타임아웃 시간
- 값이 너무 작으면 레디스 서버에 부하가 증가할 때마다 타임아웃 오류가 자주 발생할 수 있고, 너무 크면 연결 문제를 감지하는 데 오래 걸릴 수 있다.
- 레디스 서버에 연결하기 위해 FQDN(Fully Qualified Domain Name)을 사용하고 잇고 DNS 캐시를 사용하는 경우 TTL을 작게 설정하는 것이 좋다.
캐시 노드 크기 조정
크기 조정 기준
- 레디스 클러스터
- 클러스터를 구축하는 경우 최소 3개의 캐시 노드를 마스터로 설정해야 한다.
- 클러스터를 구성하고자 판단할 때에는 주로 부하가 높은 쓰기 작업을 처리하는 경우거나 높은 가용성이 요구되는 경우인지 판단 필요
- 클러스터 내부 동작 방식 이해 필요
- 여러 노드로 구성된 분산 시스템으로, 데이터를 해시 슬롯 단위로 분산 저장하고, 마스터-슬레이브 구조를 통해 고가용성과 자동 장애 조치(Failover)를 제공
- 해시 슬롯 기반 샤딩
- 모든 키는 CRC16 해시 연산을 통해 0~16383 사이의 16,384(2^14)개 해시 슬롯 중 하나에 매핑
- 각 마스터 노드는 특정 슬롯 범위를 담당하며, 키가 어느 슬롯에 속하는지에 따라 저장 위치가 결정
- 슬롯 분배 정보는 모든 노드에 공유되어 데이터 요청이 효과적으로 분산됩니다.
- 마스터-슬레이브 구조
- 마스터 노드마다 최소 하나 이상의 슬레이브 노드를 두며 마스터 장애 시 슬레이브가 자동으로 승격되어 서비스 연속성을 확보
- 마스터는 읽기/쓰기 요청 처리, 슬레이브는 실시간 복제를 통해 장애 상황 발생 시 복구를 지원합니다.
- 노드 간 통신 방식
- Gossip Protocol
- 모든 노드는 주기적으로 다른 노드와 상태 정보를 교환(ping/pong)하여 장애를 감지합니다.
- 과반수 이상의 노드가 장애 상태에 동의하면 해당 노드가 Fail로 선언됩니다.
- Full-mesh & Cluster Bus
- 노드들은 전용 채널(일반 Redis 포트 + 10000, 예: 6379→16379)을 통해 내부 메시지와 상태 정보를 교환합니다.
- Gossip Protocol
- 클러스터 특징 및 제한
- 데이터베이스 분할 불가(DB0만 사용): 클러스터 모드에서는 하나의 DB(0번)만 사용 가능하며, 내부적으로 분할되어 저장
- Multi-key 연산 제한: 키들이 같은 슬롯에 있을 때만 정상적으로 동작
- 확장성 & Rebalance: 노드를 추가·삭제 시 슬롯 재분배를 통해 자동으로 데이터와 부하를 분산 가능
- 고가용성 및 장애 처리:
- 장애 발생 시 슬레이브 승격(Auto Failover)을 통해 즉시 복구가 이루어집니다.
- 네트워크 파티션 등 다양한 장애 상황도 Gossip 프로토콜과 과반수 판정 방식으로 관리
- 실제 용도에 맞는 요구사항 추정
- 전체 데이터 양, 최대치일 때 키의 개수, 키 당 평균 크기 및 최대 크기, 초당 키의 작업 수, 트래픽, 명령어 내역 등 고려
- 클라우드 크기 조정
- 클라우드 서비스를 사용하는 경우, 백업 기능 지원 여부, 노드 크기별 특성, 레디스 버정 별 엔진 기능 등도 고려
보안
- ACL(Access Control List - 접근 제어 목록) 기능을 사용하거나 사용자 입력을 검증한느 중간계층을 추가하는 방식 권장
보안 설정
- 네트워크 보안
- bind 지시자를 통해 IP 주소 지정 가능
- TLS 기능 사용
- redis-cli는 –tls 옵션을 사용할 수 있느며 클라이언트가 지원하지 않는 경우 Spiped, stunnel 같은 프록시 사용 가능
- 기본적으로 보호모드가 활성화 되어 있다
- 루프백 인터페이스와 유닉스 도메인 소켓에서만 접근 가능
- 명령어 제한
- 외부로부터 명령어 실행을 방지하기 위해 특정 명령어를 비활성화할 수 있다.
- rename-command 지시자를 사용하여 CONFIG/FLUSHALL/FLUSHDB 같은 명령어 제한을 둘 수 있다
- 인증
- requirepass 명령어를 통해 설정 파일에 패스워드 설정 인증 기능 제공
- AUTH 명령어를 통해 패스워드를 지정하고 연결할 수 있다
ACL 기능
- 유스 케이스
- 신뢰할 수 없는 클라이언트에 접근을 허용하지 않고, 신뢰할 수 있는 클라이언트에게만 최소한의 접근 권한 부여
- 특정 명령어나 키만 지정하여 접근 허용 가능
- 사용자의 실수 예방
- 버그로 인한 의도하지 않은 키 조작 방지
- 관리형 서비스
- 신뢰할 수 없는 클라이언트에 접근을 허용하지 않고, 신뢰할 수 있는 클라이언트에게만 최소한의 접근 권한 부여
- ACL 기능을 통한 제어 내용
- ACL LIST 명령어로 레디스 서버 내에 사용가능한 사용자 및 접근 제어 상세 내용 확인 가능
- ACL CAT «CATEGORY_NAME» 형태로 카테고리에 포함된 명령어 확인 가능
- ACL 기능 설정 방법
- 제어 방법
- ACL SETUSER 명령어
- 설정 파일에 user 지시자 지정
- 설정 파일에 aclfile 지시자를 통해 acl.conf 와 같은 외부 파일 지정
- 제어 방법
벤치 마크
- 레디스 처리 속도는 CPU, Bandwidth, 데이터 크기, 캐시 히트율, RTT 등 다양한 요인의 영향을 받는다.
- RTT(Round Trip Time): 요청에서부터 응답까지 왕복 시간 의미
- redis-benchmark 명령어를 사용하면 앞서 언급한 요소들에 대한 벤치마크를 수행할 수 있다.
- 실제 상황을 고려해 레디스 클라이언트 수, 데이터 크기, 사용하는 명령어 등을 변경하여 상황을 설정할 수 있다.
- 파이프라인을 사용할 때 성능 향상 정도도 확인할 수 있다.
$ redis-benchmark -h 127.31.3.238 -p 6379 -n 10000 -r 1000 -P 10 -c 100 -d 15 // h: host, p: port, n: 요청 총 합계, P: 파이프라인을 통해 처리될 요청 수, c: 병렬 접속할 클라이언트 수 // r: set, get, incr, lpush 등 명령어에 사용할 키 공간 크기 설정 // d: set, get 명령어를 수행할 때 전송할 데이터 크기를 바이트 단위 지정
- 명령어 별로 초당 요청 수 및 전체 요청의 처리에 걸린 시간, 지정한 매개변수의 값과 함께 시간이 걸린 요청의 분포도를 확인 가능
- q 옵션을 사용하면 명령어 별 요청 수와 처리 시간, t 옵션을 사용하면 벤치마크할 명령어 지정 가능
- 주의 사항
- 가상적인 상황을 재현하여 테스트하는 것
- 실제로 애플리케이션을 배포하고 트래픽을 받을 때는 벤치마크로 커버되지 않아 참고용으로 사용하는 것이 좋다.
멀티스레드 처리
- 레디스는 주로 싱글 스레드로 요청을 처리하지만 부분적으로 멀티스레드로 처리
- UNLINK 명령어는 삭제할 키를 먼저 백그라운드 큐에 넣어 처리하기 때문에 다른 스레드에 의해 비동기적으로 삭제
- 레디스 6.0 이상부터는 옵션으로 I/O 부분의 멀티 스레드 처리 활성화 가능
- 메인 스레드로 연결 설정 요청을 받는 다.
- 그 후 소켓을 생성하고 읽기 작업을 대기하는 큐에 정보를 넣는다.
- 메인 스레드에서 읽기 이벤트를 처리를 마친 후, I/O 스레드에 순서대로 작업 할당
- I/O 처리 부분을 여러 스레드가 분담하여 처리할 수 있게 된다.
- io-threads 지시자로 스레드 개수 설정 가능
- 데이터 접근 부분을 멀티 스레드를 사용하면 메모리 공유에 대한 락 경쟁 필요
트러블슈팅
INFO 명령어로 서버 정보 읽기
- 레디스 서버 상태 파악을 위해 사용
- Server: 레디스 서버 관련 일반 정보
- 서버 버전, 재시작되지 않았는 지 확인, 서버 시작 경과 시간, 적재된 설정 파일 확인할 때 사용
- Clients: 클라이언트 연결 정보
- 현재 클라이언트의 연결 현황 등
- blocked_clients 는 BLPOP 명령어와 같이 블로킹 연산이나 WAIT 명령어로 인해 대기중인 클라이언트 수
- Memory: 레디스 서버 메모리 사용 상황
- Persistence: RDB/AOF 정보
- Stats: 통계 일반
- 다양한 통계 데이터가 집약되어 있다.
- 연결 수 확인: 현재 연결된 수는 rejected_connections의 제한값에 도달했는지, total_connections-received 기반으로 계산하여 호스트의 제한 값에 도달했는지 확인 가능
- 레플리카: sync_*로 완전 동기화 또는 부분 동기화가 진행되었는지 확인 가능
- keyspace_miss, keyspace_hits 계산으로 운영 관리에 중요한 정보도 포함
- Replication: 마스터/레플리카 정보
- 레플리카에 문제가 발생했는지, 개수나 각각의 지연 상태, 연결 상태등을 확인
- CPU
- Modules: 적재된 모듈에 대한 추가 정보
- Commandstats: 명령어 통계
- 레디스 서버 내에 실행된 명령어 별 호출 횟수, 명령어 실행 총 CPU 시간, 평균 CPU 시간, 호출 거부 횟수, 실패 횟수 등
- Errorstats: 레디스 내에 발생한 다양한 오류 추적 정보
- 오류 통계
- Latencystats: 지연 시간의 백분위 분포 통계
- 지연 시간 통계
- Cluster: 클러스터 정보
- 현재 실행중인 서버에 클러스터 모드가 활성화되어 있는 지 여부
- Keysapce: 데이터베이스 관련 정보
- 키 관련 정보로 키 개수, 만료된 키 개수, 평균 TTL 확인 가능
- Server: 레디스 서버 관련 일반 정보
- INFO 명령어를 실행하면 Commandstats 부분을 제외한 모든 부분 표시
- INFO ALL을 하면 Commandstats 포함
- INFO EVERYTHING 명령어를 실행하면 모듈이 생성한 부문도 포함하여 모든 부문 표시
지연 시간 조사
- INFO 명령어의 Commandstats 부문에서 각 명령어의 실행 횟수와 평균 소요 시간을 확인할 수 있다.
- 슬로우 로그와 지연 시간 모니터링을 함께 활용하면 더 자세히 파악할 수 있다.
- KEYS 명령어나 루아 스크립트, 트랜잭션 처리 및 계산량이 많은 명령어 영향이 있는 지 확인 필요
슬로우 로그
- 설정파일에 아래 지시자를 통해 로그로 기록할 수 있다
- slowlog-log-slower-than
- 마이크로 초 단위로 임계값 설정, 오래 걸린 쿼리 기록
- slowlog-max-len
- 레디스 서버가 유지할 엔트리 수 지정
$ SLOWLOG GET 10 // 지정한 수만큼 조회할 수 있다. $ SLOWLOG LEN // 슬로우 로그의 엔트리 수 확인 $ SLOWLOG RESET // 슬로우 로그 통계 초기화
- 레디스 서버가 유지할 엔트리 수 지정
- slowlog-log-slower-than
redis-cli 옵션
- 지연 시간 검출 옵션을 통해 지연 시간 확인 가능
- latency: 지연 시간 정보 수집 (min, max, avg)
- latency-history: latency와 동일하며 15초 단위로 줄바꿈
- latency-dist: 지연 시간과 비율에 따라 색상으로 구분된 스펙트럼 표시
- intrinsic-latency: 지정한 시간만큼 시스템 고유 지연 시간 측정
지연 시간 모니터링
- 지연 시간 모니터링 기능을 통해 지연 시간 관련 트러블 슈팅 활용 가능
- info commandstats, redis-cli latency 명령어 외에 원인을 파악하기 어려운 경우 지연시간 모닝터링 기능을 사용하는 것이 좋다.
- 이벤트별로 지연 시간 스파이크를 시계열로 기록할 수 있다.
$ LATENCY HELP // 여섯가지 하위 명령어 설명 제공
메모리 문제
- MEMORY 명령어를 통해 메모리 사용량을 확인할 수 있으며 INFO 명령어보다 더 자세히 확인 가능
- HELP 명령어를 통해 하위 명령어 확인 가능
$ MEMORY HELP
- DOCTOR 명령어를 사용하기 위해선 메모리가 필요하며 부족할 경우 진단 실패
- MALLOC-STATS 명령어는 할당자의 내부 통계 정보 확인 가능
- PURGE 명령어는 더티 페이지 회수 지시
- USAGE 명령어는 키와 그에 연관된 값, 오버헤드를 포함하여 데이터를 저장하는 데 필요한 메모리양의 크기를 나타낸다