[Redis] 레디스란? 특징, 활용예시, 비교 정리

레디스란?

Redis는 Remote Disctionary Server의 약자로 키(Key) : 값(Value) 해시 맵과 같은 구조를 가진 NoSQL 데이터베이스이다.

MySQL, Oracle같은 일반 DB와 다르게 하드 디스크(SSD, HDD)에서 데이터를 처리 하는 것이 아니라, 

Redis는 In-Memory(인메모리) 기반의 DB로 메인 메모리(DRAM)에서 데이터를 처리하기 때문에 작업 속도가 월등히 빠르다.

 

DRAM과 SSD, HDD의 비교

 

메모리 계층 구조는 다음과 같이 여러 계층이 있지만 인메모리DB와 일반 DB를 비교하기 위해 2가지에 대해서만 비교 하고 넘어 가고자 한다.

특징 DRAM (메인 메모리) SSD, HDD (하드 디스크)
가격 하드 디스크 보다 비쌈 제일 저렴
지속성 휘발성 비휘발성
속도 하드 디스크 보다 빠름 제일 느림
저장 용량 하드 디스크 보다 작음 제일 큼

(메인 메모리는 휘발성이지만 Redis는 영속성을 보장한다. 그 이유는 아래 특징 목차에서 설명한다.)

 

이처럼 일반 DB에 비해 인메모리DB가 더 가격이 비싸고 용량이 작기 때문에 모든 데이터를 인메모리DB에 저장해서는 안된다.

주로 저장하는 데이터자주 사용되고 수정이 빈번하지 않은 데이터를 저장한다.


레디스 특징

성능

Redis는 데이터를 인메모리에 저장하므로 디스크에 비해 훨씬 빠르게 작업을 수행할 수 있다.

또한 Key-Value 형식으로 데이터가 저장되기 때문에 보다 빠르게 데이터에 접근할 수 있다.

 

다양한 데이터 타입 지원 (Redis 컬렉션)

Redis는 Key에 위 처럼 다양한 데이터 타입을 저장할 수 있도록 지원한다.

이 데이터 타입들을 활용하여 개발 편의성을 극대화 할 수 있다.

이 데이터 타입들을 활용하는 방법은 아래의 블로그에 정말 잘 설명되어 있어 링크를 첨부한다.

 

[REDIS] 📚 자료구조 명령어 종류 & 활용 사례 💯 총정리

Redis 데이터 타입 (Collection) Redis의 장점 중 하나는 Key-Value 스토리지에서 Value는 단순한 Object가 아니라 다양한 자료구조를 갖기 때문이다. String, Set, Sorted Set, Hash, List 등 다양한 타입을 지원한다.

inpa.tistory.com

 

영속성 보장

Redis는 휘발성인 인메모리에 데이터를 저장하기 때문에 "RDB"와 "AOF"를 지원하여 영속성을 보장한다.

- RDB(Redis Database) : 주기적으로 레디스 DB의 스냅샷을 백업하고, 필요 시 특정한 시점의 스냅샷으로 롤업.
- AOF(Append Onl y File) : 모든 쓰기 명령들을 특정한 로그 파일에 기록해두고, 이 로그 파일을 기반으로 서버 재시작/재구성 시 복구.
- No persistence : 영속성을 사용하지 않는 것으로 순수하게 캐시로만 사용.

RDB, AOF 두 방식들 마다 장단점이 있지만 간단하게 언제 어떤 방식을 사용할지에 대해 설명하면 다음과 같다.

  • RDB + AOF : 하드 디스크 DB와 같은 제일 강력한 내구성이 필요할 경우. 
  • RDB만 사용 : 장애 발생 시, 백업은 필요하지만 어느 정도의 데이터 손실이 발생해도 괜찮은 경우
  • AOF만 사용 : 장애 발생 직전 까지 모든 데이터가 보장되어야 할 경우

 

설정 확인 및 변경 Redis가 설치된 폴더의 etc/redis.conf 파일을 확인하고 변경 또는, redis-cli로 명령어를 이용해 확인하고 변경할 수 있다.

나는 Spring Boot에 라이브러리로 추가해서 cli를 사용하는 방식을 사용했다.

(기본설정은 둘다 OFF)

redis-cli

# RDB 설정 확인
CONFIG GET save

# AOF 설정 확인
CONFIG GET appendonly

# RDB 설정 수정
CONFIG SET save "900 1"  # 900초(15분)마다 1개 이상의 키가 변경되었을 때 RDB 파일 재작성

# AOF 설정 수정
CONFIG SET appendonly yes  # AOF 활성화

 

Single Thread 방식

Redis는 싱글 쓰레드이기 때문에, 1번에 1개의 명령어만 실행할 수 있다.  (멀티 스레드를 지원하는 맴캐쉬드와 자주 비교된다.)

하지만 멀티 스레드를 사용하면서 발생하는 컨텍스트 스위칭과 메모리 사용을 줄일 수 있어 빠르게 응답할 수 있고,

Atomic(원자성)을 보장할 수 있다.

 

Pub / Sub 

Publish / Subscribe 란 특정한 주제(topic)에 대하여 해당 topic을 구독한 모두에게 메시지를 발행하는 통신 방법으로 

채널을 구독한 수신자(클라이언트) 모두에게 메세지를 전송 하는것을 의미한다.

하나의 Client가 메세지를 Publish하면, 이 Topic에 연결되어 있는 다수의 클라이언트가 메세지를 받을 수 있는 구조이다.

Redis는 Pub - Channel - Sub 구조를 갖고 있다.

publisher가 Channel에 메시지를 발행하면 해당 Channel을 구독하는 Subscriber들에 메세지를 전송한다.

