CS

[CS] Redis의 데이터 구조와 활용(feat.ChatGPT)

처누 2025. 1. 5. 22:39

질문 6: Redis의 데이터 구조와 활용

질문:

Redis는 다양한 데이터 구조를 제공하여 여러 상황에서 효율적으로 사용할 수 있습니다.

  1. Redis에서 제공하는 주요 데이터 구조 5가지를 설명하고, 각각 어떤 상황에서 적합한지 간단히 예를 들어 설명해 주세요.
  2. Redis는 기본적으로 단일 스레드로 동작합니다. 그럼에도 높은 성능을 유지할 수 있는 이유는 무엇이라고 생각하십니까?
  3. Redis의 Persistence(영속성) 옵션에는 두 가지 주요 방식이 있습니다. 이를 설명하고, 각 방식의 장단점을 말씀해 주세요.

내 답변

더보기

1. 죄송합니다. 그 부분까지는 생각을 못해봤습니다.

2. Redis는 캐시 역할로 주요 사용됩니다. 클라이언트의 요청이 생기면 캐시에서 먼저 클라이언트가 요청한 정보를 가져오게되고, 이 과정에서 Redis에 저장된 정보를 바로 반환해줍니다. 그 결과 DB까지 가지 않고도 높은 성능을 유지할 수 있습니다.

3. 죄송합니다. 그 부분까지는 생각을 못해봤습니다. 위는 제 답변입니다. 답변을 하지 못했거나 답변이 부족했다면 정석적인 답변을 알려주실 수 있을까요?

 


Redis의 데이터 구조

Strings

- 일반적인 문자열

- 값은 최대 512MB이며 String으로 될 수 있는 binary data도, JPEG 이미지도 저장 가능

- 단순 증감 연산에 좋음

- String:String 매핑을 이용하여 연결되는 자료 매핑을 할 수도 있음. HTML 매핑도 가능

 

Bitmaps

- bit 단위 연산 가능

- 2^32bit까지 사용 가능

- 저장할 때, 저장 공간 절약에 큰 장점이 있음

 

Lists

- array 형식의 데이터 구조, 데이터를 순서대로 저장함.

- 추가/삭제/조회하는 것은 O(1)의 속도를 가지지만, 중간의 특정 index 값을 조회할 때는 O(N)의 속도를 가짐.

- 중간에 추가/삭제가 느리다. 따라서 head-tail에서 추가/삭제함(push/pop 연산)

- 메세지 queue로 사용하기 적절

 

Hashes

- field:value로 구성되어있는 전형적인 hash의 형태

- key 하위에 subkey를 이용해 추가적인 Hash Table을 제공하는 자료구조

- 메모리가 허용하는 한, 제한없이 field들을 넣을 수 있음.

 

Sets

- 중복된 데이터를 담지 않기 위해 사용하는 자료구조

- 유니크한 key값

- 정렬되지 않은 집합

- 중복된 데이터를 여러번 저장하면 최종 한번만 젖아된다.

- Set간의 연산을 지원함. 교집합, 합집합 차이를 빠른 시간 내에 추출 가능

- 단, 모든 데이터를 전부 다 갖고 올 수 있는 명령이 있으므로 주의해서 사용해야 한다.

 

Sorted Sets

- set에 score라는 필드가 추가된 데이터 형(score는 일종의 가중치)

- 일반적으로 set은 정렬 되어있지않고 insert한 순서대로 들어감. 하지만 Sorted Set은 Set의 특성을 그대로 가지며 추가적으로 저장된 member들의 순서도 관리한다.

- 데이터가 저장될 때부터 score 순으로 정렬되며 저장

- sorted set에서 데이터는 오름차순으로 내부 정렬

- value는 중복 불가능, score는 중복 가능

- 만약 score 값이 같으면 사전 순으로 정렬되어 저장

 

HyperLogLogs

- 굉장히 많은양의 데이터를 dump할 때 사용

- 중복되지 않는 대용량 데이터를 count할 때 주로 많이 사용한다.

- set과 비슷하지만 저장되는 용량은 매우 작다(저장되는 모든 값이 12kb 고정)

- 저장된 데이터는 다시 확인할 수 없다.(데이터 보호에 적절)

 

Streams

- Streams는 log를 저장하기 가장 좋은 자료 구조

- append-only이며 중간에 데이터가 바뀌지 않음.

- 읽어 올 때 id값 기반으로 시간 범위로 검색

