Files
llm-wiki/raw/official-docs/redis-incr-rate-limiter-pattern.md

92 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "official-doc / Redis INCR — Atomicity & Rate Limiter Pattern Race Condition"
source_type: official-doc
url: https://redis.io/docs/latest/commands/incr/
archive_url:
related_branches: [feature-redis-atomic-program-catalog-contract]
related_projects: [ca-skeleton]
tags: [official-doc, ca-skeleton, caching, redis, rate-limit]
created: 2026-07-28
last_reviewed: 2026-07-28
status: raw
confidence: high
vendor: Redis
author: Redis (official docs)
published:
---
# 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 508509 in fetched text)
> [§Details > Pattern: rate limiter > Pattern: 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."
> (lines 565566 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 `INCR` command but does not perform the `EXPIRE` the key will be leaked until we'll see the same IP address again."
> (lines 594595 in fetched text)
> [§Details > Pattern: rate limiter > Pattern: 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)."
> (lines 597599 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`→조건부 `EXPIRE` recipe 에 공식 문서가 인정하는 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/` 예정)