Redis

  • in-memory based key value store
  • 캐싱, 세션 관리, pub/sub
  • REmote DIctionary Server
  • write by C
  • single thread

2. 싱글 스레드 아키텍처와 고성능의 비밀

Redis는 일반적으로 “싱글 스레드로 동작한다”라고 알려져 있습니다. “싱글 스레드면 병목이 발생하지 않나?”라고 의문이 들 수 있지만, 실무 환경에서는 매우 높은 처리량을 보입니다. 그 이유는 다음과 같습니다.

  1. 이벤트 루프(Event Loop)와 I/O 멀티플렉싱

Redis는 내부적으로 epoll(리눅스) 또는 kqueue(BSD 계열) 같은 I/O 멀티플렉싱을 활용하여, 대량의 네트워크 소켓을 단일 스레드에서 비동기적으로 처리합니다. 이를 통해 스레드 컨텍스트 스위칭(Context Switching) 오버헤드를 최소화하고, I/O 대기 시간도 효율적으로 다룰 수 있습니다.

  1. 인메모리 처리

대부분의 연산이 메모리 위에서 일어나므로, 디스크 I/O에 의한 지연이 상대적으로 매우 적습니다. 실제로 디스크를 접근하는 상황은 주로 영속성(Persistence) 설정 시에 RDB 스냅샷이나 AOF(append-only file)에 로그를 기록할 때 발생합니다.

  1. C 언어 및 최적화된 자료구조

Redis는 C로 구현되어, 메모리 관리를 세밀하게 제어하며, 내부 자료구조를 직접 관리하여 최대한 빠른 속도를 낼 수 있도록 설계되었습니다.

  1. 락(Lock) 최소화

싱글 스레드이기 때문에 내부 연산에 대하여 복잡한 락을 사용하지 않아도 됩니다. 즉, 여러 스레드가 데이터를 동시에 변경할 필요가 없으므로, 동시성 제어에 대한 부하가 크게 줄어듭니다.

싱글 스레드 동작으로 인한 제한 사항?

• CPU 집약적인 연산이 많은 경우(예: 복잡한 스크립트 처리, 대규모 정렬 연산 등)에는 Redis 단일 프로세스가 병목이 될 수 있습니다.

• 이러한 상황에서는 Redis 클러스터(Cluster) 구성 또는 필요에 따라 멀티 스레드 기능(Redis 6.0 이후 일부 I/O 단계에서 멀티스레드 지원)이 고려될 수도 있습니다. 다만, 일반적인 CRUD 혹은 단순 조회/저장 시나리오에서는 싱글 스레드 구조가 오히려 빠른 성능과 간단한 구조를 보장합니다.


Redis를 단순 Key-Value Store로만 보기 쉽지만, 실제로는 다양한 자료구조와 유용한 연산을 제공합니다. 주요 자료구조와 사용 예시는 다음과 같습니다.

  1. String

• 가장 기본적인 형태의 Key-Value

• 예: “user:1001” “John Doe”

  1. List

• 순서가 있는 값의 목록(Linked List 기반)

• 예: 소셜 피드, 댓글 목록, 큐(Queue) 구현

• 명령어: LPUSH, RPUSH, LPOP, RPOP, LRANGE 등

  1. Hash

• Key에 대해 다중 필드를 저장할 수 있는 형태

• 예: 사용자 프로필, 세션 정보

• 명령어: HGET, HSET, HGETALL 등

  1. Set

• 중복을 허용하지 않는 집합 자료구조

• 예: 고유 방문자(Unique Visitor) 카운트, 교집합/합집합 연산

• 명령어: SADD, SREM, SMEMBERS, SINTER 등

  1. Sorted Set (ZSet)

• 값에 대해 점수(Score)를 매겨서 순서가 정해지는 자료구조

• 예: 리더보드(Leaderboard) 구현, 랭킹, 일정 정렬

• 명령어: ZADD, ZRANGE, ZREVRANGE, ZSCORE 등

  1. Bitmap

• 0과 1로 이루어진 비트 단위 처리가 필요한 경우에 유용

• 예: 특정 날짜에 로그인한 사용자의 집합 표현, 플래그 처리 등

  1. HyperLogLog

• 대규모 유일값(Unique Count)을 추정할 때 메모리를 거의 사용하지 않고 근사값을 빠르게 계산

• 예: UV(Unique Visitor) 측정, 이벤트 발생 수 추정

자료구조가 다양하다는 것은 단순 캐싱뿐 아니라, 여러 로직을 Redis 측에서 빠르게 처리할 수 있음을 의미합니다. 백엔드에서 로직을 구현하기 전에, Redis에서 제공하는 기능으로 대체할 수 없는지 고려해 보시기 바랍니다.

4. Persistence(영속성)와 데이터 안전성

