9.4 KiB
title, source_type, url, archive_url, related_branches, related_projects, tags, created, last_reviewed, status, confidence, vendor, author, published
| title | source_type | url | archive_url | related_branches | related_projects | tags | created | last_reviewed | status | confidence | vendor | author | published | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| official-doc / Redis INCR — Atomicity & Rate Limiter Pattern Race Condition | official-doc | https://redis.io/docs/latest/commands/incr/ |
|
|
|
2026-07-28 | 2026-07-28 | raw | high | Redis | Redis (official docs) |
Redis INCR — Atomicity & Rate Limiter Pattern Race Condition
Layer:
raw/official-docs/— Redis 공식 커맨드 레퍼런스(INCR) 원문 발췌·출처 기록. 검증된 요약은/ingest후wiki/concepts/에source-summary-template형식으로 별도 작성. 원본은 raw에 영구 보관.
Parent / 활용 branch
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| raw/branch-notes/feature-redis-atomic-program-catalog-contract | 각 atomic program helper 는 흔한 unsafe multi-command recipe 와 그 안전한 atomic 대체를 쌍으로 문서화한다 — 대표 사례 GET → 판단 → INCR → EXPIRE 의 race condition 을 공식 문서가 명시적으로 서술한다는 근거 |
출처 / Source
- 원본 URL: https://redis.io/docs/latest/commands/incr/
- 아카이브 URL: (미제공)
- 저자 / 조직: Redis (공식 커맨드 레퍼런스)
- 발행일: (페이지에 명시 없음 —
since: 1.0.0커맨드 메타데이터만 존재) - 마지막 확인일: 2026-07-28
왜 저장했는지 / Why archived
feature-redis-atomic-program-catalog-contract branch 는 "다단계 read-decide-write recipe 는 항상 unsafe 버전과 atomic 대체를 쌍으로 문서화한다"는 프로젝트 결정(DEC-CA-SKELETON-OPERATIONAL-CONTRACT-REDIS-PROGRAM-001)을 구현해야 한다. Redis 공식 INCR 문서의 "Pattern: rate limiter" 절이 바로 이 다단계 recipe (GET → 판단 → INCR → 조건부 EXPIRE)의 race condition 을 공식적으로 서술하고, MULTI/EXEC 및 Lua(EVAL) 대체를 명시적으로 권고하므로 1차 근거로 확보한다.
핵심 인용 / Key quotes (verbatim)
[§Details > Pattern: counter] "The counter pattern is the most obvious thing you can do with Redis atomic increment operations." (lines 508–509 in fetched text)
[§Details > Pattern: rate limiter > Pattern: rate limiter 1] "Note the used of
MULTIandEXECin order to make sure that we'll both increment and set the expire at every API call." (lines 565–566 in fetched text)
[§Details > Pattern: rate limiter > Pattern: rate limiter 2] "In the above code there is a race condition." (line 593 in fetched text)
[§Details > Pattern: rate limiter > Pattern: rate limiter 2] "If for some reason the client performs the
INCRcommand but does not perform theEXPIREthe key will be leaked until we'll see the same IP address again." (lines 594–595 in fetched text)
[§Details > Pattern: rate limiter > Pattern: rate limiter 2] "This can be easily fixed by turning the
INCRwith optionalEXPIREinto a Lua script that is then sent using theEVALcommand (only available since Redis version 2.6)." (lines 597–599 in fetched text)
Claims Extracted / 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| REDIS-INCR-C1 | INCR 은 "atomic increment operation" 으로 서술된다 — 단일 INCR 호출 자체는 원자적이다 |
[§Pattern: counter] "The counter pattern is the most obvious thing you can do with Redis atomic increment operations." | official-vendor-doc |
단일 INCR 커맨드 호출 자체의 원자성 (per-command atomicity) |
여러 명령(GET→판단→INCR→EXPIRE)을 조합한 시퀀스 전체 가 원자적이라는 것 — 오히려 본 문서가 뒤에서 이를 반박(REDIS-INCR-C2) |
| REDIS-INCR-C2 | "GET 으로 현재값 확인 → 조건부 INCR → 첫 증가 시에만 EXPIRE" 형태의 rate limiter 구현("Pattern: rate limiter 2")에 대해 공식 문서가 명시적으로 race condition 존재를 선언한다 |
[§Pattern: rate limiter 2] "In the above code there is a race condition." | official-vendor-doc |
GET/INCR/조건부 EXPIRE 다단계 recipe 에 race 가 실재한다는 사실 자체 |
다른 언어·클라이언트 구현에서도 항상 동일 race 가 발생한다는 일반화 — 문서는 이 특정 pseudocode 예시에 대해서만 명시함 |
| REDIS-INCR-C3 | 위 race 의 구체적 실패 모드는 "클라이언트가 INCR 은 수행했지만 EXPIRE 를 수행하지 못한 경우" 이며, 이 경우 같은 IP 를 다시 볼 때까지 key 가 TTL 없이 leak 된다 |
[§Pattern: rate limiter 2] "If for some reason the client performs the INCR command but does not perform the EXPIRE the key will be leaked until we'll see the same IP address again." |
official-vendor-doc |
INCR 성공 후 EXPIRE 미실행(크래시·네트워크 단절 등) 시 key 누수 시나리오 |
이 leak 이 rate-limit 판정 정확성 자체를 깨뜨린다는 것 — 문서는 메모리/키 누수로 서술하지, 카운트 오판으로 서술하지 않음 |
| REDIS-INCR-C4 | 공식 문서는 두 가지 다른 recipe 에 두 가지 다른 대체를 권고한다 — (a) 고정 타임스탬프 키 카운터("rate limiter 1")에는 INCR+EXPIRE 를 MULTI/EXEC 로 묶을 것을, (b) 조건부 분기가 있는 단일 카운터("rate limiter 2")에는 INCR+조건부 EXPIRE 를 Lua 스크립트로 옮겨 EVAL 로 실행할 것을 권고한다 |
[§rate limiter 1] "Note the used of MULTI and EXEC in order to make sure that we'll both increment and set the expire at every API call." + [§rate limiter 2] "This can be easily fixed by turning the INCR with optional EXPIRE into a Lua script that is then sent using the EVAL command (only available since Redis version 2.6)." |
official-vendor-doc |
두 recipe 각각에 맞는 공식 대체 메커니즘 선택 근거 | MULTI/EXEC 가 "rate limiter 2" 처럼 읽은 값을 기준으로 분기(IF value == 1 THEN EXPIRE)하는 recipe 의 race 도 없앤다는 것 — 문서는 그 recipe 의 fix 로 MULTI/EXEC 가 아니라 Lua 를 명시적으로 별도 제시함 (조건부 분기 recipe 와 무분기 recipe 는 다른 처방) |
Usage Boundaries / 적용 경계
- 이 자료가 직접 증명하는 것:
REDIS-INCR-C1:INCR단일 커맨드 자체가 원자적이라는 공식 서술REDIS-INCR-C2:GET→판단→INCR→조건부EXPIRErecipe 에 공식 문서가 인정하는 race condition 이 존재한다는 사실REDIS-INCR-C3: 그 race 의 구체적 실패 모드(EXPIRE 유실 시 key leak)REDIS-INCR-C4: recipe 종류에 따라 공식이 권고하는 두 가지 다른 대체 메커니즘(MULTI/EXEC vs Lua/EVAL)
- 이 자료가 증명하지 않는 것:
MULTI/EXEC가 조건부 분기(읽은 값에 따라 다음 커맨드를 결정)가 있는 recipe 의 race 도 없앤다는 것 — 문서는 이 경우 Lua 를 명시적으로 제시EVAL/Lua 스크립트가 모든 Redis 배포 모드(clustered, Redis Functions 등)에서 동일하게 동작한다는 것 — 버전 제약("only available since Redis version 2.6")만 명시- key leak 이 실제 운영 환경에서 관측 가능한 심각도(메모리 규모·발생 빈도)를 가진다는 것 — 문서는 정성적 서술만 제공, 정량적 근거 없음
- ca-tmpl/ca-skeleton 의
ScriptDescriptor/EVALSHA/NOSCRIPT 재적재 같은 구체적 구현 메커니즘 — 이는 본 branch 의 로컬 결정 사항이지 이 공식 문서의 주장이 아님
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
feature-redis-atomic-program-catalog-contract의 unsafe recipe 카탈로그에 이GET→INCR→조건부EXPIRE패턴을 등재할 때, 대응 atomic 대체를 Lua 스크립트(EVALSHA)로 명시하고 MULTI/EXEC 로 오인하지 않도록 §구현 가이드에서 구분해야 함- 경합 재현 test 시나리오는 REDIS-INCR-C2/C3 의 실패 모드(첫 INCR 성공 후 EXPIRE 실패)를 인위적으로 유발할 수 있는 fault-injection 지점 확인 필요
메모 / Notes
- 본 문서의 "Pattern: rate limiter" 절은 rate limiter 1(고정 타임스탬프 키, 분기 없음 → MULTI/EXEC 로 충분)과 rate limiter 2(단일 카운터,
IF value == 1분기 있음 → MULTI/EXEC 로 불충분, Lua 필요)를 구분해서 서술한다. branch 의 unsafe-recipe 카탈로그를 작성할 때 이 두 변형을 하나의 "INCR+EXPIRE" 항목으로 뭉뚱그리면 REDIS-INCR-C4 의 구분을 잃는다 — 별개 카탈로그 항목으로 분리 권장. - 문서는 "Pattern: rate limiter 2" 의 세 번째 대안으로 Redis list(
RPUSH/RPUSHX/LLEN) 기반 구현도 제시하며, 여기에도EXISTS확인과MULTI/EXEC사이의 race 가 있지만 "rare conditions 에서 API call 하나를 놓치는 정도"로 무해하다고 서술한다 — 이는 이번 branch 의 핵심 인용 범위(GET→INCR→EXPIRE) 밖이라 인용에는 포함하지 않았으나, "모든 race 가 치명적인 것은 아니다"라는 대비 사례로 §메모에만 남긴다(검증 안 된 해석이므로 claim 화하지 않음).
Related / 관련
- 같은 프로젝트 내 Redis 원자성/락 관련 다른 official-doc: raw/official-docs/cache-redisson-rlock-vs-setnx
- 이 자료를 인용한 wiki 요약: (미생성 —
/ingest후wiki/concepts/예정)