- tail -f사용 하는 것 처럼 신규 추가 데이터 수신

 

Redis가 단일 스레드로 높은 성능을 유지하는 이유

1. I/O 멀티 플렉싱

- 단일 스레드로도 동시에 여러 클라이언트의 요청을 처리할 수 있도록 I/O 멀티플렉싱 기술을 사용

I/O Multiplexing
- 입출력 다중화
- 하나의 통신 채널을 통해서 둘 이상의 데이터를 전송하기 위한 기술
- 물리적 장치의 효율성을 높이기 위해, 최소한의 물리적 요소만을 이용하여 최대한의 데이터를 전달하기 위해 사용되는 기술
- 각 파일을 처리할 때 마다 개별 I/O 통로를 만들어 프로세스(스레드)를 만들면 IPC, 동기화, 스레드, Context Switching 등의 Overhead 단점
- 따라서 하나의 채널을 통해 여러 데이터를 송/수신하여 프로세스 개수를 최소한으로 유지하는 I/O Multiplexing

 

2. 메모리 기반 데이터 처리

- Redis는 모든 데이터를 메모리에 저장하고 읽기/쓰기 작업을 수행하기 때문에 I/O 병목이 없음.

- 따라서 초당 수십만 요청도 처리 가능

 

3. 간단한 구조

- 단일 스레드로 설계되어 복잡한 스레드 동기화나 잠금(lock)이 필요하지 않음.

- 오버헤드가 적고, CPU와 메모리 리소스를 효율적으로 활용

 

Redis 데이터의 영속성(Redis Persistence)

- Redis는 In-memory DB임에도 불구하고, 메모리 데이터를 disk에 저장할 수 있는 특징이 있음.

- 서버가 꺼진 후 restart되더라도 disk에 저장해놓은 데이터를 다시 읽어서 메모리에 로딩하기 때문에 데이터가 유실되지 않는다.(Persistence)

 

RDB(Redis Database File, snapshtting)

- 특정한 간격마다 메모리에 있는 레디스 데이터 전체를 디스크에 쓰는 것(백업에 용이)

- Redis는 인메모리 데이터를 주기적으로 파일에 저장하는데, Redis 프로세스가 장애로 인해 종료되더라도 해당 파일을 읽어들이면 이전의 상태로 동일하게 복구할 수 있음.

- 직접 세팅하지 않더라도 Redis는 자동으로 .rdb라는 확장자의 파일에 인메모리 데이터를 저장하도록 디폴트 설정되어있음.

- RDB(snapshot)는 순간적으로 메모리에 있는 내용을 스냅샷을 떠서 DISK에 옮겨 담는 방식

- 스냅샷을 뜬다는 말은 특정 시점의 메모리에 있는 데이터를 바이너리 파일로 저장한다는 뜻

- .rdb 파일은 AOF 파일 보다 사이즈가 작다는 특징이 있음. 따라서 로딩 속도가 AOF 보다 빠름.

- RDB 방식은 메모리의 snapshot을 그대로 저장하기 때문에 서버를 재구동시할 때 snapshot을 다시 읽으면 되므로 속도가 빠른 장점

- snapshot을 추출하는데 시간이 오래 걸리고 도중에 서버가 꺼지면 이후의 데이터가 모두 사라진다는 단점.(실제로 SAVE 옵션으로 50GB의 메모리 상태를 저장한다면 7~8분 정도 소요된다고 함.)

 

RDB 저장 방식

1. SAVE

- 순간적으로 redis의 동작을 정지시키고 그 snapshot를 디스크에 저장.(blocking 방식)

 

SAVE 동작 순서

1. Main process가 데이터를 새 RDB temp 파일에 쓴다.

2. 쓰기가 끝나면 기존 파일을 지우고, 새 파일로 교체한다.

 

2. BGSAVE

- 백그라운드 SAVE라는 의미로 별도의 자식 프로세스를 띄운 후, 명령어 수행 당시의 snapshot을 disk에 저장하고, redis는 동작을 멈추지 않게 된다.(non-blocking 방식)

 

BGSAVE 동작 순서

1. Child process를 fork()한다.

2. Child process는 데이터를 새 RDB temp 파일에 쓴다.

3. 쓰기가 끝나면 기존 파일을 지우고, 이름을 변경한다.

 

AOF(Append Only File)

- Redis의 모든 write/update 연산 자체를 모두 log 파일에 기록하는 형태

