Skip to content

Commit 373d4a1

Browse files
authored
4장 김현준
1 parent f999112 commit 373d4a1

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed

week2(4장)/김현준.md

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# 4장 처리율 제한 장치 설계
2+
- 네트워크 시스템에서 트래픽 처리율을 제어하기 위한 장치 설계
3+
- API 요청 횟수가 제한 장치에 정의된 임계치(threshold)를 넘어서면 추가로 도달한 모든 호출은 중단
4+
5+
## 1. 문제 이해 및 설계 범위 확정
6+
7+
- 면접관과 소통하며 요구사항을 도출해내는 것이 중요 !
8+
- 설정된 처리율을 초과하는 요청은 정확하게 제한
9+
- 낮은 응답시간
10+
- 적은 메모리 사용
11+
- 분산형 처리율 제한: 여러 서버, 프로세스가 하나의 처리율 제한 장치를 공유
12+
- 예외 처리: 제한 시 사용자에게 보여주어야 함
13+
- 장애 발생 시 전체 시스템 영향 X
14+
15+
## 2. 개략적 설계안
16+
17+
### 처리율 제한 장치의 위치
18+
19+
- 클라이언트
20+
- 요청이 쉽게 위변조가 가능하므로 적절하지 X
21+
- 미들웨어
22+
- API 서버로 가는 요청을 통제
23+
- 429 반환
24+
- 클라우드 마이크로서비스의 경우 API 게이트웨이 컴포넌트로 구현
25+
26+
### 처리율 제한 알고리즘
27+
28+
- 토큰 버킷
29+
- 컨테이너를 만들어서 요청이 처리될 때마다 하나의 토큰 사용
30+
- 충분한 토큰이 있으면 토큰을 꺼낸 후 요청을 시스템에 전달
31+
- 없으면 요청을 버림
32+
- 토큰 공급률에 따라 토큰을 채운다.
33+
- 버킷 크기에 따라 최대 개수가 제한된다.
34+
- 보통 API 엔드포인트마다 별도의 버킷을 둔다.
35+
- 누출 버킷 알고리즘
36+
- 요청 처리율이 고정되어 있음.
37+
- FIFO 큐로 구현한다.
38+
- 요청이 도착하면 큐가 가득 차 있는지 본다.
39+
- 빈자리가 있는 경우 큐에 요청을 추가한다.
40+
- 큐가 가득 차 있는 경유에는 새 요청은 버린다.
41+
- 지정된 시간마다 큐에서 요청을 꺼내어 처리한다.
42+
- 버킷 크기와 처리율(지정된 시간당 몇 개의 항목을 처리할지) 인자로 사용
43+
- 고정 윈도 카운터
44+
- 타임라인을 고정된 간격의 윈도로 나누고, 각 윈도마다 카운터를 붙인다.
45+
- 요청이 접수되면 카운터 값을 증가한다.
46+
- 카운터 값이 임계치에 도달하면 새로운 요청은 새 윈도가 열릴 때까지 버려진다.
47+
- 경계 부근에 순간적으로 많은 트래픽이 집중될 경우 더 많은 요청이 처리될 수 있음
48+
- 윈도 경계 부근에 많은 트래픽이 집중되면 일반 처리율보다 더 높아짐
49+
- 이동 윈도 로깅 알고리즘
50+
- 고정 윈도 카운터 알고리즘의 경계 부근 트래픽 문제로 인해 나온 알고리즘
51+
- 요청 타임스탬프를 추적한다.
52+
- 새 요청이 오면 만료된 타임스탬프는 제거한다.
53+
- 만료된 스탬프는 그 값이 현재 윈도의 시작 시점보다 오래된 타임스탬프를 말한다.
54+
- 새 요청의 타임스탬프를 로그에 추가한다.
55+
- 로그의 크기가 허용치보다 같거나 작으면 요청을 시스템에 전달한다. 그렇지 않으면 처리를 거부한다.
56+
- 단점은 로그를 저장해야 하기 때문에 다량의 메모리를 사용한다.
57+
- 이동 윈도 카운터 알고리즘
58+
- 고정 윈도 카운터 알고리즘 + 이동윈도 로깅 알고리즘
59+
- 이전 시간대의 평균 처리율에 따라 현재 윈도의 상태를 계산하므로 짧은 시간에 몰리는 트래픽에도 잘 대응한다.
60+
- 메모리 효율이 좋다.
61+
- 직전 시간대에 도착한 요청이 균등하게 분포되어 있다고 가정한 상태에서 추정치를 계산하기 때문에 다소 느슨하다.
62+
- 0.003%정도의 오차율을 가진다.
63+
64+
### 개략적인 아키텍처
65+
66+
- 카운터를 보관할 아키텍처 선정
67+
- 데이터베이스는 디스크 접근 때문에 적절 X
68+
- 메모리상에서 동작하는 캐시가 바람직
69+
- 빠르고 시간에 기반한 만료 정책을 지원
70+
- 클라이언트에 처리율 제한 미들웨어에 요청
71+
- 미들웨어는 레디스의 지정 버킷에서 카운터를 가져와서 한도에 도달했는지 아닌지 검사
72+
- 한도에 도달했다면 요청 거부
73+
- 도달하지 않았다면 API 서버로 전달 및 카운터 값 증가
74+
75+
## 3. 상세 설계
76+
77+
- 처리율 제한 규칙
78+
- 처리율 한도 초과 트래픽 처리
79+
- 429 응답
80+
- 메시지를 큐에 보관 후 나중에 처리
81+
- HTTP 응답 헤더로 클라이언트에게 고지 가능
82+
- X-Ratelimit-Remaining: 윈도 내에 남은 처리 가능 요청의 수
83+
- X-Ratelimit-Limie: 매 윈도마다 클라이언트가 전송할 수 있는 요청의 수.
84+
- X-Ratelimit-Retry-After: 한도 제한에 걸리지 않으려면 몇 초 뒤에 요청을 다시 보내야 하는지 알림
85+
86+
### 분산 환경에서의 처리율 제한 장치 구현
87+
88+
- Race Condition
89+
- 카운터 값에 대해 동시성 이슈 제어가 필요
90+
- Lock으로 해결 가능 → 그러나 시스템 성능이 떨어짐
91+
- Lua Script or Sorted set으로 해결 가능
92+
- Synchronization
93+
- 여러 대의 제한 장치를 뒀을 때 어떻게 처리율 제한 장치를 동기화할 것 인지?
94+
- Sticky Session을 이용할 수 있음
95+
- 같은 장치로 보낼 수 있도록 하는 것
96+
- 같은 장치로 계속 보내야하기 때문에 확장성에 있어서 유연하지 않음
97+
- 레디스를 중앙 집중형 데이터 저장소로 쓸 수 있음
98+
99+
### 성능 최적화
100+
101+
- 여러 데이터센터를 지원해 사용자의 트래픽을 가장 가까운 에지 서버로 전달
102+
- 최종 일관성 모델 채택
103+
104+
## 4. 마무리
105+
106+
- hard, soft 처리율 제한
107+
- hard: 요청의 개수는 임계치를 넘을 수 없다.
108+
- soft: 요청의 개수는 잠시동안 임계치를 넘어설 수 있다.
109+
- 다양한 계층에서의 처리율 제한
110+
- 7계층인 애플리케이션 뿐만 아니라 Iptables를 사용해도 적용 가능(3계층)
111+
- 회피 방법
112+
- 클라이언트 캐시를 통해 API 호출 줄임
113+
- 재시도 로직은 충분한 백오프 시간을 둔다. 등등
114+
115+
## 알아 볼 점
116+
117+
### 왜 Sorted Set, Lua Script은 Race Condition으로 부터 자유로울까?
118+
119+
Redis의 Sorted Set CAS 연산을 지원하기 때문에 레이스 컨디션 없이 데이터 추가 및 업데이트 가능
120+
121+
- CAS의 동작 원리
122+
1. **메모리 위치(address)**: 업데이트하려는 데이터가 저장된 메모리 위치.
123+
2. **기대 값(expected value)**: 업데이트하기 전, 현재 데이터가 이 값과 일치하는지 확인.
124+
3. **새로운 값(new value)**: 기대 값이 일치하면 이 값으로 데이터 업데이트.
125+
126+
**CAS 동작 프로세스**:
127+
128+
1. 특정 메모리 위치의 값이 기대 값과 같은지 확인.
129+
2. 같으면, 해당 값을 새로운 값으로 교체.
130+
3. 다르면, 아무 작업도 수행하지 않고 실패를 반환.
131+
- CAS의 특징
132+
- 비교 후 교체: 기대 값과 메모리 값이 일치하지 않으면 데이터 업데이트를 수행하지 않음.
133+
- 원자성 보장: 모든 CAS 연산은 한 번에 수행되어 중간 상태가 발생하지 않음.
134+
- 락-프리(lock-free): CAS는 잠금 없이 데이터 업데이트를 수행하므로, 성능이 뛰어나고 데드락을 방지할 수 있음.
135+
- CAS 문제점
136+
- Spin Lock
137+
- CAS가 계속 실패하면 CPU 리소스를 낭비할 수 있음.
138+
- 해결 방법: 지수 백오프(Exponential Backoff) 사용.
139+
- ABA 문제
140+
- 메모리 값이 A였다가 B로 바뀌고, 다시 A로 돌아오면 CAS는 이를 감지하지 못함.
141+
- 즉, A→B→A로 바꾸고 A→B로 바꾸면 중간 A→B→A로 바뀐 변경을 감지하지 못함.
142+
- 해결 방법: 버전 번호 추가.
143+
- Lua도 원자적으로 처리
144+
- 그러나 둘 다 단일 인스턴스 기준이기 때문에 다중마스터(클러스터 환경)에서는 다른 전략이 필요함
145+
- 데이터 샤딩으로 한 인스턴스에서만 다루기
146+
- 메시징 큐 이용 등등
147+
148+
### Iptables를 통한 처리율 제한 방법
149+
150+
- Iptables은 리눅스 커널의 네트워크 패킷 필터링 기능을 제어하는 도구
151+
- 넷필터는 IP 패킷을 검사, 수정, 드롭 또는 전달하는 기능을 제공하는데 이 규칙을 설정하고 관리하는 사용자 공간 도구를 Iptables라고 한다.
152+
- 네트워크 스택의 3계층에서 동작
153+
- 네트워크 카드에서 패킷을 받아 사용자 공간으로 전달되기 전에 처리
154+
- IP 주소와 프로토콜 기반으로 작동
155+
- 4계층(TCP/UDP)과의 연결도 제어 가능
156+
- Netfilter 패킷 처리 흐름
157+
- 네트워크 인터페이스로 들어오거나 나갈 때 5개의 체인을 통해 패킷을 처리함
158+
1. PREROUTING
159+
- 패킷이 네트워크 인터페이스로 들어오자마자 처리
160+
- 패킷의 목적지 변경 및 수정
161+
2. INPUT
162+
- 패킷이 로컬 호스트로 들어오는 경우 처리
163+
- 로컬 시스템에서 처리될 트래픽을 필터링
164+
3. FORWARD
165+
- 로컬 호스트가 아닌 다른 네트워크로 전달되는 패킷 처리
166+
- 라우터 역할을 수행하는 경우 해당 체인을 거침
167+
4. OUTPUT
168+
- 로컬 호스트에서 생성된 패킷을 처리
169+
- 외부로 나가는 패킷을 제어
170+
5. POSTROUTING
171+
- 패킷이 네트워크 인터페이스로 나가기 직전에 처리
172+
- 출발지 주소 변환
173+
174+
**동작 과정 요약**
175+
176+
1. **패킷이 들어옴** → PREROUTING.
177+
2. **로컬 호스트로 가는지 확인**:
178+
- 로컬로 간다면 → INPUT.
179+
- 라우터를 거친다면 → FORWARD.
180+
3. **패킷이 로컬에서 생성됨** → OUTPUT.
181+
4. **패킷이 나감** → POSTROUTING.
182+
183+
1. 처리율 제한을 위한 `limit` 모듈
184+
185+
**특징**
186+
187+
- 단일 규칙의 처리율을 제한합니다.
188+
- 지정된 초당 요청 수를 초과하면 나머지 트래픽을 차단하거나 다른 규칙으로 이동시킵니다.
189+
- ICMP 핑을 이용한 패킷 제한, SSH 연결 속도 제한 등
190+
191+
2. IP별 처리율 제한을 위한 `hashlimit` 모듈
192+
193+
**특징**
194+
195+
- 요청을 보내는 IP 주소별로 개별적으로 처리율을 제한.
196+
- 악의적인 트래픽을 생성하는 IP를 제어하는 데 유용.

0 commit comments

Comments
 (0)