Redis는 인메모리 기반이지만, 영속성(Persistence) 기능을 통해 데이터를 디스크에 기록함으로써 재시작 이후에도 데이터를 보존할 수 있습니다. 크게 RDB(Redis Database) 스냅샷 방식과 AOF(Append Only File) 방식이 있습니다.

  1. RDB 스냅샷

• 특정 간격(예: 5분에 한 번 등) 또는 조건(예: SAVE나 BGSAVE 명령)에 따라 전체 메모리를 덤프하여 .rdb 파일에 저장

• 스냅샷이 완료된 시점 이후로 Redis가 갑자기 다운되면, 마지막 스냅샷 이후의 변경분은 유실될 수 있습니다.

• 백업/복원 시 간단하게 파일을 옮겨 재구동하면 동일 상태로 복원 가능

  1. AOF(Append Only File)

• Redis의 모든 write/update 연산을 파일에 순차적으로 기록

• 재시작 시에 해당 로그를 재적용하여 마지막 상태까지 복원

• 로그가 계속 쌓이므로 주기적으로 BGREWRITEAOF 명령을 통해 파일 크기를 압축

• RDB보다 더 세밀하게 데이터를 보존할 수 있으나, 디스크 I/O가 더 많이 발생하므로 성능 상의 트레이드오프가 존재

실무에서는 RDB + AOF 방식을 함께 사용하거나, 서비스의 요구사항에 따라 어느 한 쪽만 선택하기도 합니다. 서비스 신뢰도(RPO, RTO 등)에 따라 적절한 설정을 고민해 보세요.


5. Replication(복제)와 장애 대비

Redis는 마스터-슬레이브 구조의 리플리케이션을 통해, 읽기 부하 분산장애 대비를 지원합니다.

Master Slave

• 마스터 노드가 모든 쓰기를 담당하고, 슬레이브 노드는 마스터 노드로부터 데이터를 복제받아 읽기 전용 역할을 수행

• 스냅샷 전송, 또는 마스터와 슬레이브 간 동기화 과정에서 RDB 또는 AOF를 활용

장애 조치(Automatic Failover)

• Redis Sentinel을 이용하면 마스터 노드가 장애 발생 시 자동으로 슬레이브 중 하나를 새 마스터로 승격(failover)

• Sentinel은 마스터 노드와 슬레이브 노드의 헬스 체크, 재선정 로직 등을 제공

이를 통해 단일 서버 장애 시에도 데이터를 유지하면서 빠르게 복구할 수 있습니다.


6. Redis Cluster(클러스터) 구조

싱글 인스턴스 혹은 마스터-슬레이브 구조만으로는 대규모 트래픽이나 메모리 수요를 처리하기 어려울 수 있습니다. 이러한 확장성 문제를 해결하기 위해 Redis는 클러스터를 지원합니다.

  1. Sharding(분산)

• 데이터를 여러 노드에 분산 저장

• Redis 클러스터는 Consistent Hashing과 유사하지만, 실제로는 16384개의 해시 슬롯(Hash Slot) 개념을 이용

• 각 키가 해시 슬롯 하나에 매핑되고, 슬롯들을 여러 Redis 노드가 나누어 갖습니다.

  1. Failover

• 클러스터 내 노드가 장애가 생기면, 해당 노드의 슬레이브가 자동으로 승격되어 데이터 유실을 최소화

• 클라이언트 측에서도 클러스터를 인식하도록 해야 하며, 보통 Redis 클러스터를 위한 클라이언트를 사용하거나 Jedis/lettuce 등에서 클러스터 모드를 활성화합니다.

  1. 확장성

• 노드를 추가하거나 제거하여 전체적인 성능과 용량을 조절

• 대규모 트래픽을 처리하면서도 Redis의 저지연 특성을 유지


7. Redis의 주요 활용 사례

  1. 캐싱(Caching)

• 가장 흔하고 대표적인 사용 방식

• 예: DB 질의 결과, 정적/반정적 페이지 데이터 캐싱, API 응답 결과 캐싱

  1. 세션 관리(Session Store)

• 웹 서비스 세션 정보를 Redis에 저장하여, 서버 간 세션을 공유하고 빠르게 세션 정보를 조회

• 예: 로그인 상태, 사용자 정보, 토큰 저장

  1. Pub/Sub

• Redis는 Publish/Subscribe 모델을 지원하여, 실시간 알림이나 이벤트 처리 시스템 구축

• 예: 채팅 메시지 브로드캐스트, 알림 서비스, 실시간 로그 전달

  1. 실시간 분석/카운팅

• 방문자 수 집계, 실시간 이벤트 추적, PV/UV 카운팅 등에 활용

• 예: HyperLogLog를 통한 유저 세션 카운트, Sorted Set을 통한 순위 집계

  1. 분산 락(Distributed Lock)

