ONE QUESTION AT A TIME.

천천히 생각하고, 분명하게.

TODAY’S QUESTION1225 / 1500
데이터베이스난이도 중하5분 답변 목표 · 보강본

Redis에 여러 명령을 보내는 왕복 비용을 줄이면서 조회 결과에 따른 갱신도 안전하게 처리하려 합니다. 파이프라이닝·MULTI/EXEC·Lua 중 무엇을 선택하나요?

잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?

답변과 점검 포인트 펼치기답변 접기
01

구두 답변

정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.

파이프라이닝·MULTI/EXEC·Lua는 줄이는 비용과 보장하는 범위가 다릅니다. 파이프라이닝은 여러 명령의 왕복 대기를 줄이는 통신 방식일 뿐 명령 사이에 다른 클라이언트가 끼어들지 않게 하거나 조건부 분기를 만들지 않습니다. MULTI/EXEC는 묶인 명령을 실행할 때 다른 클라이언트 명령이 중간에 끼어들지 않게 하지만, EXEC 전에 클라이언트가 GET 결과를 받아 다음 명령을 선택하게 하지는 않습니다. Lua는 Redis 안에서 읽기·판단·변경을 짧게 수행할 때 적합합니다.

재고 예제로 차이를 고정합니다

파이프라인으로 GET stock과 DECR stock을 함께 보내면 왕복은 줄어도 GET 결과를 확인하기 전에 DECR가 전송됩니다. 재고가 0이어도 줄어들 수 있고 다른 클라이언트가 사이에 실행할 수 있습니다. 단순 MULTI/EXEC에 같은 명령을 넣어도 GET 결과에 따라 DECR를 선택할 수 없으므로 같은 문제가 남습니다. 클라이언트에서 판단하려면 WATCH stock, GET, 값 확인, MULTI/DECR/EXEC의 낙관적 재시도를 사용하고 EXEC가 충돌하면 최신 값을 다시 읽어야 합니다.

Lua는 다음처럼 작은 비음수 정수 재고를 가정하고 서버 안에서 분기할 수 있습니다.

local stock = tonumber(redis.call('GET', KEYS[1]))
if stock > 0 then
    redis.call('DECR', KEYS[1])
    return 1
end
return 0

키 누락·잘못된 타입·음수 정책은 실제 코드에서 정의해야 합니다. Lua의 원자적 실행은 해당 Redis 노드에서 다른 명령이 끼어들지 않는다는 뜻이지 일반 DB처럼 모든 오류를 앞선 변경까지 자동 rollback한다는 뜻은 아닙니다. 실행 중 오류로 이미 수행된 쓰기가 남을 수 있고, 긴 스크립트는 모든 클라이언트 지연을 키웁니다.

방법 읽은 값으로 분기하는 위치 실패 시 남는 책임
파이프라인 이미 명령을 전송했으므로 이전 GET 결과로 후속 명령을 고를 수 없음 개별 오류와 중복 재시도
WATCH + MULTI/EXEC WATCH 후 GET을 읽은 클라이언트 EXEC 충돌 시 다시 읽고 판단
Lua 서버 안에서 읽고 분기 쓰기 전 입력 검증, 실행 오류와 응답 유실

WATCH 방식은 같은 연결에서 WATCH→GET→판단→MULTI→갱신→EXEC를 수행합니다. 조건이 맞지 않아 갱신하지 않으면 UNWATCH로 감시를 끝냅니다. 충돌로 EXEC가 중단되면 예전 판단을 재사용하지 않고 다시 읽어야 합니다.

클러스터와 재시도를 함께 설계합니다

Redis Cluster에서 Lua·다중 키 트랜잭션은 관련 키가 같은 슬롯에 있어야 합니다. hash tag로 묶을 수 있지만 핫 슬롯과 두 계정 이체의 분산 제약이 생깁니다. 타임아웃 뒤 성공 응답을 잃으면 클라이언트는 명령이 실행됐는지 모릅니다. 재고 감소와 요청 처리 ID를 같은 원자 범위에 기록하거나, 결과 조회 가능한 상태를 두어 중복 감소를 막겠습니다.

독립적인 다건 GET은 제한된 pipeline이 적합하고, 단순한 원자 명령으로 표현 가능한 조건부 변경은 그 명령을 먼저 검토합니다. 여러 키의 짧은 판단이 필요하면 Lua 또는 WATCH 재시도를 선택하되 스크립트 실행 시간과 충돌 재시도 폭을 제한합니다. 검증은 동시 차감·스크립트 오류·EXEC 충돌·응답 유실·슬롯 이동을 재현해 재고가 음수가 되지 않고 요청 ID 중복이 안전하게 처리되는지 확인하겠습니다.

파이프라인은 응답을 모아 읽는 방식이므로 각 명령의 오류 응답을 빠뜨리지 않고 순서대로 해석해야 합니다. MULTI 단계에서 명령 큐잉 자체가 실패한 경우와 EXEC 중 한 명령이 오류를 반환한 경우를 분리하며, EXEC의 비간섭성이 일반적인 rollback을 뜻하지 않는다는 점을 코드 계약에 남깁니다. Lua에서는 입력 키가 KEYS로 전달되는지, 외부 네트워크 호출이나 무제한 반복이 없는지 확인합니다. 같은 요청을 재실행할 때 처리 ID와 결과를 함께 검사하겠습니다.

02

득점 포인트

이해가 드러나는 지점을 확인해 보세요.

  • 왕복 감소·끼어듦 방지·서버 내부 분기를 구분한다.
  • WATCH 재시도와 Lua의 판단 위치·실패 범위를 비교한다.
  • rollback 오해·긴 스크립트·클러스터 슬롯·응답 유실을 포함한다.
03

감점 포인트

놓치기 쉬운 조건과 오해를 짚어 보세요.

  • pipeline이 자동 원자적이라고 말한다.
  • MULTI 안에서 GET 결과를 받아 다음 명령을 정한다고 한다.
  • Redis 오류가 앞선 쓰기를 항상 롤백한다고 설명한다.
04

더 파고들 거리

하나 더 질문하며 이해의 범위를 넓혀 보세요.

득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.

원리부터 공부하고 싶다면

답변을 보충하는 개념·예제·슈도코드를 읽어 보세요.

← 전체 질문 보기