본문 바로가기

CS ﹒ Algorithm/Database

강대명님의 우아한 Redis 정리

Redis의 Collection에 대해 알아보던 중 배달의 민족에서 운영하는 우아한 Tech 채널에서 강대명님께서 강연하신  캐시의 모든 것 영상을 시청하고 학습을 위해 정리한 글입니다.

 

 

 

1. 왜? 언제? 어디서?

 

1-1. Cache

 

- 왜 캐시를 사용하는가?

(1) 나중에 요청될 데이터를 미리 저장해놨다가 빠르게 반환하기 위함. (Like DP)

(2) 저장 매체별 접근 속도가 다르기 때문. (L1 -> L2 -> L3 -> Memory -> Disk) 

(3) 파레토 법칙에 의해 전체 요청의 80%는 20% 지점에서 일어난다. 따라서 해당 부분을 캐싱하는 것이 효율적이다.

 

80:20의 법칙으로도 많이 알려져 있다.

 

- 어떤 형태로 주로 사용하는가?

(1) Look aside Cache

: 캐시에서 데이터를 먼저 조회하고, 만약 캐시에 해당 데이터가 없다면 DB에서 조회한다.

(2) Write Back

: 캐시에 우선 저장하고, 이후 일정 주기마다 DB에 해당 데이터를 동기화한다.

대표적인 사용 예시는 서버 로그 같이 빈번하게 저장해야하는 데이터의 경우 레디스를 활용할 수 있다.

 

- 왜 Redis인가? 다른 선택지들은?

(1) Collection의 존재로 인해 Memcached에 비해 개발 편의성이 증가.

: 마치 Python과 C의 개발 편의성의 차이와 같다.

(2) Ranking Server를 구현할 때 Redis와 DB의 차이점을 생각해보자.

: DB에서 유저를 매번 쿼리로 불러올 경우 유저 수가 많아질 수록 성능 저하가 발생한다.

인메모리 서버는 sorted set 하나로 쉽게 구현 가능하고 replication도 가능하다.

(3) 특정 데이터를 KEY / VALUE형태로 저장하는 경우 DB와 REDIS의 차이점을 생각해보자.

: DB에서는 동시에 여러 데이터가 삽입되는 경우 동시성 문제가 발생할 우려가 있다.

그러나 REDIS는 싱글 쓰레드이므로 RaceCondition의 우려가 상대적으로 적다. ("따닥"은 레디스에서도 문제다 ㅎㅎ)

 

- Redis의 주된 사용처는?

(1) Remote Date Store 

: 서버간 데이터 공유 시 활용 가능하다.

(2) 한 대에서만 필요하면 전역변수로 해결 가능하지 않니?

: 싱글 쓰레드이므로 원자성을 보장해주는 것이 크다.

(3) 인증 토큰 등을 저장

(4) 랭킹 보드

(5) API Limiter

 

- Collection 사용 시 주의점은 없는지

(1) 모든 데이터를 가져오는 명령을 주의해야 한다.

(2) Sorted Sets의 Score는 Double 타입이므로 프론트에 전송 시 String 형태로 전송하는 것이 좋다.

(3) 하나의 컬렉션에 데이터를 1만개 이하로 유지하는 것이 좋다.

 

 

 

 

2. Redis의 운영

 

2-1. 메모리 관리

 

(1) 메모리 관리의 중요성

- Redis는 In-Memory Data Store이므로 Physical Memory 이상을 사용하면 문제가 발생한다.

- Swap이 있다면 Swap으로 인해 Page Fault 발생 시마다 느려지며, 없으면 서버가 죽는다.

- MaxMoemory를 설정해도 안전하지 못하며 RSS 값을 직접 모니터링해야 한다.

- 실제로 수많은 사람들이 현재 메모리에 Page Fault가 발생한다는 사실을 인지하지 못하고 사용하고 있음.

 

(2) 메모리 관리 방법

- fork할 때마다 전체 메모리의 일정 비율을 사용하게 되므로 큰 메모리의 인스턴스 하나보다 작은 메모리의 인스턴스 여러개가 유리하다

 

(3) 파편화

- 레디스 3.x버전의 경우 used memory와 rss의 값이 엄청나게 차이나는 경우가 비일비재하다.

- 4.x 버전부터 메모리 파편화를 줄일 수 있는 기능이 추가되었으나 버전별 편차가 있을 수 있음.

- 다양한 사이즈의 데이터보다 유사한 크기의 데이터를 가지는 것이 유리하다. (파편화 문제니 당연한 일이다.)

 

(5) 메모리가 부족할 때 해결책

- 메모리가 많은 장비로 마이그레이션하거나, 있는 데이터를 줄이는 수 밖에 없다.