이 기능은 실시간 채팅, 실시간 스트리밍, 실시간 알림, SNS 피드 등에 사용할 수 있다.


레디스 활용 예시

해당 내용은 직접 Redis를 활용해본 방법들에 대해서만 작성하였다.

이 외에도 정말 많은 활용 방법들이 있지만 추후에 해당 기능들을 적용하고 나면 업데이트 할 예정이다.

 

I/O가 빈번히 발생하는 데이터

우리가 처리하는 데이터 중 찜 수, 판매상품 수 같은 카운트 쿼리 데이터가 가장 I/O가 빈번히 발생한다.

특히 내 프로젝트에서는 사용자별로 사이드바에 찜 수, 장바구니 수들을 카운트 쿼리로 반환된 데이터 수를 view에 뿌려주는데,

사이드바는 여러 페이지에서 노출되어 페이지 이동마다 카운트 쿼리를 호출하게 된다.

그렇기 때문에 매번 카운트 쿼리를 호출하지 않고 해당 데이터를 캐싱 처리하여 카운트 수가 변경되지 않을 경우에 Redis를 통해 해당 수를 반환하도록 하여 RDS의 부담을 줄도록 하였다.

 

세션 관리

서버가 한대일 경우에는 해당 서버에 세션 정보를 저장해서 사용할 수 있겠지만,

만약 scale-out이 적용되어 서버가 N대가 있을 경우에는 서버마다 가지고 있는 세션 저장소에서 세션을 공유하지 않기 때문에 세션 불일치 문제가 발생한다.

하지만 세션 저장소를 따로 만들고 세션 저장소에 세션 정보를 저장하여 공유하여 사용하면 서버가 늘어난다해도 세션 저장소에서 세션 정보만 공유해주면 된다.

특히 Redis를 가장 많이 활용하는 방법이 세션 저장소로 많이 활용 하는데, 이는 key - value 형식의 데이터 처리에 특화되어 있고, 메모리에 저장되어 있기 때문에 속도가 빠르기 때문이다.


레디스 주의할점

O(N) 시간복잡도 명령어 사용 금지

Redis는 Single Thread 서버이기 때문에 시간 복잡도를 고려해야 한다.

싱글 쓰레드이기 때문에 동시에 단 1개의 명령어만 처리할 수 있고 했다.

그렇기 때문에, 하나의 명령어를 처리하는 속도가 오래 걸릴 경우 나머지 명령어들은 대기 상태로 전환되는데, 데이터의 수가 많은 경우 큰 속도 저하를 야기할 수 있다.

특히, O(N)의 시간복잡도를 갖는 대표적 명령어 들 (keys, flushAll, flushDB, delete collections, get all collections)는 운영환경에서 사용을 금지한다.

(keys 명령 대신 scan 명령으로 대체하여 사용)

 

DEL 명령 대신 UNLINK 명령 사용 권장

키에 많은 데이터가 있을 때 DEL 명령으로 삭제하면 그 키를 지우는 동안 아무런 동작을 할 수가 없다.

하지만 UNLINK 명령을 사용하면 백그라운드로 삭제되기 때문에 UNLINK 명령을 사용하는것이 좋다.

 

캐시 만료시간 설정

인메모리 DB는 크기가 한정되어 있기 때문에 key에 대한 Expire Time을 설정하는 것이 권장된다.

만약 메모리가 가득 찼을 경우에는 MAXMEMORY-POLICY 정책에 의해 데이터가 삭제 된다.

- noeviction(default) : 메모리가 가득차면 더 이상 Redis에 새로운 키를 저장하지 않는다. (즉, 메모리가 가득차면 새로운 데이터 저장이 불가능.)
- volatile : 가장 최근에 사용하지 않았던 키부터 삭제하는 정책. expire 설정에 있는 키값만 삭제. (만약 메모리에 expire 설정이 없는 키들만 남아있다면 위와 같은 문제가 발생할 수 있다.)
- allkeys(권장) : allkeys-lru는 모든 키에 대해 LRU방식으로 데이터를 삭제한다. allkeys-lfu는 사용 빈도수가 가장 적은 데이터부터 삭제해준다. (MAXMEMORY로 인해 장애가 발생할 가능성 X)
 
메모리를 줄이기 위한 설정

기본적으로 아래의 Collection들은 다음과 같은 자료구조를 사용한다.

Collection 자료구조
Hash HashTable을 하나 더 사용
Sorted Set Skiplist, HashTable
Set HashTable

그런데 이 자료구조들은 많은 메모리를 사용한다.

따라서 메모리 사용을 줄이고 싶으면 Ziplist를 이용할 수 있다. (속도가 중요하다면 사용 X)

Ziplist를 이용하게 되면 속도는 느려지지만 메모리는  20 ~ 30% 훨씬 적게 사용하게 된다고 한다.

Ziplist를 사용하기 위해서는 redis 설정 파일에서 설정해주어야 한다. (방법은 검색 추천)

 


Redis vs Memcached

key-value 방식의 인메모리 DB로 Redis와 Memcached를 가장 많이 비교한다.

  Redis Memcached
스레드 싱글 스레드 멀티 스레드
데이터 타입 list, string, hashes, sorted sets, bitmaps 등 다양한 자료구조 지원 string과 integer만 지원
데이터 저장 데이터가 메모리와 디스크에 저장되어 데이터 복구 가능하다. 데이터가 메모리에만 저장되기 때문에
장애 발생 및 서버 종료 시 데이터가 유실된다.
처리 속도  Memcached보다는 느리지만 큰 차이는 없다. 디스크를 거치지 않아 redis보다 더 빠르다.
영속성(Persistence) 지원 지원 안함