RSS

서버리스 프로젝트에서 Redis가 빛날 때

Vercel은 코드를 실행하고, Supabase는 데이터를 영구 저장하며, QStash는 비동기 작업을 전달한다. 여기까지 이해하고 나면 Redis의 자리가 모호하게 느껴질 수 있다.

Redis를 가장 쉽게 설명하면 여러 서버리스 함수가 함께 사용하는 빠른 공용 메모장이다.

상품과 주문의 원본은 Supabase에 저장한다. Redis에는 요청 횟수, 잠깐 재사용할 조회 결과, 작업 잠금처럼 빠르게 읽고 자주 바뀌며 일정 시간이 지나면 지워도 되는 값을 둔다.

서버리스 함수의 메모리는 공용이 아니다

서버리스 플랫폼은 요청량에 따라 여러 함수 인스턴스를 만들 수 있다.

사용자 A → Vercel 함수 1의 메모리
사용자 B → Vercel 함수 2의 메모리
QStash   → Vercel 함수 3의 메모리

각 함수가 가진 메모리는 서로 공유되지 않는다. 함수가 종료되거나 새로운 인스턴스가 만들어지면 메모리에 저장한 값이 유지된다고 보장할 수도 없다.

Redis를 가운데 두면 모든 함수가 같은 값을 볼 수 있다.

Vercel 주문 API ─┐
Vercel 조회 API ─┼──> Upstash Redis
Vercel Worker ───┘      공용 임시 상태

각 함수 ──────────────> Supabase
                         영구 데이터

Redis가 빛나는 순간은 다음 세 조건이 겹칠 때다.

실행 인스턴스가 여러 개이고, 모두 같은 값을 봐야 하며, 그 값을 빠르게 자주 변경해야 할 때

첫 번째: 여러 인스턴스에 걸친 요청 제한

주문 API를 IP당 1분에 10회로 제한한다고 해보자. 각 Vercel 함수의 메모리에 숫자를 저장하면 제한이 정확하지 않다.

함수 A가 센 요청: 7회
함수 B가 센 요청: 6회
실제 전체 요청: 13회

각 함수는 10회를 넘지 않았다고 판단하지만 실제 제한은 이미 초과했다.

Redis에 하나의 공용 카운터를 두면 어느 함수가 요청을 받아도 같은 숫자를 증가시킨다.

키: rate:order:사용자식별값
값: 7
만료 시간: 60초

Redis의 INCR는 숫자를 원자적으로 증가시키고, EXPIRE는 시간이 지나면 키를 자동으로 정리한다. Redis 공식 문서에서도 여러 분산 서비스 인스턴스가 같은 요청 한도를 적용해야 할 때 Redis 기반 요청 제한을 사용하도록 설명한다.

작은 서버리스 프로젝트에서 Redis를 처음 경험하기에는 이 기능이 가장 좋다. 결과가 눈에 보이고, 함수 메모리만 사용했을 때 무엇이 잘못되는지도 이해하기 쉽다.

두 번째: 반복 조회를 줄이는 캐시

상품 목록이 자주 조회되지만 몇 초 동안 같은 결과를 반환해도 괜찮다면 매번 Supabase를 조회할 필요가 없다.

첫 요청
Redis 확인 → 없음 → Supabase 조회 → Redis에 30초 저장

다음 요청
Redis 확인 → 있음 → 바로 반환

이 패턴은 응답 시간을 줄이고 PostgreSQL이 반복해서 수행하는 읽기 작업을 줄인다. 다만 캐시는 원본이 아니다. Redis 값이 사라지면 Supabase에서 다시 만들 수 있어야 한다.

캐시를 도입할 때는 먼저 세 가지를 정해야 한다.

  • 얼마나 오래 저장할 것인가
  • 상품이 변경되면 캐시를 바로 지울 것인가
  • Redis에 문제가 생기면 Supabase를 직접 조회할 것인가

캐시 무효화 규칙 없이 Redis부터 추가하면 빠른 데이터와 정확한 데이터가 서로 달라지는 문제가 생긴다.

세 번째: 중복 Worker 실행을 조정할 때

QStash는 실패한 작업을 재시도하므로 같은 작업이 다시 전달될 수 있다. 두 Worker가 같은 주문을 동시에 처리하지 않도록 Redis에 짧은 잠금을 둘 수 있다.

키: lock:order:123
값: processing
만료 시간: 30초

한 Worker가 잠금을 얻으면 다른 Worker는 작업을 건너뛴다. 잠금에는 반드시 만료 시간을 둬야 한다. Worker가 중간에 종료됐는데 잠금이 영원히 남으면 이후 처리까지 막히기 때문이다.

Redis 잠금만으로 최종 완료를 판단해서는 안 된다. processedAt이나 작업 ID처럼 영구적인 처리 결과는 Supabase에도 기록해야 한다. Redis는 동시 실행을 조정하고, Supabase는 최종 사실을 보관한다.

