Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
## 2차 설계 보완
> 설정된 처리율을 초과하는 요청은 정확하게 제한한다.
> 낮은 응답시간: 이 처리율 제한 장치는 HTTP 응답시간에 나쁜 영향을 주어서는 곤란하다.
> 가능한 한 적은 메모리를 써야 한다.
> 분산형 처리율 제한: 하나의 처리율 제한 장치를 여러 서버나 프로세스에서 공유할 수 있어야 한다.
> 예외 처리: 요청이 제한되었을 대는 그 사실을 사용자에게 분명하게 보여주어야 한다.
> 높은 결함 내성: 제한 장치에 장애가 생기더라도 전체 시스템에 영향을 주어서는 안 된다.

### 요청 제한에 대해 사용자에게 가시적으로 안내
- X-Ratelimit-Remaining: 윈도우 내 잔여 요청 수
- X-Ratelimit-limit: 매 윈도우 마다 클라이언트가 전송할 수 있는 요청의 수
- X-Ratelimit-Retry-After: 한도 제한에 걸리지 않으려면 몇 초 뒤에 요청을 다시 보내야 하는지 알림
### 슬라이딩 윈도우
가정: 제한이 Limit 1분

기존: 요청을 수집하여 현재 요청이 들어오는 시점 기준으로 1분 내 토큰의 수를 카운팅하여 요청의 허용 여부를 결정
책에서 제한 하는 방법: 1분이라는 슬롯 기준으로 현재 슬롯의 요청횟수와 직전 슬롯의 요청 횟수를 비율로 계산하여 횟수를 결정
1분의 1/2이지난(1:30 시점)에서는 직전 1분의 뒤에 30초 내 요청수 * 0.5 + 현재 요청수 * 0.5로 하여 비율 계산

### 높은 결함 내성
MSA 환경에서 rate limiter의 장애로 다른 모든 API에 대한 Rate Limit이 동작하지 않으면 안되기 때문에 middle ware로 api서버 별로 앞단에 위치시키는 것이 적합해보인다

### 분산형 처리율 제한
in-memory DB를 활용하여 하나의 DB를 rate limiter 들이 공유하여 사용하게하면 MSA 환경에서 Scale Out 시에도 문제 없음

## Sequence Diagram
```mermaid
sequenceDiagram
participant C as Client
participant GW as Gateway
participant RL as rate-limiter
participant MEM as In-Memory DB (공유)
participant Q as Queue
participant W as worker
participant DB as Database

C->>GW: API 요청 (api-key)
GW->>RL: rate-limit 체크 요청 (api-key)
RL->>MEM: 현재 슬롯 카운트 + 직전 슬롯 카운트 조회

alt limit(timeout) 내 응답
MEM-->>RL: count_cur(현재 슬롯), count_prev(직전 슬롯)
Note over RL: 슬라이딩 윈도우 계산<br/>weight = 슬롯 경과시간 / 윈도우 길이 (예: 30s/60s = 0.5)<br/>count = count_prev × (1-weight) + count_cur × weight
alt count ≥ limit
RL-->>GW: 거부 (deny)
GW-->>C: 429 Too Many Requests<br/>X-Ratelimit-Limit, X-Ratelimit-Remaining: 0<br/>X-Ratelimit-Retry-After
else count < limit
RL->>MEM: 현재 슬롯 +1 (key + TTL)
RL-)Q: 카운트 증가 이벤트 발행 (비동기)
RL-->>GW: 허용 (allow)
GW-->>C: 200 OK<br/>X-Ratelimit-Limit, X-Ratelimit-Remaining, X-Ratelimit-Retry-After
end
else timeout · In-Memory DB 무응답
RL-->>GW: 장애 내성 - 허용 (allow, fail-open)
GW-->>C: 200 OK (헤더는 마지막 알려진 값 또는 생략)
end

Note over Q,DB: 비동기 영속화 (요청 흐름과 분리되어 지연이 없음)
Q->>W: 카운트 이벤트 소비
W->>DB: 카운트 영속화

Note over RL,MEM: 분산 처리율 제한: 모든 rate-limiter 인스턴스가<br/>동일한 In-Memory DB(예: Redis)를 공유 → API 서버 Scale-out 시에도 카운트 일관성 유지

Note over GW,RL: 높은 결함 내성: rate-limiter를 각 API 서버 앞단의<br/>미들웨어로 배치 → 한 limiter 장애가 다른 API의 제한 로직에 영향 주지 않음
```

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@

## 요구사항
> 설정된 처리율을 초과하는 요청은 정확하게 제한한다.
> 낮은 응답시간: 이 처리율 제한 장치는 HTTP 응답시간에 나쁜 영향을 주어서는 곤란하다.
> 가능한 한 적은 메모리를 써야 한다.
> 분산형 처리율 제한: 하나의 처리율 제한 장치를 여러 서버나 프로세스에서 공유할 수 있어야 한다.
> 예외 처리: 요청이 제한되었을 대는 그 사실을 사용자에게 분명하게 보여주어야 한다.
> 높은 결함 내성: 제한 장치에 장애가 생기더라도 전체 시스템에 영향을 주어서는 안 된다.

## 설계
![아키텍처.png](https://github.com/Kimchuljoong/system-design-study/blob/main/04-%E1%84%8E%E1%85%A5%E1%84%85%E1%85%B5%E1%84%8B%E1%85%B2%E1%86%AF_%E1%84%8C%E1%85%A6%E1%84%92%E1%85%A1%E1%86%AB_%E1%84%8C%E1%85%A1%E1%86%BC%E1%84%8E%E1%85%B5%E1%84%8B%E1%85%B4_%E1%84%89%E1%85%A5%E1%86%AF%E1%84%80%E1%85%A8/%E1%84%8B%E1%85%A1%E1%84%8F%E1%85%B5%E1%84%90%E1%85%A6%E1%86%A8%E1%84%8E%E1%85%A5.png?raw=true)

## Sequence Diagram
```mermaid
sequenceDiagram
participant GW as Gateway
participant RL as rate-limiter
participant MEM as In-Memory DB
participant Q as Queue
participant W as worker
participant DB as Database

GW->>RL: rate-limit 체크 요청 (api-key)
RL->>MEM: api-key 버킷 카운트 조회

alt limit(timeout) 내 응답
MEM-->>RL: 현재 카운트 반환
alt 카운트 ≥ 임계치
RL-->>GW: 불가능 (deny)
else 카운트 < 임계치
RL->>MEM: 버킷 +1 (고유값 + TTL)
RL-)Q: 카운트 증가 이벤트 발행 (비동기)
RL-->>GW: 가능 (allow)
end
else timeout · In-Memory DB 무응답
RL-->>GW: 장애 내성 - 가능 (allow)
end

Note over Q,DB: 이후 비동기 영속화 (요청 흐름과 분리)
Q->>W: 카운트 이벤트 소비
W->>DB: 카운트 영속화
```

## 설계 이유
- in-memory 사용으로 접근 속도 보장
- message queue를 활용하여 사용자의 접근 결과를 비동기적으로 영속화
- gateway에서 rate-limiter에 요청과 응답 사이에 요청 대기 시간 제한으로 서비스에 영향 최소화(rate-limiter 실패 시에는 원래 api 그대로 호출 서비스 가용성 보장)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.