인 메모리가 빠른데 어떻게 활용해야하나요
2026. 3. 14. 17:50

Topic (오늘의 주제)

Redis(Remote Dictionary Server)인메모리(In-Memory) 에 데이터를 저장하는 키-값(Key-Value) 저장소이다. 디스크 I/O 없이 메모리에서만 동작해 응답 속도가 매우 빠르며, 캐시, 세션 스토어, 실시간 랭킹, 메시지 브로커 등 다양한 용도로 쓰인다.


Why (왜 사용하는가? 왜 중요한가?)

  • 문제점: DB(MySQL, PostgreSQL 등)는 디스크 기반이라 조회·갱신이 상대적으로 느리고, 트래픽이 몰리면 DB 부하와 응답 지연이 발생한다. 세션을 애플리케이션 메모리에만 두면 서버를 여러 대 쓰는 환경에서 공유가 어렵다.
  • 해결책: 자주 쓰는 데이터를 Redis에 두어 캐시로 활용하면 DB 부하를 줄이고 응답 속도를 높일 수 있다. 세션을 Redis에 저장하면 여러 서버가 같은 세션 저장소를 쓰는 구조를 만들 수 있다.
  • 면접 포인트: "캐시를 왜 쓰나요?", "Redis와 DB의 차이", "Redis 자료 구조와 사용 사례"를 설명할 수 있으면 좋다.

1. Redis가 필요한 상황 (등장 배경)

DB만 쓸 때의 한계

  • 디스크 I/O: RDBMS는 데이터를 디스크에 저장하고, 조회 시 디스크에서 읽어오므로 상대적으로 느리다.
  • 반복 조회: "인기 상품 목록", "조회수 많은 게시글"처럼 같은 데이터를 자주 조회하면 DB에 같은 쿼리가 반복해서 날아가 부하가 커진다.
  • 세션 공유: 서버가 여러 대일 때 세션을 각 서버 메모리에만 두면, 사용자가 다른 서버로 가면 로그인이 풀리는 문제가 생긴다.

Redis를 쓰면 얻는 것

목적 설명
캐시 자주 쓰는 데이터를 메모리에 두어 DB 조회를 줄이고 응답 속도를 높인다.
세션 스토어 로그인 세션을 Redis에 저장해 여러 서버가 같은 세션을 공유한다.
실시간 랭킹 Sorted Set으로 점수 기반 순위를 빠르게 조회·갱신한다.
메시지 큐 / Pub-Sub 채팅, 알림처럼 실시간으로 메시지를 주고받을 수 있다.

2. Redis 핵심 특징

인메모리(In-Memory)

  • 데이터를 메모리(RAM) 에 저장한다. 디스크 접근보다 훨씬 빠르다.
  • 메모리 크기에 제한이 있으므로, 전체 데이터를 Redis에만 두지 않고 캐시·세션·랭킹 등 적절한 용도로만 사용하는 것이 좋다.

키-값(Key-Value) 구조

  • 기본적으로 키(Key)값(Value) 를 저장하고 조회한다.
  • 키는 문자열, 값은 문자열뿐 아니라 여러 자료 구조(리스트, 해시, 집합, 정렬 집합 등)를 지원한다.

단일 스레드 모델

  • 명령 처리는 단일 스레드로 동작한다. 한 번에 하나의 명령만 처리하므로 race condition 없이 명령이 원자적(atomic) 으로 실행된다.
  • I/O 멀티플렉싱(epoll 등)으로 여러 클라이언트 연결을 동시에 처리한다.

TTL(Time To Live)

  • 키에 만료 시간을 줄 수 있다. 시간이 지나면 자동으로 삭제되어 캐시 만료를 구현하기 쉽다.
SET session:user123 "..." EX 3600   # 3600초(1시간) 후 만료
EXPIRE key 60                        # 기존 키에 60초 TTL 설정

영속성 옵션 (선택)

  • 기본은 메모리만 사용하지만, RDB 스냅샷 또는 AOF(Append Only File) 로 디스크에 저장해 재시작 후 복구할 수 있다. 캐시만 쓰는 경우는 비활성화해도 된다.