네 번째: 짧게 살아 있는 실시간 상태

다음 데이터도 Redis와 잘 맞는다.

  • 현재 접속자 수
  • 인기 상품 순위
  • 몇 분 동안 유지할 인증 시도 횟수
  • 실시간 대시보드 카운터
  • 짧은 사용자 세션이나 임시 인증 흐름

이 값들은 매우 자주 변하고 빠르게 읽어야 한다. 일부는 일정 시간이 지나면 자동으로 사라져야 한다. 키마다 만료 시간을 설정할 수 있는 Redis의 특성이 잘 맞는 영역이다.

Supabase와 Redis는 경쟁 관계가 아니다

두 저장소는 목적이 다르다.

Supabase에 둘 것 Redis에 둘 것
주문, 금액, 재고 요청 횟수
고객이 확인할 처리 결과 짧은 작업 잠금
관계와 이력이 중요한 데이터 다시 만들 수 있는 캐시
트랜잭션이 필요한 원본 빠르게 변하는 실시간 카운터

Upstash Redis는 데이터를 디스크에 유지하는 기능도 제공하지만, 애플리케이션 설계에서는 여전히 중요한 원본과 재구성 가능한 보조 데이터를 구분하는 편이 안전하다. Redis가 빠르다는 이유로 주문이나 결제의 유일한 원본을 옮길 필요는 없다.

QStash와 Redis도 서로 다른 역할이다

두 서비스 모두 Upstash에서 제공되기 때문에 한 묶음처럼 보이지만 독립적인 도구다.

QStash: 이 작업을 Worker에 전달해 주세요
Redis: 지금 공유해야 할 값은 이것입니다

QStash는 메시지 전달과 재시도를 책임진다. Redis는 카운터, 캐시, 잠금 같은 상태를 저장한다. QStash Worker를 사용한다고 Redis가 자동으로 필요한 것은 아니며, Redis를 사용한다고 QStash가 필요한 것도 아니다.

Redis가 아직 필요하지 않은 경우

다음 상황에서는 Supabase와 함수 코드만으로 충분할 수 있다.

  • 트래픽이 적어 데이터베이스 부하가 문제되지 않는다.
  • 모든 값이 영구적인 업무 데이터다.
  • 정확한 분산 요청 제한이 필요하지 않다.
  • 여러 Worker의 동시 실행을 조정할 일이 없다.
  • 캐시 없이도 응답 속도가 충분하다.

Redis를 추가하면 환경변수, 네트워크 호출, 장애 처리, 비용 관찰 대상도 함께 늘어난다. 필요가 증명되기 전에 도입하면 학습 목적 외에는 복잡도만 늘 수 있다.

도입 시점을 판단하는 질문

다음 질문 중 하나에 명확히 “예”라고 답할 수 있을 때 Redis를 검토하면 된다.

  1. 여러 함수가 같은 요청 횟수를 정확히 공유해야 하는가?
  2. 반복되는 DB 조회가 실제 병목인가?
  3. 같은 작업이 동시에 실행되지 않도록 빠른 잠금이 필요한가?
  4. 수초나 수분 뒤 자동으로 사라질 상태가 많은가?
  5. 매우 자주 변하는 숫자를 빠르게 읽고 써야 하는가?

해당되는 항목이 없다면 Redis 없이 시작해도 된다.

작은 프로젝트에 적용하는 가장 쉬운 방법

첫 기능은 주문 API 요청 제한이 적합하다.

1. 주문 요청이 들어온다.
2. Upstash Redis에서 식별값별 요청 횟수를 확인한다.
3. 1분 동안 10회 이하면 주문을 처리한다.
4. 10회를 넘으면 429 응답을 반환한다.
5. 1분이 지나면 카운터가 자동으로 만료된다.

이 기능 하나로 서버리스 인스턴스의 독립성, 공용 상태, 원자적 카운터, 만료 시간이라는 Redis의 핵심을 모두 경험할 수 있다. 이후 상품 조회가 실제로 많아질 때 캐시를, Worker 중복 실행 문제가 생길 때 잠금을 추가하면 된다.

정리

서버리스 프로젝트에서 Redis는 항상 필요한 데이터베이스가 아니다. 여러 함수가 공유해야 하는 짧고 빠른 상태가 생겼을 때 빛나는 보조 저장소다.

Supabase = 영구 장부
QStash = 작업 전달 기사
Vercel = 코드를 실행하는 공간
Redis = 모두가 함께 보는 빠른 메모장

원본 데이터는 Supabase에 남기고, 요청 제한·캐시·잠금·실시간 카운터처럼 다시 만들 수 있는 상태부터 Redis에 맡기는 것이 가장 이해하기 쉽고 안전한 시작점이다.

참고 자료