Redis 주니어 코딩 면접

Redis 주니어 (1~3년) 코딩 · 알고리즘 5문항 조회수 88 · 2026-07-23 (목) 11:10:58
1 데이터 구조 선택
Medium

Q. 음악 스트리밍 서비스에서 사용자가 최근 재생한 곡 목록을 관리하려고 합니다. 최근 재생한 50곡을 시간 순서대로 유지하되, 같은 곡을 다시 재생하면 이전 기록은 제거하고 최신 위치에만 추가되어야 합니다. 이를 Redis로 구현할 때 어떤 데이터 타입을 사용하고 어떤 명령어 조합으로 구현할 수 있는지 설명해주세요.

A. 모범답안

Sorted Set을 사용하여 구현하는 것이 적합합니다. 재생 시각을 타임스탬프로 score에 저장하고 곡 ID를 member로 저장합니다. ZADD 명령어는 기존 member가 있으면 score만 업데이트하므로 중복이 자동으로 제거됩니다. ZREVRANGE 명령어로 최근 50개를 조회하고, ZREMRANGEBYRANK 명령어로 50개를 초과하는 오래된 항목을 삭제할 수 있습니다. 예를 들어 ZADD recent:user:123 1234567890 song:456 명령으로 재생 기록을 추가하고, ZREVRANGE recent:user:123 0 49로 최근 50곡을 조회할 수 있습니다.

핵심 포인트
  • • Sorted Set을 사용하여 타임스탬프 기반 정렬과 중복 제거를 동시에 해결
  • • ZADD는 기존 member의 score를 자동으로 업데이트하여 중복 제거
  • • ZREVRANGE로 최신순 조회, ZREMRANGEBYRANK로 개수 제한 관리
Follow-up 질문

만약 사용자가 재생한 모든 곡의 재생 횟수도 함께 관리해야 한다면 어떤 데이터 구조를 추가로 사용해야 할까요?

2 데이터 일괄 처리
Medium

Q. 배치 작업으로 10만 개의 상품 가격 정보를 Redis에 업데이트해야 합니다. 각 상품은 product:price:{product_id} 형태의 키로 저장됩니다. 단순 반복문으로 SET 명령어를 10만 번 실행하는 것보다 성능을 개선할 수 있는 방법을 설명하고, Python Redis 클라이언트를 사용한다고 가정할 때 어떻게 구현할 수 있는지 설명해주세요.

A. 모범답안

Pipeline을 사용하여 네트워크 왕복 시간(RTT)을 줄일 수 있습니다. 일반적인 SET 명령어는 매번 클라이언트-서버 간 요청-응답을 기다리지만, Pipeline은 여러 명령어를 한 번에 전송하고 응답을 일괄 수신합니다. Python에서는 r.pipeline()으로 파이프라인 객체를 생성하고, 반복문 안에서 pipe.set()으로 명령어를 추가한 뒤 pipe.execute()로 실행합니다. 메모리 관리를 위해 1000~5000개씩 배치로 나누어 execute()를 호출하는 것이 좋습니다. 이 방법으로 10만 번의 RTT를 20~100번으로 줄여 성능을 크게 향상시킬 수 있습니다.

핵심 포인트
  • • Pipeline을 사용하여 네트워크 왕복 시간(RTT)을 대폭 감소
  • • 여러 명령어를 버퍼에 모았다가 한 번에 전송하여 처리
  • • 메모리 사용량을 고려하여 적절한 배치 크기로 분할 실행
Follow-up 질문

Pipeline 사용 시 주의해야 할 점은 무엇이며, MULTI/EXEC와는 어떤 차이가 있나요?

3 조건부 연산
Medium

Q. 쿠폰 발급 시스템에서 선착순 1000명에게만 쿠폰을 발급해야 합니다. 동시에 수천 명의 사용자가 쿠폰 발급을 요청할 때, Redis를 사용하여 정확히 1000개만 발급되도록 보장하려면 어떤 명령어와 로직을 사용해야 하는지 설명해주세요. 발급 가능 여부 확인과 카운트 증가가 원자적으로 처리되어야 합니다.

A. 모범답안

INCR 명령어를 사용하여 원자적으로 카운터를 증가시키고 그 결과값을 확인하는 방식이 가장 안전합니다. INCR coupon:issued 명령어를 실행하면 현재값이 1 증가된 결과를 반환받는데, 이 값이 1000 이하인 경우에만 쿠폰을 발급합니다. INCR은 원자적 연산이므로 동시에 여러 요청이 들어와도 정확한 카운팅이 보장됩니다. 만약 반환값이 1000을 초과하면 쿠폰 발급을 거부하고 사용자에게 마감 메시지를 전달합니다. 추가로 발급된 쿠폰 정보는 별도의 Set이나 Hash로 관리할 수 있습니다.