3. Redis 데이터 구조(자료형)

Redis는 단순 문자열뿐 아니라 여러 자료형을 지원한다. 용도에 맞는 타입을 선택하면 된다.

자료형 설명 대표 명령 사용 예
String 문자열, 숫자, 직렬화된 객체 SET, GET, INCR, DECR 캐시, 카운터, 세션
List 순서 있는 문자열 리스트 LPUSH, RPUSH, LRANGE 최근 목록, 메시지 큐
Set 순서 없고 중복 없는 집합 SADD, SMEMBERS, SINTER 좋아요 유저 집합, 태그
Hash 필드-값 쌍 (객체처럼) HSET, HGET, HGETALL 사용자 프로필, 설정
Sorted Set 점수로 정렬된 집합 ZADD, ZRANGE, ZRANK 랭킹, 실시간 순위

String — 캐시, 세션, 카운터

SET user:1000 "{ \"name\": \"홍길동\" }" EX 3600
GET user:1000

INCR view:article:42    # 조회수 1 증가
DECR stock:product:99   # 재고 1 감소

Hash — 객체 단위 저장

HSET user:1000 name "홍길동" email "hong@example.com" age 25
HGET user:1000 name
HGETALL user:1000

List — 순서 있는 목록

LPUSH recent:user:1000 "article:1" "article:2"   # 왼쪽에 추가
LRANGE recent:user:1000 0 9                       # 최근 10개 조회

Sorted Set — 랭킹

ZADD ranking:game 1000 "userA" 950 "userB" 1100 "userC"
ZREVRANGE ranking:game 0 9 WITHSCORES   # 1~10위 조회
ZRANK ranking:game "userB"              # userB의 순위

4. 사용 사례 정리

1) 캐시 (Cache)

  • DB 조회 결과, API 응답 등을 Redis에 저장해 두고, 같은 요청이 오면 DB 대신 Redis에서 반환한다.
  • TTL을 두어 오래된 데이터는 자동으로 삭제하고, 필요 시 DB에서 다시 조회해 캐시를 갱신한다.

2) 세션 스토어 (Session Store)

  • 로그인한 사용자의 세션 ID → 세션 데이터를 Redis에 저장한다.
  • 서버가 여러 대여도 같은 Redis를 바라보면 세션이 공유된다.

3) 실시간 랭킹

  • Sorted Set에 점수(score)멤버(회원ID, 상품ID 등)를 넣고, ZREVRANGE로 상위 N명을 조회한다.
  • 게임 점수, 인기 검색어, 인기 글 등에 활용한다.

4) 카운터 / Rate Limiting

  • INCR로 요청 횟수, 조회수 등을 증가시키고, TTL과 함께 쓰면 "1분당 N회 제한" 같은 제한을 구현할 수 있다.

5) Pub/Sub (메시지 브로커)

  • 채널에 메시지를 발행(publish)하고, 구독자(subscribe)가 실시간으로 받는다.
  • 채팅, 알림, 이벤트 전파 등에 사용한다.

5. Spring에서 Redis 사용하기

의존성 (Spring Boot)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 기본 클라이언트는 Lettuce이다. (과거에는 Jedis가 많이 쓰였음)

설정 (application.yml)

spring:
  data:
    redis:
      host: localhost
      port: 6379
      password: ${REDIS_PASSWORD:}   # 비어 있으면 미사용
      timeout: 2000ms

RedisTemplate 사용

@RequiredArgsConstructor
@Service
public class ProductCacheService {
    private final RedisTemplate<String, Object> redisTemplate;

    public void saveProduct(Long id, Product product) {
        String key = "product:" + id;
        redisTemplate.opsForValue().set(key, product, Duration.ofMinutes(30));
    }

    public Product getProduct(Long id) {
        String key = "product:" + id;
        return (Product) redisTemplate.opsForValue().get(key);
    }
}

캐시 어노테이션으로 사용

@Cacheable(value = "products", key = "#id")
public Product getProduct(Long id) {
    return productRepository.findById(id).orElseThrow();
}
  • @Cacheable: 메서드 결과를 캐시에 저장하고, 같은 키로 호출 시 캐시에서 반환한다.
  • @CacheEvict: 캐시 항목을 지울 때 사용한다. (예: 수정·삭제 시)