- default로 appendonly.aof 파일에 기록되며, 조회를 제외한 입력/수정/삭제 명령이 실행될 때마다 기록된다.

- 서버가 재시작될 때, log에 기록된 write/update 연산을 재실행하는 형태로 데이터를 복구하는 방식.

 

데이터 저장 순서

1. 클라이언트가 Redis에 업데이트 관련 명령을 요청

2. Redis는 해당 명령을 AOF에 저장

3. 파일쓰기가 완료되면 실제로 해당 명령을 수행해서 Redis 메모리에 내용을 변경함.

 

- 이처럼 동작이 발생할 때마다 매번 기록하기 때문에 RDB방식과는 달리 특정 시점이 아니라 항상 현재 시점까지의 로그를 기록할 수 있으며, 기본적으로 non-blocking으로 동작된다.

- AOF는 log 파일에 대해서만 append하기 때문에 log write 속도가 빠르고 어떤 시점에 서버가 다운되더라도 데이터가 사라지지 않는 장점이 있음.

- RDB는 바이너리 파일이라서 수정이 불가능했지만, AOF 로그 파일은 text 파일이므로 편집이 가능함.

- 모든 write/update 연산을 log파일에 남기기 때문에 log 데이터 양이 굉장히 크고, 복구 시 저장된 모든 write/update연산을 다시 실행하기 때문에 재시작 속도가 느림.

- AOF방식은 rewrite 기능을 제공하여 이전 기록은 모두 사라지고 최종 데이터만 기록되도록 하여 파일의 크기가 줄어들게 하는 기능이 있다.(모든 log를 기록하는 것이 아니게 됨) 

 

RDB vs AOF 

- 우선 redis를 캐시로만 사용한다면 굳이 백업 기능을 필요없다. 저장 공간 낭비가 될 수 있기 때문.

- 백업은 필요하지만 어느 정도의 데이터 손실이 발생해도 괜찮은 경우, RDB를 단독 사용하는 것을 고려함.

- 하지만 장애 상황 직전까지 모든 데이터가 보장되어야 할 경우 AOF 사용

- 그렇지만 RDB와 AOF 방식의 장단점을 상쇄하기 위해 두가지 방식을 혼용해서 사용하는 것이 바람직함.

- 주기적으로 RDB(snapshot)으로 백업하고, 다음 snapshot까지의 저장을 AOF 방식으로 수행하는 식으로 혼용한다.

이렇게 하면 서버가 restart 될 때 백업된 snapshot을 reload하고, 비교적 적은 양의 AOF로그만 replay하면 되기 때문에, restart 시간을 절약하고 데이터의 유실을 방지할 수 있음.

 

수정된 답변

더보기

1. 

String : 문자열 또는 숫자 값을 저장하는

hash : key:value 형태로 저장할 수 있고, subkey를 사용할 수 있는

list : 순서가 있는 값인

set : 중복되지 않는 유일한 값인

sorted set : set의 특징을 가지면서도 점수(Score)가 있는 정렬된

2. Redis가 단일 스레드임에도 높은 성능을 유지할 수 있는 이유는 첫번째로 I/O Multiplexing 덕분입니다. 여러 요청이 들어올 때마다 새로운 프로세스 혹은 스레드를 만들어서 처리하는 것이 아닌 하나의 프로세스 혹은 스레드로 입력을 받아 처리하기 때문입니다. 두번째로 Redis는 In-memory DB이기 때문입니다. 모든 데이터를 메모리에 저장하여 읽기/쓰기 작업을 하기 때문에 I/O 병목이 없습니다.

3. Redis Persistence 옵션에는 RDB(Redis Database File)과 AOF(append only file) 두가지 옵션이 있습니다. 

RDB는 특정 시점까지의 데이터를 모두 백업하는 옵션입니다. AOF보다 파일 사이즈가 작아 로딩 속도가 빠르다는 장점이 있지만 서버가 다운됐을 때 특정 시점 이후의 데이터를 유실할 수 있다는 단점이 있습니다. AOF는 write/update작업을 할 때마다 log를 기록하는 옵션입니다. 서버가 다운되더라도 모든 동작을 log로 기록해놨기 때문에 데이터 손실이 없다는 장점이 있지만 모든 log를 기록하는만큼 파일의 크기가 크고 재시작 속도가 느립니다.


참고

https://inpa.tistory.com/entry/REDIS-📚-데이터-타입Collection-종류-정리