• 여러 인스턴스에서 동시에 접근이 필요한 자원을 동기화하기 위한 방법

• SETNX, EXPIRE 같은 명령을 조합하여 락을 구현하거나, Redisson 등 라이브러리 사용

  1. 스트리밍(Stream) 기능

• Redis 5.0부터 추가된 자료구조

• Pub/Sub과 비슷하지만 로그 저장 및 소비(Consumer Group 등) 기능을 좀 더 확장

• Kafka 등 다른 메시지 브로커가 필요 없는 비교적 단순한 이벤트 스트림 처리


8. 메모리 관리와 Eviction(만료 정책)

Redis는 인메모리로 동작하므로, 메모리가 부족해지면 키를 자동으로 삭제(Eviction) 하거나, 요청을 거부(OOM - Out Of Memory)할 수 있습니다. 대표적인 만료 정책은 다음과 같습니다.

  1. noeviction

• 새 데이터를 추가할 수 없고, 메모리가 부족해지면 에러를 반환

  1. allkeys-lru

• 모든 키 중에서 가장 오랫동안 사용되지 않은(Least Recently Used) 키부터 제거

  1. volatile-lru

• 만료 시간(TTL)이 설정된 키들 중 LRU 대상 제거

  1. allkeys-random, volatile-random

• 무작위로 키를 제거

  1. allkeys-lfu(Least Frequently Used)

• Redis 4.0 이후 추가된 정책

• 가장 사용 빈도가 낮은 키부터 제거

서비스 특성에 맞는 적절한 정책을 택하고, 키 만료 시간을 적극적으로 설정해주는 것이 중요합니다.


9. 트랜잭션과 Lua 스크립트

Redis에서의 트랜잭션은 관계형 DB의 트랜잭션처럼 원자성, 격리성을 완벽하게 제공하지 않습니다. 다만, MULTI와 EXEC 명령을 통해 명령어들을 한 번에 처리하거나 WATCH 키워드로 낙관적 락(Optimistic Lock) 기능을 사용할 수 있습니다.

또한, 복잡한 로직이나 여러 명령어를 하나의 단위로 실행하기 위해 Lua 스크립트를 사용할 수 있습니다. Lua 스크립트는 서버 측에서 원자적으로 실행되며, 스크립트가 실행되는 동안 Redis는 다른 명령을 처리하지 않기 때문에 일관성을 보장할 수 있습니다.


10. 성능 측정과 모니터링

Redis는 자체적으로 INFO 명령이나 MONITOR 명령을 제공하여 내부 동작 상태나 명령 호출 내역 등을 조회할 수 있습니다.

INFO

• 서버 상태, 메모리 사용량, 연결 수, CPU 사용량, 레플리카 상태 등 각종 지표 확인 가능

MONITOR

• Redis 서버에 들어오는 모든 명령을 실시간 확인

• 트래픽이나 질의 패턴 분석

또한, redis-cli —latency, redis-cli —stat 등의 기능을 통해 지연(Latency) 시간이나 명령 처리량 등을 확인할 수도 있습니다. 운영 환경에서는 Prometheus와 Grafana를 연동하여, 지표를 시각화하고 알람을 설정하면 편리합니다.


11. 결론 및 정리

Redis는 단순 Key-Value Store가 아니라, 고성능 인메모리 데이터베이스로 분류할 수 있을 정도로 다양한 기능과 자료구조, 확장성(Cluster), 영속성(Persistence), 레플리케이션(Replication) 등을 제공합니다.

싱글 스레드 아키텍처로 인한 단순성과 높은 성능

풍부한 자료구조를 통해, 백엔드 로직을 효율적으로 오프로드

RDB + AOF를 통한 선택적 영속성

클러스터, 센티널을 통한 확장성과 장애 조치

Pub/Sub, Stream으로 이벤트 기반 시스템 구축

배포 규모와 요구사항에 따라 다양한 설정과 아키텍처를 선택할 수 있으며, 높은 신뢰도와 초저지연 처리가 필요한 현대 백엔드 환경에서 Redis의 중요성은 점점 커지고 있습니다. Redis를 적절히 활용한다면, 애플리케이션의 확장성과 성능을 크게 개선할 수 있을 것입니다.

Redis를 더 깊이 공부하려면, 공식 문서( https://redis.io/documentation )를 꼼꼼히 살펴보고, 실제로 다양한 시나리오에서 사용해 보며 경험치를 쌓는 것이 가장 좋습니다.

“적절한 상황과 자료구조를 선택해 효율적으로 사용한다면, Redis는 언제나 강력한 무기가 될 수 있다.”


http://redisgate.kr/redis/configuration/redis_overview.php https://redis.io/technology/redis-enterprise-cluster-architecture/