DS log

[Redis] 내부 아키텍처에 대해서 알아보자. 본문

기술

[Redis] 내부 아키텍처에 대해서 알아보자.

DS log 2026. 4. 6. 22:40
728x90

 

기존에 Redis하면 자동 반사로 특징은 싱글 스레드! 라고 암기가 되어있었는데요. 이번에 좋은 기회로 Redis를 공부하게 되서 오늘은 Redis 내부 아키텍처에 대해서 소개해보려고 합니다.  

 

메인 스레드와 보조 스레드

Redis는 메인 스레드 1개와 백그라운드 보조 스레드들로 구성되어 있습니다. 간단하게 주요 작업은 메인 스레드가 처리하고 시간이 오래걸리는 작업은 백그라운드 보조 스레드가 처리하는 구조입니다.

 

1. 메인 스레드

 

메인 스레드는 클라이언트의 모든 명령어를 순차적으로 처리하는 핵심 엔진입니다. 이때 이벤트 루프 기반의 비동기 I/O를 활용하여 단일 스레드임에도 불구하고 높은 처리량을 보여줍니다.

 

2. 보조 스레드

 

보조 스레드들은 메인 스레드가 처리하기에 시간이 오래 걸리는 I/O 작업을 전담합니다. 예를 들어, 대용량 데이터 삭제를 위한 UNLINK 명령어, RDB 파일 저장을 위한 BGSAVE, 또는 AOF 파일 재작성 등이 있습니다.

 

3. 작업 큐를 통한 협업

 

두 스레드는 작업 큐를 통해 협업합니다. 메인 스레드가 처리하기에 오래 걸리는 작업을 발견하면, 그 작업을 작업 큐에 넣어 보조 스레드에게 위임합니다. 보조 스레드는 이 큐에서 작업을 꺼내 수행합니다. 덕분에 메인 스레드는 작업을 큐에 넣는 아주 짧은 시간 외에는 클라이언트의 명령어를 막힘 없이 수행할 수 있게 됩니다.

 

싱글 스레드인데 어째서 빠르다고 할까?

Redis는 하나의 메인 스레드로 여러 클라이언트와 연결된 소켓들의 요청을 동시에 처리합니다. 이 과정은 이벤트 루프를 중심으로 아래와 같이 진행됩니다.

1. 이벤트 대기

 

Redis의 메인 스레드는 I/O 멀티플렉싱 기술(리눅스의 epoll 등)을 사용하여 다수의 클라이언트 소켓들을 감시합니다. 메인 스레드는 소켓에 클라이언트 요청 데이터가 도착하여 '읽기 가능(Readable)' 이벤트가 발생하기를 효율적으로 대기합니다.

 

2. 데이터 수신 및 버퍼 저장

 

이벤트 루프가 소켓의 읽기 이벤트를 즉시 감지하면, 메인 스레드가 활성화됩니다. 메인 스레드는 소켓으로부터 요청을 읽어 해당 소켓의 입력 버퍼(Input Buffer)에 저장합니다.

 

3. 순차 명령어 실행

 

데이터가 버퍼에 저장된 후, 메인 스레드는 이 버퍼에 있는 명령어를 FIFO 방식으로 순차적으로 가져와 실행합니다. 이 실행 과정이 바로 Redis가 싱글 스레드로 원자성을 핵심입니다.

 

이 구조 덕분에 메인 스레드는 I/O 작업을 기다리며 시간을 낭비하지 않고, 실제 명령어를 처리하는 데에만 집중하여 높은 성능을 유지할 수 있습니다.

 

싱글 스레드 모델의 장단점은 무엇일까?

Redis의 싱글 스레드 명령어 실행 모델은 다음과 같은 장점과 단점을 가집니다.

 

명령어들이 순차적으로 실행되므로, 복잡한 Lock 메커니즘 없이도 Race Condition이 발생하지 않습니다. 따라서 데이터 정합성을 매우 쉽게 보장할 수 있는 장점이 있습니다.

 

그러나, 스레드가 1개라는 점에서 Head-of-Line Blocking 이 발생할 위험이 있습니다. 하나의 명령어가 오래 실행되면, 그 작업이 끝날 때까지 다른 모든 클라이언트의 요청 처리가 지연됩니다.

 

이것이 바로 KEYS와 같은 시간 복잡도가 높은 명령어를 사용하지 말고 SCAN 명령어를 사용하라고 하는 이유입니다. 

 

싱글 스레드인데 MULTI/EXEC 트랜잭션은 왜 필요할까?

공부를 하다가 싱글 스레드인데 "왜 Redis에 트랜잭션을 보장해주는 MULTI/EXEC 같은 명령어가 있는 거지?"라는 의문이 들었습니다.

 

이 의문의 답은 Redis가 처리하는 요청의 근본적인 환경을 생각하면 이해하기 쉽습니다. Redis 메인 스레드는 하나지만, 외부 클라이언트로부터 요청을 받는 소켓(연결)은 여러 개가 동시에 존재합니다. Redis의 싱글 스레드는 한 번에 하나의 명령만 실행하므로 단일 명령어의 원자성은 보장합니다. 하지만, 여러 클라이언트가 각각의 소켓을 통해 동시에 요청을 보내면, Redis는 이 소켓들에서 들어온 명령어들을 하나씩 번갈아 순차적으로 처리합니다.


따라서, 특정 클라이언트 두 개의 명령어를 보냈을 때, 이 두 명령어 사이에 다른 클라이언트 B의 명령어가 끼어들어 실행될 수 있습니다.

MULTI/EXEC 트랜잭션은 바로 이 문제를 해결합니다. 트랜잭션 블록 내의 모든 명령어들을 하나의 작업 묶음으로 간주하여, 해당 블록이 실행되는 동안에는 다른 소켓에서 들어온 어떠한 명령도 끼어들지 못하게 막아, 다수 명령어 시퀀스의 원자성을 보장해 줍니다.

 

결론

Redis는 단일 메인 스레드로 명령을 순차적으로 처리하는 싱글 스레드 모델을 채택하여 복잡한 락 없이도 Race Condition 문제를 근본적으로 방지하고 데이터의 원자성을 보장합니다.

 

여기에 I/O 멀티플렉싱(I/O Multiplexing) 기술 기반의 이벤트 루프를 결합하여, I/O 대기 시간을 극복하고 단일 스레드로 수많은 클라이언트의 요청을 동시에 처리합니다. 결국 Redis는 명령어 실행의 단순성과 I/O 처리의 비동기성이라는 두 가지 핵심 요소를 결합하여 안정적인 고성능 처리를 달성합니다.

 

728x90