- Hash, SortedSet, Set은 메모리 단편화도 많이 일어나고 내부적으로 추가 자료구조를 사용하므로 공간을 많이 차지한다. 따라서 ZipList 설정을 통해 메모리를 절약할 수 있다.

- 인메모리 특성상 개수가 많지 않다면 선형 탐색도 빠르다.

 

(6) O(N) 명령어를 주의해야 한다.

- 대표적으로 KEYS, FLUSHALL, FLUSHDB, delete Collections, Get All Collections가 있다

- Redis는 싱글 스레드이므로 모든 작업을 순차적으로 처리하고, 한 번에 시간이 오래 걸리는 작업이 투입될 경우 나머지 작업이 모두 정체된다.

- 모니터링을 위해 KEYS를 남발하거나 거대한 자료구조에서 모든 데이터를 가져올 경우 일시적으로 서버가 중단된다.

- scan 명령을 사용함으로써 KEYS 명령어를 대체할 수 있다.

- Collection은 애초에 여러개 컬렉션으로 나눠서 저장하거나 분할해서 가져와라.

 

 

2-2. Replication

 

(1) Redis의 Replication 과정

- Secondary에 replicaof 명령 전달

- Secondary는 Primary에 Sync 명령 전달

- Primary는 현재 메모리 상태 저장을 위해 Fork()

- Fork한 프로세서는 현재 메모리 정보를 Disk에 dump()

- 해당 정보를 Secondary에 전달

- Fork 이후의 데이터를 Secondary에 계속 전달

 

(2) Redis에서 Replication할 시 주의점

- Replication 과정에서 fork()로 인해 메모리가 부족해질 수 있음(Redis -cli --rdb도 마찬가지): 단, AWS ElasticCache 등은 보다 안정적임

- 여러 Redis가 동시에 Replica를 두고 있을 때, 재시도를 동시에 시도되도록하면 문제가 발생할 여지가 있음.

 

(3) redis.conf의 권장 설정

- Maxclient 50000

- RDB/AOF Off- KEYS disable: 전체 장애의 90% 이상이 KEYS와 SAVE 설정으로 인해 발생한다.

- 적절한 ziplist 설정

 

 

 

2-3. 분산처리

 

(1) Consistent Hashing- 분산 시마다 리밸런싱 된다면 부하가 발생하기 때문에, 해싱하여 자신의 해시값보다 크지만 가장 가까운 값을 가진 서버로 배치하는 방식을 사용한다.- 서버가 추가/삭제되더라도 해당 서버에 해당하는 데이터들만 이동하므로 1/N만큼의 부하가 발생한다.

 

(2) Sharding- 특정 Range로 범위를 정하고 해당 레인지에 저장할 경우 구현이 간단하나 특정 서버에 부하가 집중될 수 있음.- Module 방식의 경우 데이터가 배수로 이동하기 때문에 Module이 추가/삭제될 때마다 부하가 발생함

 

(3) Cluster

- 해시 기반으로 슬롯을 구분하며, CRC 16 알고리즘을 사용한다.

- 특정 서버는 Slot range를 가지고 있고, 데이터 마이그레이션은 해당 슬롯의 데이터를 다른 서버로 전달하는 방식으로 이루어진다.

- 자체적인 primary, secondary 장애 극복이 가능한 것이 장점이나 메모리 사용량이 많고 직접 구현 시 별도로 라이브러리 관리가 필요하다.

 

 

 

2-4. 장애극복(Failover)

 

(1) Coordinator

- Zookeeper, etcd, consul등의 Coordinator를 사용한다.

- 해당 기능을 위해 별도로 개발이 필요한 것이 단점.

 

(2) VIP/DNS 기반

- API 서버를 한 곳으로 접속하도록 해놓고 Health Check 결과 응답이 없다면 다른 서버에 VIP/DNS를 할당한다

- 클라이언트에서 추가적인 처리가 필요한 것이 단점이다.

- DNS의 경우는 DNS Cache TTL을 관리해야하며 언어, 툴별로 모두 기준이 다르다.

 

 

2-5. 모니터링

 

(1) Redis Info

- RSS

- Used Memory

- Connection

- 초당 처리 요청 수

- 레디스는 싱글 쓰레드이므로 Conenction이나 초당 처리 요청 수의 등락이 심하다면 주의가 필요하다.

 

(2) System

- Cpu

- Disk

- Network rx/tx

 

(3) CPU 사용량이 100%인 경우 

- 실제로 처리량이 많은 경우 CPU 성능이 좋은 서버로 이전해야한다.

- O(N)계열 명령이 많은 경우 Monitor를 통해 원인을 파악해야하며, Monitor 사용 자체가 부하를 주므로 오래 사용해서는 안된다.