TIL

08. Lua Scripting

핵심 명령

EVAL

EVAL "return redis.call('GET', KEYS[1])" 1 stock:evt_123

EVALSHA / SCRIPT LOAD

SCRIPT LOAD "<script>"              # → sha1 반환
EVALSHA <sha1> 1 stock:evt_123 3    # numkeys=1, KEYS[1]=stock:evt_123, ARGV[1]=3

KEYS와 ARGV

원자성

-- KEYS[1]=재고 키, ARGV[1]=차감 수량
local left = tonumber(redis.call('GET', KEYS[1]))
if left == nil then return -2 end                 -- 키 없음
if left < tonumber(ARGV[1]) then return -1 end    -- 재고 부족
return redis.call('DECRBY', KEYS[1], ARGV[1])     -- 차감 후 잔량 반환

redis.call vs redis.pcall

실행 모델과 한계

단일 스레드 블로킹

쓰기 스크립트는 마스터 전용

롤백 없음

결정성과 effects replication

Redis Functions (7.0+)

Transaction vs Lua 비교

기준 Transaction (WATCH/MULTI) Lua Script
원자성 확보 낙관적 — 감시 키 변경 시 취소 → 재시도 스크립트 전체를 단일 실행 단위로 강제
read-modify-write WATCH로 우회(읽기는 트랜잭션 밖) 스크립트 안에서 직접 처리
재시도 고경합 시 필요 (retry storm) 불필요
읽기 복제본 분산 가능 쓰기 스크립트는 마스터 전용(불가)
블로킹 짧음 긴 스크립트는 서버 전체 블로킹
네트워크 명령들 왕복(파이프라인) EVALSHA로 단일 RTT
가독성·디버깅 명령 단위로 명확 별도 Lua라 디버깅·테스트 어려움
롤백 없음 없음 (중간 실패해도 이전 effect 유지)
적합 상황 단순 CAS, 저경합 복잡한 다단계 원자 연산, 고경합

참고