diff --git "a/004.\354\262\230\353\246\254\354\234\250\354\240\234\355\225\234\354\236\245\354\271\230\354\204\244\352\263\204" "b/004.\354\262\230\353\246\254\354\234\250\354\240\234\355\225\234\354\236\245\354\271\230\354\204\244\352\263\204"
deleted file mode 100644
index 8b13789..0000000
--- "a/004.\354\262\230\353\246\254\354\234\250\354\240\234\355\225\234\354\236\245\354\271\230\354\204\244\352\263\204"
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git "a/004_\354\262\230\353\246\254\354\234\250\354\240\234\355\225\234\354\236\245\354\271\230\354\204\244\352\263\204/2\354\243\274\354\260\250.md" "b/004_\354\262\230\353\246\254\354\234\250\354\240\234\355\225\234\354\236\245\354\271\230\354\204\244\352\263\204/2\354\243\274\354\260\250.md"
new file mode 100644
index 0000000..d813b92
--- /dev/null
+++ "b/004_\354\262\230\353\246\254\354\234\250\354\240\234\355\225\234\354\236\245\354\271\230\354\204\244\352\263\204/2\354\243\274\354\260\250.md"
@@ -0,0 +1,115 @@
+### 어떠한 처리율 제한 알고리즘을 사용할 것인가 ?
+
+- 토큰 버킷 알고리즘과 이동 윈도우 카운터 알고리즘에 대해서 고민
+- 토큰 버킷 알고리즘에서 토큰 버킷이란 지정된 용량을 갖는 컨테이너다. 각 요청이 처리될 때마다, 하나의 토큰을 사용한다. 요청이 도착하면, 충분한 토큰이 있으면 시스템에 전달하고, 충분한 토큰이 없으면, 버려지게 되는 경우.
+- 토큰 버킷 알고리즘은 2개의 인자를 받는다.
+ - 버킷 크기 : 버킷에 담을 수 있는 토큰의 최대 개수
+ - 토큰 공급률 : 초당 몇개의 토큰이 버킷에 공급되는 가?
+- 장점 - 구현이 쉽고, 메모리 사용 측면에서 효율적
+
+- 이동 윈도우 카운터 알고리즘.
+- 현재 1초간의 요청 수 + 직전 1초간의 요청 수 *이동 윈도와 직전 1초가 겹치는 비율
+- 짧은 시간에 몰리는 트래픽에도 잘 대응한다.
+- 직전 시간대에 도착한 요청이 균등하게 분포되어 있다고 가정한 상태에서, 추정치를 계산하기 때문에 느슨하다고 생각이 들지만, 시스템의 실제 상태와 맞지 않게 허용되거나 버려진 요청은 0.03%
+- 이동 윈도우 카운터 알고리즘이 낫다고 느낌. 대규모 시스템이므로, 토큰에서 발생할 수 있는 최대 ( 버킷 크기 + 토큰 공급률 ) 이 작다고 느껴질 수도 있지만, 이게 여럿이 모이면, 서버에 큰 부하가 될 수 도 있다고 생각함.
+
+### 여러 서버로 처리되는 경우에 따른 동시성 이슈
+
+- Redis 의 중앙 저장소를 만들고,
+- LuaScript 또는 Sorted Set 을 이용하여 해결
+
+---
+
+### 정말로 이게 최선인가 ?
+
+- Rate Limiter 에서 중요한 것은 무엇인가 ?
+- 실제로 정의한 그만큼만 들어오는 게 중요한 것인 가?
+- API Gateway 에서 정체 없이 빠르게 처리되는 게 더 중요한 것인가 ?
+- 도메인에 따라서 나뉘지 않을까 싶다.
+
+### Local + Global 2계층 — 정확히 어떻게 계산하나
+
+> 로컬은 "이 노드 한 대가 본 요청"만 안다. 글로벌은 "전 노드 합산"을 안다.
+로컬은 빠르지만 부분만 보고, 글로벌은 전체를 보지만 느리다. 2계층은 이 둘을 어떻게 조합하느냐의 문제다.
+>
+
+## 모델 A - "일단 Redis에 물어보되, 명백한 초과만 미리 쳐낸다"
+
+요청이 들어오면 노드는 먼저 **자기 로컬 카운트만** 본다. 여기서 내릴 수 있는 판단은 단 하나: *"나 이 노드 혼자서 이미 전체 한도(20)를 넘겼나?"*
+
+- 넘겼으면 → **즉시 거부**. Redis 안 간다.
+- 안 넘겼으면(정상 상황에선 거의 다 여기) → **Redis로 위임**.
+
+그리고 진짜 통과/거부 판정은 **항상 Redis가** 내린다. Redis는 전 노드가 올린 카운트를 합산한 값(슬라이딩 윈도우 추정 `est`)으로 최종 결정하니까 이게 **권위**다.
+
+→ 즉 로컬은 그냥 **거름망**이다. "누가 봐도 초과인 트래픽"만 걸러서 Redis를 보호할 뿐, 실제 판단은 안 한다. 그래서 **정확하지만(오버슈트 거의 0) 정상 부하에서도 거의 매 요청이 Redis를 친다** → RTT를 못 없앤다.
+
+```mermaid
+sequenceDiagram
+ participant C as 클라이언트
+ participant N as 노드 (로컬)
+ participant R as Redis (권위)
+
+ C->>N: 요청
+ Note over N: 로컬 카운트 확인
나 혼자 20건 이상?
+ alt 이미 한도 초과
+ N-->>C: 즉시 거부 (Redis 0회)
+ else 애매 — 정상 부하 대부분
+ N->>R: 합산 카운트 조회 + 판정 위임
+ Note over R: est = 전 노드 합산
최종 통과/거부 결정
+ R-->>N: allow / deny
+ N-->>C: 응답
+ end
+```
+
+> 정상 트래픽은 거의 다 아래 `else`로 빠져 **매번 Redis를 친다** → 이게 "느린 이유".
+>
+
+## 모델 B - "내 몫 안이면 Redis한테 안 물어본다"
+
+중앙이 한도 20을 노드들에게 **미리 쪼개서 나눠준다** (slice, 예: 3노드면 각자 6~7장).
+
+요청이 들어오면 노드는 **자기 slice가 남았는지만** 본다.
+
+- 남았으면 → **즉시 허용**. Redis 안 간다.
+- 다 썼으면 → 그때 Redis에 "내 몫 더 줘" 요청.
+
+노드들은 별도로 **주기적으로(100ms마다 등)** 자기가 처리한 수를 Redis에 보고하고, Redis는 그걸 합산해서 **남은 예산을 바쁜 노드에 재분배**한다.
+
+→ 핫패스에서 **Redis를 아예 안 친다** → 빠름. 대신 노드가 들고 있는 정보가 "살짝 과거"라 **오버슈트(한도 초과)가 생길 수 있다** (오버슈트 폭 ≈ 동기화 주기 × 노드 수). 그리고 LB가 불균등하면 한 노드만 slice 소진하고 나머진 노는 사태가 나서 → **동적 재분배가 필수**다.
+
+```mermaid
+sequenceDiagram
+ participant C as 클라이언트
+ participant N as 노드 (slice 보유)
+ participant R as Redis (예산 분배)
+
+ Note over C,N: 핫패스 — 요청마다
+ C->>N: 요청
+ Note over N: 내 slice 남았나?
+ alt slice 남음 (대부분)
+ N-->>C: 즉시 허용 (Redis 0회)
+ else slice 소진
+ N->>R: 내 몫 더 줘
+ R-->>N: 추가 slice
+ N-->>C: 응답
+ end
+
+ Note over N,R: 백그라운드 — 100ms 주기 (핫패스와 별개)
+ N->>R: 처리량 보고
+ R->>N: slice 재분배
+```
+
+> 핫패스(요청마다)에선 Redis 화살표가 거의 안 생기고, Redis 통신은 백그라운드로 분리된다 → "빠르지만 정보가 살짝 과거 → 오버슈트".
+>
+
+## 비유로 한 방에
+
+- **모델 A** = 매번 본사에 전화해서 승인받는 방식. 단, "이미 내 책상에 쌓인 게 한도 넘으면" 전화 안 하고 바로 반려. → 정확하지만 전화를 계속 함.
+- **모델 B** = 본사가 아침에 "넌 오늘 6건까지 OK" 쿠폰을 미리 나눠줌. 쿠폰 있으면 본사 안 물어보고 바로 처리, 떨어지면 그때 더 달라고 전화. 본사는 가끔 누가 많이 썼나 보고 쿠폰을 다시 분배. → 빠르지만 정보가 약간 늦어서 살짝 넘칠 수 있음.
+
+> **핵심 한 줄**: A는 Redis가 매번 답하니 정확하지만 느리고, B는 Redis를 가끔만 부르니 빠르지만 근사다.
+한도를 빡빡하게 지켜야 하면 A, 정상 부하 보호가 목적이면 B.
+>
+
+---
\ No newline at end of file
diff --git "a/005_\354\225\210\354\240\225\355\225\264\354\213\234/img.png" "b/005_\354\225\210\354\240\225\355\225\264\354\213\234/img.png"
new file mode 100644
index 0000000..a9b6f10
Binary files /dev/null and "b/005_\354\225\210\354\240\225\355\225\264\354\213\234/img.png" differ
diff --git "a/005_\354\225\210\354\240\225\355\225\264\354\213\234/\352\260\200\354\203\201\353\205\270\353\223\234_\354\233\220\353\246\254.html" "b/005_\354\225\210\354\240\225\355\225\264\354\213\234/\352\260\200\354\203\201\353\205\270\353\223\234_\354\233\220\353\246\254.html"
new file mode 100644
index 0000000..7e83efc
--- /dev/null
+++ "b/005_\354\225\210\354\240\225\355\225\264\354\213\234/\352\260\200\354\203\201\353\205\270\353\223\234_\354\233\220\353\246\254.html"
@@ -0,0 +1,665 @@
+
+
+
안정 해시의 "쏠림 문제"를 가상 노드가 어떻게 해결하는지 눈으로 확인해봐요
+먼저 결론부터 기억하고 시작해요.
+서버 하나를 해시 링 위에 한 점으로 놓는 대신, + 여러 개의 "가짜 점"(가상 노드)으로 쪼개서 링 곳곳에 흩뿌리면 + 데이터가 서버들에게 훨씬 골고루 나뉜다.
+왜 그게 필요한지, 아래에서 하나씩 볼게요. 👇
+가상 노드를 이해하려면 "해시 링"부터 알아야 해요.
+서버와 데이터(키)를 모두 같은 해시 함수에 넣어서, 그 결과값을 + 동그란 링(0 → 최대값 → 다시 0) 위의 한 지점에 배치해요.
+링을 시계라고 생각하세요. 서버 A는 3시, 서버 B는 7시 위치에 붙어 있어요. + 데이터 키를 링에 놓은 뒤, 시계 방향으로 돌면서 처음 만나는 서버가 그 데이터를 담당해요.
+이 방식의 장점은 서버를 추가/삭제해도 대부분의 키가 그대로 유지된다는 것.
+ (일반 해시 hash % N 방식은 서버 수 N이 바뀌면 거의 모든 키가 재배치돼요.)
서버를 링 위에 "딱 한 점"씩만 놓으면 생기는 일.
+해시 함수는 서버를 링 위 랜덤한 위치에 떨어뜨려요. + 운이 나쁘면 서버들이 한쪽에 몰리고, 그 사이 구간이 제각각이 됩니다.
+ ++ 🔴 S1이 담당하는 구간(호)이 유독 넓죠? → + S1에 데이터·트래픽이 몰림 = 핫스팟 +
+ +한 서버에만 부하가 쏠리면 그 서버가 먼저 뻗어요. + 게다가 서버가 죽거나 추가될 때 담당 구간 크기가 들쭉날쭉이라 + 재배치되는 데이터 양도 예측이 안 됩니다.
+아래 슬라이더를 움직여서 직접 확인해보세요. 이게 이 페이지의 핵심이에요!
+ +서버 S1을 링에 1점만 놓는 대신,
+ S1#0, S1#1, S1#2 ... 처럼 이름을 바꿔가며 해시해서
+ 여러 점(가상 노드)으로 링 곳곳에 흩뿌려요.
+ 이 점들은 전부 실제로는 같은 서버 S1을 가리켜요.
1 → 200으로 올려보세요. 각 서버의 점이 많아져 링에 골고루 박히면서 아래 막대가 평평해지는 걸 보세요.
+ +노드 3대 → 4대로 늘릴 때 세 방식을 나란히 비교해요. 님이 헷갈린 바로 그 지점이에요.
+ +지금은 노드 3대 상태예요. 버튼을 누르면 4대가 되고, 이사한 키가 빨갛게 튀어나와요. 각 칸의 24개 키가 어느 노드로 가는지 색으로 표시돼요.
+ + + +hash % N은 거의 다 이사(빨강 폭탄 💥) — 순진한 방식.
+ 해시 슬롯과 안정 해시는 딱 1/4만 이사예요.
+ 슬롯 ≈ 가상 노드라서 이 둘의 결과가 비슷하게 나오는 게 핵심 포인트!
가상 노드가 있어도 "찾는 방법"은 똑같이 단순해요.
+데이터 키 "user_1234"를 해시 함수에 넣어 링 위 한 지점을 구해요.
+그 지점에서 시계 방향으로 이동하며 처음 만나는 점(가상 노드)을 찾아요.
+만난 점이 S3#7이라면? "#7"은 무시하고 실제 서버 S3가 담당해요.
즉, 가상 노드는 "링 위에서만 존재하는 라벨"일 뿐, + 실제 서버 대수가 늘어난 게 아니에요. 서버 3대는 그대로 3대예요.
+| 항목 | 가상 노드 없음 (서버당 1점) | 가상 노드 있음 (서버당 여러 점) |
|---|---|---|
| 데이터 분포 | 들쭉날쭉 (쏠림 위험) | 골고루 균등 |
| 서버 추가/삭제 시 | 재배치량 예측 어려움 | 부드럽고 균등하게 이동 |
| 핫스팟 | 잘 생김 | 잘 안 생김 |
| 메모리·관리 비용 | 적음 | 점이 많아질수록 증가 |
가상 노드가 많을수록 분포는 균등해지지만, 링에서 관리할 점이 많아져 + 메모리와 탐색 비용이 늘어요. 그래서 무한정 늘리지 않고 + 실무에선 보통 서버당 100~200개 수준을 씁니다.
+