6. 캐시 전략 간단 정리

전략 설명 특징
Cache-Aside 애플리케이션에서 캐시를 먼저 조회하고, 없으면 DB 조회 후 캐시에 넣음 가장 많이 사용, 캐시 미스 시 DB 부하
Write-Through DB에 쓸 때마다 캐시에도 동기적으로 반영 캐시와 DB가 항상 일치, 쓰기 비용 증가
Write-Behind DB에 쓰고 나중에 캐시를 비동기로 갱신 쓰기 성능 좋음, 일시적 불일치 가능

실무에서는 Cache-Aside를 가장 많이 사용하고, TTL을 두어 오래된 데이터는 자연스럽게 만료시키는 방식이 흔하다.


7. 주의점과 한계

휘발성

  • 기본적으로 메모리에만 있으므로 서버 재시작 시 데이터가 사라질 수 있다. 중요한 데이터는 Redis만 믿지 말고 DB를 원본으로 두고, Redis는 캐시·세션 등으로만 쓰는 것이 안전하다.

메모리 제한

  • 메모리 크기 한도가 있으므로 무한히 넣지 말고, TTL을 두거나 eviction 정책(maxmemory-policy)을 설정해 오래된/덜 쓰는 키를 지우도록 한다.

단일 스레드

  • 하나의 명령이 오래 걸리면 그동안 다른 명령이 대기한다. 무거운 연산이나 대량의 키를 한 번에 조회하는 패턴은 피하는 것이 좋다.

클러스터/복제

  • 고가용성과 확장이 필요하면 Redis Cluster, Replication 등을 고려한다. 주니어 단계에서는 단일 인스턴스 또는 Managed Redis(AWS ElastiCache 등)로 시작해도 충분하다.

8. 예상 꼬리 질문 정리

Q1. Redis와 RDBMS(MySQL 등)의 차이는?

Redis는 인메모리 키-값 저장소로, 디스크 I/O 없이 메모리에서 동작해 읽기·쓰기가 매우 빠릅니다. 주로 캐시, 세션, 랭킹에 사용합니다. RDBMS는 디스크 기반이고, 트랜잭션·정규화·복잡한 쿼리(JOIN 등)를 지원해 영구 저장과 데이터 무결성에 적합합니다. Redis는 보조 저장소·캐시로, DB와 함께 쓰는 경우가 많습니다.

Q2. Redis는 단일 스레드인데 왜 빠른가요?

명령 처리는 단일 스레드라 한 번에 하나의 명령만 실행되어 lock 없이 원자적으로 동작합니다. 실제로는 I/O 멀티플렉싱으로 여러 클라이언트 연결을 동시에 받고, 데이터가 메모리에 있어 디스크 I/O가 없기 때문에 전체적으로 매우 빠릅니다.

Q3. 캐시에 Redis를 쓰는 이유는?

메모리 기반이라 조회·저장이 빠르고, TTL을 줄 수 있어 만료된 데이터를 자동으로 지울 수 있습니다. 다양한 자료형(String, Hash, List, Set, Sorted Set)을 지원해 단순 키-값뿐 아니라 리스트·랭킹 등도 캐시하기 좋습니다.


요약

  • Redis는 인메모리 키-값 저장소로, 캐시, 세션, 랭킹, Pub/Sub 등에 널리 쓰인다.
  • 특징: 인메모리, 키-값, 단일 스레드(원자적 연산), TTL 지원.
  • 자료형: String, List, Set, Hash, Sorted Set — 용도에 맞게 선택한다.
  • Spring에서는 spring-boot-starter-data-redisRedisTemplate, 또는 @Cacheable 등으로 연동한다.
  • 캐시 전략은 Cache-Aside를 많이 쓰고, TTL과 eviction 정책으로 메모리를 관리한다.
  • 주의: 휘발성·메모리 한도·무거운 명령 자제. 중요한 데이터는 DB를 원본으로 두고 Redis는 보조로 사용한다.

참고 자료