핵심 포인트
  • • INCR 명령어의 원자적 특성을 활용하여 동시성 문제 해결
  • • 증가된 결과값을 확인하여 발급 가능 여부 판단
  • • GET 후 SET 방식은 Race Condition이 발생하므로 사용 불가
Follow-up 질문

만약 쿠폰 발급 후 사용자가 취소할 수 있다면 어떻게 구현해야 할까요?

4 복합 자료구조 설계
Hard

Q. 실시간 주식 거래 시스템에서 각 종목별로 최근 거래 내역 100건과 현재 체결가, 거래량, 시가, 고가, 저가 등의 실시간 정보를 함께 관리해야 합니다. 초당 수천 건의 거래가 발생하고 클라이언트는 특정 종목의 정보를 빈번하게 조회합니다. 이를 Redis로 효율적으로 설계할 때 어떤 데이터 타입 조합을 사용하고 각각 어떤 명령어로 구현할 수 있는지 설명해주세요.

A. 모범답안

두 가지 데이터 구조를 조합하여 사용합니다. 첫째, 실시간 시세 정보는 Hash를 사용하여 stock:info:{종목코드} 키에 저장하고, HSET으로 개별 필드를 업데이트하며 HGETALL로 전체 정보를 조회합니다. 둘째, 최근 거래 내역은 List를 사용하여 stock:trades:{종목코드} 키에 저장하고, LPUSH로 새 거래를 추가하며 LTRIM으로 100개로 제한합니다. LRANGE로 최근 거래 내역을 조회할 수 있습니다. 이렇게 분리하면 시세 정보는 부분 업데이트가 가능하고, 거래 내역은 시간순 관리가 용이하며, 각각 독립적으로 조회할 수 있어 효율적입니다.

핵심 포인트
  • • Hash로 실시간 시세의 여러 필드를 효율적으로 관리
  • • List로 시간순 거래 내역을 관리하고 LTRIM으로 개수 제한
  • • 목적에 따라 데이터를 분리하여 조회 및 업데이트 효율성 확보
Follow-up 질문

만약 거래 내역을 시간 범위로 조회해야 한다면 어떤 데이터 타입이 더 적합할까요?

5 Lua 스크립트 활용
Hard

Q. 재고 차감 시스템에서 상품의 현재 재고를 확인하고, 재고가 충분하면 차감하고 부족하면 에러를 반환해야 합니다. 재고 확인과 차감 사이에 다른 요청이 끼어들면 안 됩니다. Redis에서 WATCH와 MULTI/EXEC를 사용하는 방법과 Lua 스크립트를 사용하는 방법 중 어느 것이 더 적합한지 비교하고, Lua 스크립트로 구현할 때 어떤 로직을 작성해야 하는지 설명해주세요.

A. 모범답안

Lua 스크립트가 더 적합합니다. WATCH/MULTI/EXEC는 낙관적 잠금 방식으로 충돌 시 재시도가 필요하지만, Lua 스크립트는 원자적으로 실행되어 재시도 로직이 불필요합니다. Lua 스크립트에서는 redis.call('GET', KEYS[1])로 현재 재고를 가져오고, tonumber로 숫자로 변환한 뒤 요청 수량과 비교합니다. 재고가 충분하면 redis.call('DECRBY', KEYS[1], ARGV[1])로 차감하고 성공을 반환하고, 부족하면 에러 메시지를 반환합니다. EVAL 명령어로 스크립트를 실행하며, KEYS에는 재고 키를, ARGV에는 차감 수량을 전달합니다. 이 방식은 네트워크 왕복도 1회로 줄어 성능도 우수합니다.

핵심 포인트
  • • Lua 스크립트는 원자적 실행이 보장되어 재시도 로직 불필요
  • • 조건 확인과 데이터 변경을 하나의 스크립트로 처리
  • • WATCH/MULTI/EXEC 대비 충돌 상황에서 성능이 우수
Follow-up 질문

Lua 스크립트를 프로덕션에서 사용할 때 성능을 위해 고려해야 할 사항은 무엇인가요?

댓글 0

로그인 후 댓글을 작성할 수 있습니다.

아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!