TIL - 20261005

juni·2일 전

TIL

목록 보기
471/473

1005 운영 자동화/AI 워크플로우 심화 (29/N): Rate Limiting, Quota, Backpressure와 Load Shedding


✅ 1. 시스템이 느려질 때 가장 위험한 대응은 ‘모든 요청을 끝까지 받아주는 것’이다

정상 상태에서는:

Request
↓
NestJS
↓
DB
↓
Response

가 잘 동작한다.

하지만 갑자기 요청이 폭증하면:

Request 100
↓
DB Query 100

정도가 아니라:

Request 10,000

↓

Connection Pool 대기

↓

DB Latency 증가

↓

API Timeout

↓

Client Retry

↓

요청 더 증가

하는 악순환이 생길 수 있다.


✅ 2. 과부하 상황에서는 일부 요청을 거절하는 것이 전체 시스템에는 더 안전할 수 있다

예:

10,000 요청 모두 받기
→ 전체 서비스 장애

보다:

중요 요청 1,000개 처리

불필요 요청 일부 제한

이 더 나을 수 있다.

이게 이번 내용의 핵심이다.


✅ 3. Rate Limiting이란?

특정 시간 동안 허용하는 요청 수를 제한하는 것이다.

예:

1분 동안
100 requests

이상 들어오면 추가 요청을 제한한다.


✅ 4. Rate Limit은 공격 방어만을 위한 것이 아니다

흔히:

DDoS
Bot
Abuse

만 생각하지만 실제 운영에서는:

실수로 무한 API 호출

Frontend Retry Loop

Webhook 재전송 폭주

잘못된 자동화

대량 Excel 요청

AI Tool Loop

같은 정상 기능의 Bug도 Rate Limit으로 피해를 줄일 수 있다.


✅ 5. 현재 프로젝트에서 실제로 보호 가치가 높은 영역

예:

로그인

검색 API

주문 조회

신청 API

Excel Export

알림톡 재발송

AI 분석 API

Webhook Endpoint

관리자 Bulk Action

등이다.


✅ 6. 모든 Endpoint에 같은 제한을 두면 안 된다

예:

상품 조회

는 초당 많은 요청이 가능해도 괜찮을 수 있다.

반면:

알림톡 재발송

은 1초에 수십 번 실행되면 큰 문제가 된다.


✅ 7. 그래서 Rate Limit은 업무 단위로 나눈다

예:

Public Read API
높은 Limit

Authentication
낮은 Limit

Export
매우 낮은 Limit

Notification Resend
매우 낮은 Limit

AI Tool Action
별도 Budget

이다.


✅ 8. Rate Limit의 기본 구성

보통 다음이 필요하다.

누구를 기준으로 제한할 것인가?

몇 번까지 허용할 것인가?

어떤 시간 단위인가?

초과하면 어떻게 할 것인가?

✅ 9. Key 기준

예:

IP

User ID

Admin ID

API Key

Session

Order ID

Tenant

Webhook Provider

를 사용할 수 있다.


✅ 10. IP Rate Limit

예:

IP A
1분 100회

같은 방식이다.

Public API에서는 유용하다.


✅ 11. IP만 사용하면 문제가 있을 수 있다

회사나 통신망에서 여러 사용자가 같은 공인 IP를 공유할 수 있다.

그러면 정상 사용자끼리 Limit을 공유하게 된다.


✅ 12. 로그인 이후에는 User ID 기준이 더 정확할 수 있다

예:

user:{userId}

기준으로 요청 횟수를 관리한다.


✅ 13. 관리자 기능은 Admin ID 기준도 좋다

예:

admin:{id}:export

처럼 한다.

한 관리자가 Excel 버튼을 계속 눌러도 시스템 전체에 영향을 덜 준다.


✅ 14. IP + User 조합도 가능하다

예:

user:{id}:ip:{ip}

다만 Key가 너무 복잡해지지 않도록 한다.


✅ 15. Rate Limit과 Quota는 다르다

Rate Limit:

짧은 시간 동안 얼마나 빨리 사용할 수 있는가?

Quota:

전체 기간 동안 얼마나 많이 사용할 수 있는가?

이다.


✅ 16. 예

Rate Limit:

1분
10회

Quota:

하루
1,000회

이다.


✅ 17. AI API에서는 둘 다 중요하다

예:

분당 10회

하루 500회

월 Token 1M

같이 관리할 수 있다.


✅ 18. 개인 Local LLM에서도 Budget 개념은 필요하다

돈이 나가지는 않더라도:

CPU

RAM

실행 시간

동시 모델 Run

은 제한된 Resource다.


✅ 19. AI Workflow Budget

예:

maxToolCalls = 30

maxFixAttempts = 3

maxDuration = 20m

maxConcurrentRuns = 1

정도로 둘 수 있다.


✅ 20. Rate Limiting Algorithm

대표적으로:

Fixed Window

Sliding Window

Token Bucket

Leaky Bucket

등이 있다.

모든 걸 직접 구현할 필요는 없지만 개념은 알아두면 좋다.


✅ 21. Fixed Window

예:

18:00:00 ~ 18:00:59
100회

허용한다.

다음 분이 되면 Counter를 초기화한다.


✅ 22. Fixed Window의 문제

예:

18:00:59
100회

18:01:00
100회

가 들어오면 실제 1초 사이에 200회가 들어올 수 있다.


✅ 23. Sliding Window

현재 시점 기준으로 최근 일정 기간 요청을 본다.

예:

지금 기준
최근 60초
100회

이다.

더 정확하지만 구현 비용이 증가한다.


✅ 24. Token Bucket

Bucket에 Token이 일정 속도로 충전된다.

요청 하나가 Token 하나를 소비한다.


✅ 25. 예

Bucket Size
100

Refill
초당 10 Token

이면 잠깐 100개 Burst는 허용하면서 장기적으로 초당 10개 수준을 유지할 수 있다.


✅ 26. Burst가 있는 실제 Web 서비스에 Token Bucket이 실용적이다

사용자가 페이지를 열면 동시에:

상품 조회

FAQ

카테고리

추천

배너

등 여러 요청이 나갈 수 있다.

너무 엄격한 초당 Limit은 정상 동작도 막을 수 있다.


✅ 27. 그래서 Burst Allowance가 중요하다

예:

평균
10 req/s

Burst
30

정도로 허용한다.


✅ 28. Leaky Bucket

요청이 Bucket에 쌓이고 일정 속도로 처리된다.

즉:

입력 Burst

↓

Queue

↓

일정한 처리 속도

로 만든다.


✅ 29. Queue Worker 처리량 제어와 비슷하다

특히:

알림톡

외부 API

AI 작업

에서 유용한 사고방식이다.


✅ 30. HTTP Rate Limit과 Queue Rate Limit은 다르다

HTTP:

요청 자체를 얼마나 받을 것인가?

Queue:

쌓인 Job을 얼마나 빠르게 처리할 것인가?

이다.

둘 다 필요할 수 있다.


✅ 31. Export 예

관리자가:

Excel Export 100개

를 연속 클릭했다고 하자.

API 자체에서:

Export Request
분당 5개

를 제한할 수 있다.


✅ 32. Queue에도 추가 제한

Export Worker
concurrency = 2

로 둔다.

즉:

API Rate Limit
+
Worker Concurrency Limit

두 단계가 있다.


✅ 33. 외부 Provider Rate Limit도 고려해야 한다

예:

알림톡 Provider
초당 N건

제한이 있다면 Worker가 무제한 호출해서는 안 된다.


✅ 34. 우리 내부 Limit은 Provider Limit보다 보수적으로 잡을 수 있다

Provider가:

100 req/s

를 허용하더라도:

80 req/s

정도로 운영할 수 있다.

여유를 남긴다.


✅ 35. 429 Too Many Requests

HTTP Rate Limit을 초과하면 일반적으로:

429

응답을 사용할 수 있다.


✅ 36. Client에게 Retry 힌트 제공

예:

Retry-After

를 제공할 수 있다.


✅ 37. Frontend는 429를 일반 Error와 다르게 처리할 수 있다

예:

요청이 많습니다.
잠시 후 다시 시도해주세요.

처럼 보여준다.


✅ 38. 자동화 Client는 Retry-After를 지켜야 한다

나쁜 Retry:

429
↓
즉시 Retry
↓
429
↓
즉시 Retry

이다.


✅ 39. 이건 Retry Storm을 만든다

그래서:

Backoff
+
Jitter
+
Retry-After

를 함께 사용한다.


✅ 40. Rate Limit에서 중요한 것은 제한 숫자보다 Retry Behavior다

Server가 제한해도 Client가 계속 즉시 재시도하면 부하는 줄지 않는다.


✅ 41. Retry Budget

예:

한 Request
최대 3회 Retry

정도로 제한한다.


✅ 42. Global Retry Budget

더 강하게는 서비스 전체의 Retry 비율을 제한할 수 있다.

예:

전체 요청의
10% 이상 Retry 금지

같은 사고방식이다.


✅ 43. Backpressure란?

하류 시스템이 감당할 수 없는 속도로 일이 들어올 때:

상류 시스템에 속도를 줄이라는 신호를 주는 것

이다.


✅ 44. 예

API
초당 1,000 Job 생성

↓

Worker
초당 100 Job 처리

이면 Queue는 계속 쌓인다.


✅ 45. 1초마다 900 Job씩 밀린다

10분이면:

540,000 Job

이 쌓일 수 있다.


✅ 46. Queue가 있다는 것은 무한히 받아도 된다는 뜻이 아니다

Queue는 Burst를 흡수해 주지만 무한 Buffer가 아니다.


✅ 47. Backpressure가 없으면

Queue Depth 증가

↓

Job Latency 증가

↓

메모리/Redis 증가

↓

Retry 증가

↓

DLQ 증가

한다.


✅ 48. Queue Depth를 시스템 상태로 본다

예:

0~100
정상

100~1,000
주의

1,000+
과부하

처럼 볼 수 있다.

정확한 숫자는 실제 처리량에 맞춘다.


✅ 49. Queue Age도 중요하다

Depth가 100이라도:

Oldest Job
30분

이면 심각할 수 있다.


✅ 50. 반대로 Depth가 10,000이어도

Worker가 초당 5,000개를 처리한다면 큰 문제가 아닐 수 있다.

그래서:

Depth

+

Oldest Job Age

+

Processing Rate

를 같이 본다.


✅ 51. Queue Lag

예:

job.createdAt
→
job.startedAt

까지 걸린 시간이다.


✅ 52. Queue Lag SLO

예:

Notification
95% 10초 이내

AI Report
30분 이내

처럼 업무별로 다르다.


✅ 53. Backpressure 전략 1: Producer 제한

Queue가 너무 많이 쌓이면 새 Job 생성을 제한한다.

예:

queueDepth > threshold
→ Export 요청 거절

한다.


✅ 54. Export 같은 비핵심 기능에 효과적이다

예:

현재 Export 요청이 많습니다.
잠시 후 다시 시도해주세요.

로 처리한다.


✅ 55. 주문 생성까지 무조건 거절하는 것은 위험하다

핵심 업무는 다른 방식이 필요하다.


✅ 56. 중요도별 처리

예:

Order
CRITICAL

Notification
HIGH

Export
NORMAL

AI Report
LOW

로 나눈다.


✅ 57. Load Shedding

시스템이 과부하일 때 중요도가 낮은 기능부터 의도적으로 거절/중단하는 것이다.


✅ 58. 예

정상 상태:

주문
검색
추천
통계
AI 분석

전부 동작.

과부하:

주문
정상

검색
제한

추천
OFF

AI 분석
OFF

처럼 운영한다.


✅ 59. 이게 Graceful Degradation과 연결된다

핵심 기능은 살리고 부가 기능을 줄인다.


✅ 60. Load Shedding은 장애가 아니라 보호 기능이다

일부 기능을 제한함으로써 전체 서비스가 죽는 것을 막는다.


✅ 61. 현재 투게더몰에서 우선순위를 나눈다면

대략:

P0
주문 신청

P0
관리자 주문 처리

P1
고객 안내

P1
상품 조회

P2
Excel Export

P2
통계

P3
AI 분석

P3
추천

처럼 볼 수 있다.

실제 업무 중요도에 맞게 조정한다.


✅ 62. 과부하 시 가장 먼저 끌 후보

예:

AI Insight

관리자 무거운 Report

대량 Export

추천 기능

이다.


✅ 63. Kill Switch와 연결

0928에서 만든 Feature Flag를 사용해:

ai_analysis_enabled=false

같이 빠르게 끌 수 있다.


✅ 64. 자동 Load Shedding도 가능하다

예:

DB CPU > 90%

↓

AI 분석 요청 거절

같은 정책이다.


✅ 65. 하지만 초기에 완전 자동화는 조심한다

Metric 순간 Spike 하나로 기능이 계속 켜졌다 꺼질 수 있다.


✅ 66. Hysteresis가 필요할 수 있다

예:

90% 이상 5분
→ OFF

70% 이하 10분
→ ON

처럼 복구 기준을 다르게 둔다.


✅ 67. 현재는 Manual Kill Switch + Alert부터 시작하는 것이 현실적

자동 Shedding은 나중에 적용한다.


✅ 68. Concurrency Limit

동시에 몇 개 작업까지 실행할지 제한한다.

예:

Export Worker
2

AI Worker
1

Notification Worker
10

이다.


✅ 69. Concurrency는 Rate와 다르다

Rate:

초당 몇 건 시작?

Concurrency:

동시에 몇 건 실행?

이다.


✅ 70. 예

한 Job이 30초 걸린다면:

rate = 초당 10건

이어도

concurrency
300

까지 늘어날 수 있다.


✅ 71. 장시간 AI Job은 Concurrency가 특히 중요하다

현재 로컬 LLM은 모델 하나만 동시에 돌리는 편이 안정적일 수 있다.

예:

AI Worker
concurrency = 1

이다.


✅ 72. DB Connection Pool도 Concurrency Limit 역할을 한다

예:

Pool Size
20

이면 동시에 DB Connection을 20개까지만 사용한다.


✅ 73. 하지만 Pool을 Rate Limiter처럼 사용하면 안 된다

과도한 요청은 Pool Queue에 계속 쌓이면서 Latency가 증가한다.


✅ 74. Connection Pool 앞에서 요청 수를 제어하는 것이 낫다

즉:

Request Limit

↓

Application

↓

DB Pool

이다.


✅ 75. Bulkhead

0924와 연결된다.

리소스를 기능별로 분리해 하나의 과부하가 전체를 먹지 않게 한다.


✅ 76. 예

Order Worker
별도 Concurrency

AI Worker
별도 Concurrency

Export Worker
별도 Concurrency

이다.


✅ 77. 모든 Job이 동일 Worker Pool을 쓰면

AI Job 하나가 CPU를 많이 사용해 주문 Job이 늦어질 수 있다.


✅ 78. Queue도 중요도에 따라 일부 분리할 수 있다

예:

critical

normal

low

정도다.

현재 규모에서는 너무 많이 나누지 않는다.


✅ 79. Priority Queue

하나의 Queue 안에서 Priority를 줄 수도 있다.

예:

Order
priority 1

Export
priority 5

AI Report
priority 10

처럼 한다.


✅ 80. Priority가 있다고 Low Priority가 영원히 실행되지 않게 하면 안 된다

고우선 Job이 계속 들어오면 Low Job이 Starvation될 수 있다.


✅ 81. Starvation

LOW Job
계속 대기

하는 문제다.


✅ 82. Aging

오래 기다린 Job의 Priority를 점차 높이는 전략이 있다.

현재 규모에서는 필요할 때 고려한다.


✅ 83. Deadline 기반 처리

예:

알림톡
5분 안에 보내야 함

이면 Deadline을 가지고 우선 처리할 수도 있다.


✅ 84. 이미 Deadline을 넘긴 Job은 실행 가치가 없을 수도 있다

예:

오전 9시 안내
현재 오후 8시

라면 보내지 않는 편이 나을 수 있다.


✅ 85. Expired Job

상태:

EXPIRED

로 처리한다.


✅ 86. Queue Worker가 시작 전에 Deadline을 확인한다

예:

if (job.deadlineAt < now) {
  return markExpired();
}

같이 한다.


✅ 87. 대량 작업은 Chunking

예:

10,000명 알림

하나의 Job으로 만들지 않는다.


✅ 88. Batch

500명
×
20 Job

으로 나눈다.


✅ 89. Chunking 장점

Concurrency 조절 가능

일부 Retry 가능

Progress 확인 가능

Rate Limit 적용 가능

하다.


✅ 90. Chunk Size도 너무 크거나 작으면 안 된다

너무 큼:

한 Job 실패 영향 큼

너무 작음:

Queue Overhead 증가

한다.


✅ 91. External API 호출에는 Semaphore를 둘 수 있다

예:

동시 Provider 요청
최대 5

이다.


✅ 92. Rate Limit + Semaphore

예:

동시 5개

초당 20회

둘 다 적용할 수 있다.


✅ 93. Provider별로 별도 Limit

예:

Kakao
20/s

Notion
5/s

Other Provider
10/s

처럼 한다.


✅ 94. 하나의 Provider 장애가 다른 Provider를 막지 않도록 한다

Provider별 Bulkhead다.


✅ 95. Rate Limit State는 어디에 저장할까?

단일 서버라면:

Memory

로도 가능하다.


✅ 96. Multi-instance라면 공유 상태가 필요할 수 있다

예:

Redis

가 흔하다.


✅ 97. 그렇지 않으면 Instance마다 Limit을 별도로 계산한다

예:

Server A
100/min

Server B
100/min

이면 전체 Limit은 200/min이 된다.


✅ 98. Global Limit이 필요한 경우 공유 Counter를 사용한다

예:

admin-export:{adminId}

Counter를 Redis에 둔다.


✅ 99. 현재 단일/소규모 서버라면 복잡한 Global Limiter부터 만들 필요는 없다

NestJS Guard 수준으로 시작할 수 있다.


✅ 100. 단 로그인/인증 Rate Limit은 중요하다

Brute Force 방어에 도움이 된다.

예:

IP 단위

계정 단위

를 함께 볼 수 있다.


✅ 101. 계정 단위만 보면 공격자가 여러 계정을 시도할 수 있다

IP 단위도 필요하다.


✅ 102. IP만 보면 공유망 사용자가 영향을 받을 수 있다

그래서 조합이 필요할 수 있다.


✅ 103. 로그인 실패 횟수 기반 추가 제한

예:

5회 실패
→ Delay 증가

등이다.


✅ 104. 하지만 계정 Lockout을 너무 쉽게 걸면 DoS가 될 수 있다

공격자가 다른 사람 계정을 일부러 잠글 수 있기 때문이다.


✅ 105. 그래서 Rate Limit이 Lockout보다 안전한 경우가 많다

완전 잠금 대신 속도를 제한한다.


✅ 106. 검색 API Rate Limit

검색은 Query 비용이 높을 수 있다.

특히:

LIKE '%keyword%'

같은 Query가 무거우면 Bot이 DB를 압박할 수 있다.


✅ 107. Debounce도 중요하다

Frontend 검색창에서:

한 글자 입력할 때마다 API 요청

하지 않는다.


✅ 108. Debounce 예

300ms

사용자 입력이 멈춘 뒤 요청한다.


✅ 109. Debounce는 Rate Limit의 Frontend 버전이라고 볼 수 있다

불필요한 요청 자체를 만들지 않는다.


✅ 110. 같은 Query 중복 요청 Deduplication

TanStack Query가 같은 Key 요청을 공유할 수 있다.

Cache/Rate Limiting과 같이 활용한다.


✅ 111. Pagination Limit

API에서:

limit=100000

을 허용하면 한 요청만으로도 큰 부하가 발생한다.


✅ 112. Max Page Size

예:

limit
max 100

등 상한을 둔다.


✅ 113. Export는 별도 Job으로

사용자가 10만 건을 내려받고 싶다면:

GET /orders?limit=100000

이 아니라:

ExportJob

으로 넘긴다.


✅ 114. 이것도 Load Control이다

큰 요청을 일반 API에서 분리한다.


✅ 115. Query Complexity Limit

검색 필터가 지나치게 복잡할 수도 있다.

예:

OR 수십 개

기간 10년

정렬 + Full Text + Join

등이다.


✅ 116. 기간 제한

관리자 검색 기본 범위:

최근 30일

로 두고 필요할 때 확장하도록 할 수 있다.


✅ 117. 과도한 Query는 Background Job으로 넘긴다

즉:

Interactive Request

와:

Batch Job

을 구분한다.


✅ 118. Request Timeout도 Load Protection이다

무거운 요청이 무한히 서버 Resource를 점유하지 않게 한다.


✅ 119. 예

API
10초

External API
3초

처럼 제한한다.


✅ 120. Timeout만으로 충분하지는 않다

Timeout이 발생해도 DB Query가 계속 돌아가는 경우가 있을 수 있다.

DB Statement Timeout도 고려한다.


✅ 121. PostgreSQL Statement Timeout

너무 오래 걸리는 Query를 제한할 수 있다.

운영 정책에 맞춰 설정한다.


✅ 122. Query Timeout은 모든 Query에 동일하게 둘 필요는 없다

예:

Order Detail
짧게

Report Query
길게

다.


✅ 123. Report는 Background Job으로 분리하면 Interactive Timeout을 짧게 유지할 수 있다

이게 Async Job 구조의 장점이다.


✅ 124. Slow Consumer

Queue Producer보다 Consumer가 계속 느린 상태다.


✅ 125. 원인은 여러 가지

외부 API 느림

DB Lock

CPU 부족

잘못된 Concurrency

Rate Limit

Provider 장애

일 수 있다.


✅ 126. Concurrency를 무조건 늘리면 안 된다

예:

Worker 10
→ 100

으로 늘리면 DB/Provider를 더 압박할 수 있다.


✅ 127. 병목이 어디인지 먼저 확인한다

CPU-bound?

DB-bound?

External API-bound?

Rate Limit-bound?

를 구분한다.


✅ 128. Little's Law 개념

대략적으로:

Concurrency
≈
Throughput × Latency

관계를 생각할 수 있다.


✅ 129. 예

한 작업이 평균:

2초

걸리고 초당:

10건

처리하려면 대략:

20개

동시 실행이 필요할 수 있다.


✅ 130. 단 실제 시스템에서는 여유와 변동성이 있다

공식 숫자로 맹신하지 않고 Capacity Planning 힌트로 사용한다.


✅ 131. Queue Consumer Autoscaling

Queue Depth가 증가하면 Worker 수를 늘릴 수도 있다.


✅ 132. 하지만 현재 규모에서는 수동/고정 Concurrency가 더 단순하다

Auto Scaling까지는 실제 필요가 생긴 뒤 고려한다.


✅ 133. Scale Out도 무한 해결책이 아니다

DB와 External API Capacity는 그대로일 수 있다.

Worker만 늘리면 하류가 무너진다.


✅ 134. Backpressure의 핵심은 하류 Capacity를 존중하는 것

Producer Capacity
>
Consumer Capacity

상태를 오래 유지하지 않는다.


✅ 135. Admission Control

시스템에 일을 받아들일지 말지를 입구에서 결정한다.


✅ 136. 예

현재:

AI Queue Depth
20

이고 최대:

20

이라면 신규 AI 요청은:

거절

할 수 있다.


✅ 137. 사용자에게 명확한 상태 제공

예:

현재 분석 작업이 많습니다.
잠시 후 다시 시도해주세요.

또는:

대기열 5번째

처럼 보여줄 수 있다.


✅ 138. Queueing을 사용자에게 숨기지 않아도 된다

장시간 작업은:

PENDING

PROCESSING

COMPLETED

상태를 제공하는 것이 낫다.


✅ 139. Backlog Limit

Queue가:

maxDepth

를 넘으면 신규 Job 생성을 막는다.


✅ 140. 이 Limit은 Queue 기술 제한과 업무 제한이 다르다

Redis가 100만 Job을 넣을 수 있다고 100만 건을 받아도 되는 것은 아니다.


✅ 141. 업무 Deadline을 고려하면 Queue 최대 크기가 정해질 수 있다

예:

Worker
분당 100건 처리

업무 Deadline
10분

이면 대략 1,000건 이상 쌓이면 Deadline을 넘길 가능성이 높다.


✅ 142. 그래서 Queue Capacity는 처리량과 SLO 기준으로 잡는다

단순 Memory 기준만 보면 안 된다.


✅ 143. Overload State

예:

NORMAL

DEGRADED

OVERLOADED

상태를 정의할 수 있다.


✅ 144. NORMAL

모든 기능 정상.


✅ 145. DEGRADED

예:

AI Analysis OFF

Export 제한

Recommendation OFF

한다.


✅ 146. OVERLOADED

핵심 기능만 허용한다.

예:

주문

필수 관리자 처리

만 유지한다.


✅ 147. 이런 상태를 자동 계산할 수도 있다

Input:

DB CPU

Queue Age

Error Rate

Latency

등이다.


✅ 148. 하지만 초기에는 Dashboard + Manual Toggle로 충분하다

자동화는 운영 데이터가 쌓인 뒤 한다.


✅ 149. Load Shedding Policy 예

interface LoadSheddingPolicy {
  feature: string;

  priority:
    | 'CRITICAL'
    | 'HIGH'
    | 'NORMAL'
    | 'LOW';

  shedWhenOverloaded: boolean;
}

✅ 150. Feature Flag와 합칠 수 있다

예:

system_overload_mode=true

일 때 Low Priority 기능을 비활성화한다.


✅ 151. 단 하나의 Global Flag로 너무 많은 로직을 숨기지 않는다

어떤 기능이 영향을 받는지 명확해야 한다.


✅ 152. Retry가 Overload를 악화시키는 대표 원인

Server:

503

응답.

Client 100개가 동시에:

1초 후 Retry

하면 다시 100개가 몰린다.


✅ 153. Jitter

각 Retry 시간을 다르게 한다.

예:

1.0s
1.3s
1.8s
2.4s

등이다.


✅ 154. Exponential Backoff

예:

1s

2s

4s

8s

처럼 Retry 간격을 늘린다.


✅ 155. Max Backoff

무한히 증가시키지 않는다.

예:

최대 1분

등 상한을 둔다.


✅ 156. Retry Deadline

Job 자체 Deadline을 넘으면 Retry하지 않는다.


✅ 157. Rate Limit Error는 Retryable일 수 있다

하지만:

Retry-After

를 존중해야 한다.


✅ 158. Validation Error는 Retry하지 않는다

400

Invalid Payload

Permission Denied

같은 Error는 Rate Control과 무관하다.


✅ 159. Circuit Breaker와 과부하 보호

Provider가 느린데 계속 요청하면 Worker가 쌓인다.

Circuit Breaker를 열어:

새 요청 잠시 차단

할 수 있다.


✅ 160. Rate Limiter와 Circuit Breaker 차이

Rate Limiter:

요청이 너무 많음

Circuit Breaker:

하류 시스템이 비정상

이다.


✅ 161. 둘은 함께 사용할 수 있다

예:

초당 10건 Limit

+

Provider Error 50% 이상
→ Circuit Open

이다.


✅ 162. Timeout도 같이 필요하다

과부하 보호는:

Rate Limit

Concurrency Limit

Timeout

Circuit Breaker

Backpressure

를 조합한다.


✅ 163. 하나의 방어선만으로는 부족하다

예:

Rate Limit이 있어도 Job 하나가 5분 걸리면 Concurrency가 쌓일 수 있다.


✅ 164. AI Tool Loop에 Rate Limit

AI Agent가 Bug로:

DB Query

DB Query

DB Query
...

를 반복할 수 있다.


✅ 165. Tool별 호출 제한

예:

DB Read
20/run

Git command
50/run

External API
10/run

같이 Budget을 둔다.


✅ 166. 위험 Tool은 더 낮게

예:

Production Write
1/run

또는 Human Approval을 요구한다.


✅ 167. AI Cost Budget

API 모델을 사용하는 경우:

maxTokens

maxCost

를 설정한다.


✅ 168. Local LLM도 시간 Budget

예:

한 Run
최대 30분

이다.


✅ 169. Budget 초과 시

AI_BUDGET_EXCEEDED

로 종료한다.


✅ 170. AI가 자동으로 Budget을 늘리지 못하게 한다

무한 자동화 방지다.


✅ 171. 사용자/API별 Quota

예:

Admin Export
하루 20건

같이 둘 수 있다.


✅ 172. Quota는 Rate보다 장기간 자원 보호에 좋다

누군가 매분 Limit 이하로 호출해도 하루 전체 사용량은 매우 클 수 있다.


✅ 173. Export Quota

예:

1분 3건

하루 50건

같이 둘 수 있다.


✅ 174. AI Quota

예:

동시 1

시간당 10

하루 100

처럼 구성할 수 있다.


✅ 175. Quota Reset

DAILY

MONTHLY

등 Reset 기준이 필요하다.


✅ 176. Timezone도 명확히 한다

예:

Asia/Seoul 기준 자정

인지 UTC 기준인지 명확히 한다.

0929 Scheduler와 연결된다.


✅ 177. Rolling Quota도 가능하다

예:

최근 24시간

을 기준으로 한다.

더 정확하지만 구현 복잡도가 높다.


✅ 178. 현재는 Calendar Day 기준이 단순하다

정말 필요할 때 Rolling으로 바꾼다.


✅ 179. 관리자 Bulk Action 제한

예:

주문 상태 10,000건 일괄 변경

을 한 Request로 허용하면 위험하다.


✅ 180. Max Selection

예:

한 번에 최대 100건

으로 제한할 수 있다.


✅ 181. 더 큰 작업은 Bulk Job 생성

BulkOrderUpdateJob

으로 넘긴다.


✅ 182. Bulk Job도 Chunking

100건 × 여러 Batch

형태로 처리한다.


✅ 183. Dry Run

대량 변경 전에:

대상 건수

현재 상태

예상 변경

을 보여준다.


✅ 184. Rate Limit은 Business Safety 장치가 될 수 있다

예:

알림톡 재발송
1주문당 5분에 1회

같이 한다.


✅ 185. 이것은 일반 API Rate Limit과 다르다

Key:

notification-resend:{orderId}

이다.


✅ 186. Domain Rate Limit

특정 업무 Entity 기준 제한이다.

예:

한 주문
알림 재발송
5분 1회

이다.


✅ 187. Business Cooldown

다른 이름으로:

cooldown

이라고 볼 수 있다.


✅ 188. Cooldown은 중복 발송 방지에 좋다

Idempotency와 같이 사용한다.


✅ 189. Idempotency와 Rate Limit은 다르다

Idempotency:

같은 Logical Action 중복 방지

Rate Limit:

서로 다른 Action이라도 빈도 제한

이다.


✅ 190. 예

사용자가 서로 다른 Request ID로 재발송을 10번 눌러도:

Idempotency Key
각각 다름

일 수 있다.

Rate Limit은 2번째부터 막을 수 있다.


✅ 191. 관리자 수동 Retry에도 Rate Limit

실패 Job Retry 버튼을 계속 누르는 것을 막는다.


✅ 192. 예

job:{id}:manual-retry

1분
1회

정도다.


✅ 193. DLQ Retry도 Batch Limit

예:

한 번에 최대 50건

으로 제한한다.


✅ 194. 전체 10만 건 Retry 버튼은 위험하다

1001에서 다룬 Retry Storm과 연결된다.


✅ 195. Webhook Rate Limit은 신중

외부 Provider의 정상 Burst를 잘못 차단하면 Event가 유실될 수 있다.


✅ 196. Provider 특성을 고려한다

Webhook은:

짧은 시간에 대량 전송

할 수 있다.

너무 낮은 HTTP Limit을 두지 않는다.


✅ 197. 대신 Webhook은 빠르게 Inbox에 저장하고 응답

Receive

↓

Validate

↓

Inbox Insert

↓

200 OK

후 Background Processing한다.


✅ 198. 이렇게 하면 Request 처리량이 높아진다

Webhook Handler에서 무거운 Business Logic을 직접 하지 않는다.


✅ 199. Webhook Queue Backpressure

Inbox가 계속 증가하면 별도 Alert가 필요하다.


✅ 200. Provider 재전송 정책도 고려

429/500 응답을 보내면 Provider가 더 자주 Retry할 수도 있다.


✅ 201. 따라서 Webhook은 가능한 빨리 정상 수신하고 내부 Queue에서 속도를 조절

좋은 패턴이다.


✅ 202. Public API와 Webhook Rate Policy를 분리한다

같은 Global Limit을 쓰지 않는다.


✅ 203. Crawler/Bot

상품 사이트는 검색엔진/봇 Traffic도 있을 수 있다.


✅ 204. 무조건 Bot 차단하지 않는다

SEO Crawler까지 막으면 검색 노출에 영향을 줄 수 있다.


✅ 205. 명백한 Abuse만 제한

예:

초당 수백 검색

임의 ID Enumeration

등이다.


✅ 206. WAF/CDN Rate Limit

Application 이전 계층에서 차단할 수도 있다.

예:

CloudFront/WAF

같은 Edge 계층이다.


✅ 207. 장점

Application/DB까지 요청이 내려오기 전에 막을 수 있다.


✅ 208. Application Rate Limit도 여전히 필요할 수 있다

사용자/업무 ID처럼 Edge가 모르는 Context가 있기 때문이다.


✅ 209. Defense in Depth

Edge Rate Limit

↓

Application Rate Limit

↓

Concurrency Limit

↓

DB Pool

↓

Provider Rate Limit

같은 여러 층이 있다.


✅ 210. 하지만 전부 처음부터 만들 필요는 없다

실제 위험도가 높은 Endpoint부터 적용한다.


✅ 211. 현재 우선 적용 후보

로그인

검색

Excel Export

알림 재발송

관리자 Bulk Action

AI 실행

이다.


✅ 212. 상품 일반 조회는 우선 Cache/CDN이 더 효과적일 수 있다

1004와 연결된다.


✅ 213. Rate Limit Response에 현재 Limit 정보를 제공할 수도 있다

예:

remaining

resetAt

등이다.


✅ 214. 하지만 내부 구현 정보를 과도하게 노출할 필요는 없다

공격자가 Limit을 정밀하게 계산할 수 있다.

필요한 Client 정보만 제공한다.


✅ 215. 관리자 UI에서는 남은 Quota를 보여줄 수 있다

예:

오늘 Export
17 / 50

이다.


✅ 216. 사용자에게 제한 이유를 명확히 보여준다

서버 오류

라고 하지 않고:

짧은 시간에 요청이 많습니다.

로 구분한다.


✅ 217. Queue 작업에서는 PENDING을 Error로 보지 않는다

과부하 상황에서 즉시 처리되지 않아도 정상 Queueing일 수 있다.


✅ 218. 예상 대기시간

Processing Rate를 이용해 대략 계산할 수도 있다.

예:

앞에 100건

분당 20건 처리

예상 5분

이다.


✅ 219. 하지만 정확한 ETA를 보장하지 않는다

외부 API Latency 등으로 달라질 수 있다.


✅ 220. Queue Position

고객/관리자에게:

대기 중

정도만 보여줘도 충분할 수 있다.


✅ 221. Shed vs Queue

모든 요청을 Queue에 넣는 게 좋은 것은 아니다.


✅ 222. Queue할 가치가 있는 작업

Export

AI Report

대량 알림

Background 분석

이다.


✅ 223. 오래 기다리면 의미 없는 작업

검색 요청

페이지 조회

현재 상태 조회

는 Queue보다 빠르게 Reject하는 편이 낫다.


✅ 224. Interactive vs Async 구분

Interactive

수초 내 Response 필요

Async

대기 가능

이다.


✅ 225. Interactive Overload

빠르게:

429

503

등으로 실패시키는 것이 낫다.


✅ 226. Async Overload

Queue 또는 Deferred Processing을 사용한다.


✅ 227. Status Code 구분

429
Client/Identity 기준 요청 과다
503
서비스 Capacity 부족

처럼 구분할 수 있다.


✅ 228. 503에도 Retry-After를 제공할 수 있다

Client가 무작정 즉시 재시도하지 않도록 한다.


✅ 229. Admission Control에서 DB 상태도 볼 수 있다

예:

DB Connection Pool 95% 사용

이면 Low Priority 요청을 거절할 수 있다.


✅ 230. 하지만 Request마다 CloudWatch Metric 조회 같은 무거운 작업을 하면 안 된다

Application 내부에서 사용할 수 있는 가벼운 Signal을 사용한다.


✅ 231. 예

Queue Depth Cache

Pool Active Count

Local Overload State

등이다.


✅ 232. Overload State를 일정 주기로 계산

예:

5초마다

Metric을 보고 상태를 갱신한다.


✅ 233. Request Path에서는 상태만 빠르게 읽는다

if overloaded && featureLowPriority
→ reject

이다.


✅ 234. Backpressure도 Cache처럼 새로운 복잡성을 만든다

너무 민감하게 반응하면 정상 요청이 불필요하게 거절된다.


✅ 235. 따라서 Metrics 없이 Threshold를 추측하지 않는다

초기에는:

관찰

Alert

Manual Control

부터 시작한다.


✅ 236. Capacity Baseline

예:

평소 API RPS

DB p95

Queue Throughput

Worker Concurrency

를 측정한다.


✅ 237. Load Test

Staging에서 점진적으로 Traffic을 올려본다.

예:

10 RPS

50 RPS

100 RPS

200 RPS

이다.


✅ 238. 목표는 최대 숫자 자랑이 아니다

어디서:

Latency가 급증하는가?

Error가 생기는가?

DB가 포화되는가?

를 찾는 것이다.


✅ 239. Saturation Point

Resource가 포화되기 시작하는 지점이다.


✅ 240. 예

100 RPS
정상

150 RPS
p95 200ms

180 RPS
p95 1.5s

200 RPS
Timeout 증가

이면 180~200 부근이 위험할 수 있다.


✅ 241. Rate Limit은 Saturation Point보다 여유 있게 설정

예:

150 RPS 이하

처럼 안전 Margin을 둔다.


✅ 242. 하지만 전체 Limit 하나로 끝내지 않는다

Endpoint별 비용이 다르다.


✅ 243. Weighted Rate Limit

예:

상품 Detail
cost 1

복잡 검색
cost 5

Export
cost 50

처럼 요청 비용을 다르게 계산할 수 있다.


✅ 244. 현재 규모에서는 과할 수 있다

우선 무거운 Endpoint에 별도 Limit을 두는 것이 단순하다.


✅ 245. Database Write Rate

대량 Write도 제한이 필요할 수 있다.

예:

Lead Insert

Webhook Insert

Bulk Update

이다.


✅ 246. Write Batch

한 건씩 10,000번 Insert보다 Batch Insert가 더 효율적일 수 있다.


✅ 247. 하지만 너무 큰 Batch는 Lock/Transaction 시간을 늘린다

적당한 크기로 나눈다.


✅ 248. Batch Worker에는 Transaction Timeout도 둔다

무한히 큰 Transaction을 막는다.


✅ 249. API Request Body Size 제한

큰 Payload도 일종의 Resource 공격이다.

예:

100MB JSON

을 받아 Parser가 CPU/RAM을 쓸 수 있다.


✅ 250. Body Size Limit

Endpoint별 적절한 크기로 제한한다.


✅ 251. 파일 업로드도 Size Limit

예:

이미지
10MB

등이다.


✅ 252. Excel Export 요청도 최대 기간/Row 제한

예:

한 번에
100만 Row

를 허용하지 않는다.


✅ 253. Large Export는 Split할 수 있다

예:

월별

통신사별

50,000 rows/file

등으로 나눈다.


✅ 254. API Pagination도 Load Protection이라는 점을 기억한다

1004 Cache 이전에 Pagination을 먼저 최적화하는 이유다.


✅ 255. Log Rate Limiting

과부하 때 Error Log가 초당 수천 건 발생할 수 있다.


✅ 256. Log 자체가 장애를 키울 수 있다

Disk IO

Cloud Logging 비용

Network

이 증가한다.


✅ 257. 동일 Error Sampling

예:

동일 Error
초당 1000회

실제 Log
초당 10회

만 기록하고 Counter는 Metric으로 남길 수 있다.


✅ 258. Error Aggregation

DATABASE_TIMEOUT
1분 12,420건

처럼 집계한다.


✅ 259. Audit Log는 Sampling하면 안 되는 경우가 많다

Audit와 Application Log를 구분한다.


✅ 260. Metrics Cardinality도 과부하를 만들 수 있다

예:

label=userId

로 모든 사용자를 Metric Label에 넣으면 Series가 폭증한다.


✅ 261. Rate Limit Metric도 Label을 제한

예:

endpoint

limiterType

result

정도만 사용한다.


✅ 262. userId는 일반 Metric Label보다 Log/Tracing에 둔다

Cardinality를 줄인다.


✅ 263. Rate Limit Metrics

예:

rate_limit_allowed_total

rate_limit_rejected_total

quota_exceeded_total

이다.


✅ 264. Queue Metrics

queue_depth

queue_oldest_age

queue_processing

queue_failed

queue_throughput

이다.


✅ 265. Load Shedding Metrics

load_shed_total

system_overload_state

feature_disabled_due_to_load

등이다.


✅ 266. Concurrency Metrics

worker_active

worker_capacity

db_pool_active

db_pool_waiting

등이다.


✅ 267. Saturation이 중요하다

Observability의:

Traffic

Errors

Latency

Saturation

중 Saturation을 보는 단계다.


✅ 268. Queue Depth만 보고 Worker를 늘리지 않는다

동시에:

DB CPU

Provider Latency

Error Rate

도 본다.


✅ 269. Alert 예

Export queue oldest age
> 10분

Warning.


✅ 270. Notification queue oldest age

> 1분

이면 더 높은 Severity일 수 있다.


✅ 271. AI Queue

> 30분

이어도 업무 영향이 낮을 수 있다.


✅ 272. 같은 숫자를 모든 Queue에 적용하지 않는다

업무 SLO에 맞춘다.


✅ 273. Overload Runbook

예:

1. Error Rate 확인

2. Latency 확인

3. DB Pool / CPU 확인

4. Queue Depth / Age 확인

5. External Provider 상태 확인

6. Low Priority 기능 Pause

7. Worker Concurrency 확인

8. Retry Storm 여부 확인

9. Recovery 후 Backlog Controlled Drain

이다.


✅ 274. Backlog Recovery

장애 복구 후 Queue가 많이 쌓여 있다.

Worker Concurrency를 갑자기 최대치로 올리면 다시 장애가 날 수 있다.


✅ 275. Controlled Drain

예:

concurrency
5

↓

10

↓

20

점진적으로 올린다.


✅ 276. Provider Recovery 직후도 조심

Provider가 복구되자마자 수십만 Retry를 보내면 Provider가 다시 다운될 수 있다.


✅ 277. Retry Drain Rate

예:

초당 20건

처럼 제한한다.


✅ 278. Fresh Traffic 우선 여부

Backlog와 신규 요청 중 어떤 것을 먼저 처리할지 결정한다.


✅ 279. 예

알림톡:

30분 전 메시지

vs

현재 주문 완료 메시지

현재 메시지가 더 중요할 수 있다.


✅ 280. Priority를 이용해 신규 Critical Job을 먼저 처리할 수 있다


✅ 281. 하지만 오래된 Job이 영원히 밀리지 않게 한다

Deadline/Expiration 정책을 같이 사용한다.


✅ 282. Backlog Reconciliation

너무 오래된 Job은:

실제 여전히 필요한가?

확인한다.


✅ 283. Blind Replay하지 않는다

0917 Reconciliation 원칙과 같다.


✅ 284. Notification Backlog 예

Order 상태
이미 CANCELLED

인데 오래된:

ORDER_COMPLETED 알림

이 Queue에 남아 있으면 발송하면 안 될 수 있다.


✅ 285. 실행 직전에 현재 상태 검증

특히 오래 대기한 Job에서는 중요하다.


✅ 286. AI 작업도 오래 기다렸다면 Context가 바뀌었을 수 있다

예:

commitSha

가 달라졌다면 기존 AI Job 실행이 의미 없을 수 있다.


✅ 287. AI Queue에서 Stale Job 검증

baseCommit

promptVersion

policyVersion

을 다시 확인한다.


✅ 288. Context가 바뀌었으면

STALE

로 종료하고 새 Run을 만든다.


✅ 289. Rate Limit도 Versioning이 필요할 수 있다

정책이 변경된다.

예:

Export
5/min
→
2/min

이다.


✅ 290. Policy Version

예:

ratePolicyVersion = v3

를 기록할 수 있다.


✅ 291. Rate Limit 설정 변경도 Audit

특히:

100/min
→
10000/min

은 큰 위험이다.


✅ 292. Config Validation

예:

min

max

allowed range

를 둔다.


✅ 293. Limit을 0으로 설정하면 의미를 명확히 한다

0 = disabled?

인지:

0 = unlimited?

인지 혼동하면 위험하다.


✅ 294. 명시적 상태가 낫다

예:

enabled=false

와 limit 숫자를 분리한다.


✅ 295. Emergency Override

장애 대응 중 일시적으로 Limit을 낮추거나 높일 수 있다.


✅ 296. Override에는 Expiry를 둔다

예:

1시간 후 자동 원복

한다.


✅ 297. 그렇지 않으면 임시 설정이 영구 설정이 된다

0928 Configuration Drift와 연결된다.


✅ 298. Rate Limit Bypass

내부 Health Check나 Trusted System은 예외가 필요할 수 있다.


✅ 299. 하지만 관리자라고 무조건 Bypass하지 않는다

관리자 Bulk 요청이 오히려 큰 부하를 만들 수 있다.


✅ 300. Bypass는 최소화한다

예:

Internal Health Endpoint

특정 Infrastructure Probe

정도다.


✅ 301. API Key별 Limit

외부 Integration이 생기면:

partner-a
1000/day

partner-b
100/day

처럼 나눌 수 있다.


✅ 302. Tenant별 Fairness

한 고객/지점이 Resource를 전부 독점하지 않게 한다.

현재 여러 지점/통신사 통합으로 확장될 경우 중요해질 수 있다.


✅ 303. Fair Queueing

예:

LGU

SKT

KT

Job이 한쪽에 몰려도 다른 쪽 Job이 전부 밀리지 않게 할 수 있다.


✅ 304. 지금부터 만들 필요는 없지만 구조 확장 시 기억한다


✅ 305. Per-Carrier Worker Concurrency

예:

LGU
5

SKT
5

KT
5

처럼 분리할 수도 있다.


✅ 306. 단 실제 처리량이 적을 때는 Pool 하나가 단순하다

과도한 Partitioning은 피한다.


✅ 307. Abuse Prevention

예:

상담 신청 Form

에 Bot이 수천 건을 넣을 수도 있다.


✅ 308. Rate Limit + CAPTCHA 등을 조합할 수 있다

하지만 정상 사용성을 해치지 않게 한다.


✅ 309. Honeypot 같은 단순 Anti-bot도 가능

현재 필요할 때 도입한다.


✅ 310. Rate Limit은 보안 정책과 운영 정책이 겹치는 영역이다

공격 방어와 Resource 보호 모두 담당한다.


✅ 311. Distributed Rate Limit에서 Redis 장애

Rate Limiter가 Redis에 의존하는데 Redis가 다운됐다.

어떻게 할까?


✅ 312. Fail Open

Rate Limit 검사 실패
→ 요청 허용

이다.

가용성은 높지만 Abuse 방어는 약해진다.


✅ 313. Fail Closed

Limiter 실패
→ 요청 차단

이다.

보안은 강하지만 정상 사용자도 막힌다.


✅ 314. Endpoint별 정책이 달라야 한다

예:

상품 조회
Fail Open
위험한 관리자 Bulk Action
Fail Closed

처럼 한다.


✅ 315. 로그인은 상황에 따라 보수적으로 처리

단 Rate Limiter 장애 때문에 모든 로그인까지 막을지 신중히 결정한다.


✅ 316. Local Fallback Limiter

Redis 장애 시 Instance별 임시 Local Limit을 사용할 수도 있다.


✅ 317. 하지만 분산 정확도는 떨어진다

그래도 무제한 허용보다 나을 수 있다.


✅ 318. Rate Limiter 자체 Timeout도 짧게

Rate Limit 확인 때문에 Request가 느려지면 안 된다.


✅ 319. Limiter 데이터도 TTL 필수

예:

rate:user:123:window

Key가 영원히 남지 않게 한다.


✅ 320. Counter Key에 PII 금지

전화번호 대신 내부 ID를 사용한다.


✅ 321. Rate Limit Log에도 개인정보 최소화

subjectType
endpoint
result

정도만 남긴다.


✅ 322. Limit 초과를 Error Log로 매번 남기지 않는다

정상 제어 동작일 수 있다.


✅ 323. INFO/Metric으로 집계

예:

rate_limit.rejected

Metric을 증가시킨다.


✅ 324. 단 갑자기 초과율이 급증하면 Alert

Bot/Client Bug 가능성이 있다.


✅ 325. Reject Ratio

예:

전체 요청 중
20% Rate Limited

라면 정상 Limit이 너무 낮거나 Traffic 이상일 수 있다.


✅ 326. Endpoint별 Reject Rate

어디에서 문제가 발생하는지 본다.


✅ 327. Rate Limit과 UX

버튼을 연속 클릭하는 사용자의 경우:

버튼 Disable

Loading State

만 잘 구현해도 Server Rate Limit에 걸릴 요청이 줄어든다.


✅ 328. Frontend Request Prevention이 먼저일 수 있다

예:

신청 버튼
Double Submit 방지

이다.


✅ 329. Double Submit에는 Idempotency Key도 사용

Frontend Disable만 믿지 않는다.


✅ 330. 다층 방어

Button Disable

↓

Idempotency Key

↓

Business Cooldown

↓

Rate Limit

이다.


✅ 331. 주문 신청에는 일반 Rate Limit보다 Idempotency가 더 중요할 수 있다

동일 신청을 두 번 만드는 문제를 막아야 하기 때문이다.


✅ 332. Rate Limit은 그 위에 Abuse 방어로 추가한다


✅ 333. Admin Bulk Action에도 Preview + Confirmation

Rate Limit보다 사용자 실수를 먼저 줄인다.


✅ 334. Request Coalescing

같은 데이터 요청이 동시에 여러 개 들어오면 하나로 합친다.

1004 Single Flight와 같다.


✅ 335. 이것도 Load Reduction 전략이다

Rate Limit 없이도 하류 요청 수를 줄인다.


✅ 336. Backpressure와 Cache는 함께 사용된다

Cache Hit
→ DB 요청 감소

Rate Limit
→ Traffic 제한

Backpressure
→ Queue 성장 제한

서로 다른 층이다.


✅ 337. Capacity Protection 전체 구조

CDN / Cache

↓

Rate Limit

↓

Admission Control

↓

Application

↓

Concurrency Limit

↓

Queue

↓

Worker Rate Limit

↓

DB / External Provider

이다.


✅ 338. 이 구조를 한 번에 모두 구현하지 않는다

현재 필요한 병목부터 해결한다.


✅ 339. 현재 프로젝트 추천 1단계

로그인 Rate Limit

Search Debounce

Max Pagination Limit

Export Request Limit

AI Concurrency 1

이다.


✅ 340. 2단계

Notification Resend Cooldown

Bulk Action Size Limit

Queue Depth / Age Monitoring

이다.


✅ 341. 3단계

Provider Worker Rate Limit

Retry Backoff + Jitter

Backlog Controlled Drain

이다.


✅ 342. 4단계

Load Shedding Kill Switch

Low Priority Feature Pause

이다.


✅ 343. 5단계

실제 규모가 커지면:

Distributed Rate Limit

Autoscaling

Fair Queueing

을 고려한다.


✅ 344. 당장 과한 것

복잡한 Global Adaptive Limiter

Multi-region Quota

Dynamic Weighted Fair Queue

AI가 자동으로 Capacity 조정

서비스 Mesh Rate Limit

까지는 필요 없다.


✅ 345. NestJS 구조 예

src/
├─ common/
│  ├─ rate-limit/
│  │  ├─ rate-limit.guard.ts
│  │  ├─ rate-limit.policy.ts
│  │  └─ rate-limit.service.ts
│  │
│  └─ overload/
│     ├─ overload.service.ts
│     └─ load-shedding.guard.ts
│
├─ export/
├─ notification/
└─ automation/

✅ 346. Rate Policy

예:

interface RateLimitPolicy {
  key: string;

  limit: number;

  windowMs: number;

  burst?: number;
}

✅ 347. Endpoint별 Policy

예:

export const ratePolicies = {
  login: {
    limit: 10,
    windowMs: 60_000,
  },

  export: {
    limit: 3,
    windowMs: 60_000,
  },
};

정확한 숫자는 실제 Traffic에 맞게 조정한다.


✅ 348. Domain Cooldown

예:

interface CooldownPolicy {
  action: string;

  resourceKey: string;

  cooldownMs: number;
}

이다.


✅ 349. 알림 재발송

action
RESEND_NOTIFICATION

resourceKey
order:123

cooldown
5m

같이 할 수 있다.


✅ 350. Queue Policy

예:

interface QueueCapacityPolicy {
  maxDepth?: number;

  maxOldestAgeMs?: number;

  concurrency: number;

  ratePerSecond?: number;
}

이다.


✅ 351. Load Shedding Policy

예:

interface FeaturePriority {
  feature: string;

  priority:
    | 'CRITICAL'
    | 'HIGH'
    | 'NORMAL'
    | 'LOW';

  disableInDegraded: boolean;

  disableInOverload: boolean;
}

✅ 352. Global Overload 상태

type SystemLoadState =
  | 'NORMAL'
  | 'DEGRADED'
  | 'OVERLOADED';

이다.


✅ 353. 초기에는 사람이 상태를 바꿔도 된다

관리자나 Config에서:

NORMAL
→ DEGRADED

로 전환한다.


✅ 354. 나중에 Metric 기반 자동화를 붙일 수 있다

먼저 운영 경험을 쌓는다.


✅ 355. Codex 구현 프롬프트

현재 NestJS + Prisma + PostgreSQL + 기존 Queue/Worker 구조에
과부하 보호를 위한 최소한의
Rate Limiting / Quota / Backpressure 구조를 추가해줘.

목표는 복잡한 Traffic Management Platform을 만드는 것이 아니라,

- 잘못된 반복 요청
- 관리자 Bulk Action
- Export 폭주
- AI Job 폭주
- 외부 Provider Rate Limit
- Queue Backlog

때문에 전체 서비스가 영향을 받는 것을 막는 것이다.

현재 사용하는 Queue, Redis, Auth Guard,
Frontend 요청 구조를 먼저 분석한다.

실제 Traffic Metric이 없는 곳의 Limit 값을
근거 없이 매우 낮게 설정하지 않는다.

1. 현재 Endpoint를 중요도와 비용 기준으로 분류한다.

예:
CRITICAL
- 주문 신청
- 관리자 주문 처리

HIGH
- 상품 조회
- 고객 알림

NORMAL
- Export
- 통계

LOW
- AI 분석
- 추천

실제 코드 기준으로 수정한다.

2. 다음 Endpoint를 우선 Rate Limit 후보로 검토한다.

- 로그인
- 검색
- Export 요청
- 알림 재발송
- 관리자 Bulk Action
- AI 실행 API

3. 일반 Product Read API 등에
무조건 강한 Rate Limit을 적용하지 않는다.

CloudFront / Cache가 더 적합한지 먼저 검토한다.

4. Rate Limit Key 전략을 만든다.

지원 후보:
- IP
- authenticated userId
- adminId
- API key
- resourceId

Endpoint에 맞는 Key만 사용한다.

5. 내부 ID 대신 전화번호/이메일 등의
PII를 Rate Limit Key로 사용하지 않는다.

6. 현재 단일 Instance라면
과도한 Distributed Rate Limiter를 만들지 않는다.

Multi-instance가 확인되거나 Global Limit이 필요할 때
기존 Redis를 활용할 수 있는 추상화를 만든다.

7. RateLimitService를 Business Logic과 분리한다.

8. Limit 초과 시
HTTP 429를 반환할 수 있게 한다.

가능한 경우 Retry-After를 제공한다.

9. Frontend가 429를 일반 서버 오류와 구분할 수 있게 한다.

10. Export 요청은
Rate Limit과 Queue Concurrency를 둘 다 고려한다.

예:
- 사용자/관리자 요청 빈도 제한
- Export Worker 동시 실행 제한

정확한 숫자는 Config로 조정 가능하게 한다.

11. Export Job이 이미 너무 많이 대기 중이라면
신규 Export 요청을 거절할 수 있는
Admission Control을 추가할 수 있게 한다.

판단에:
- queue depth
- oldest job age
를 고려한다.

12. Queue Capacity는
Redis가 얼마나 많이 저장 가능한지가 아니라
업무 SLO와 Worker Throughput을 기준으로 판단하도록 한다.

13. Queue별로 다음 정보를 확인할 수 있게 한다.

- pending
- active
- failed
- oldest job age
- throughput

14. AI Worker는
현재 하드웨어/모델 구조를 분석해서
기본 concurrency를 보수적으로 설정한다.

Local LLM 작업을 무제한 동시 실행하지 않는다.

15. AI Workflow에 다음 Budget을 지원할 수 있는 구조를 만든다.

- maxAttempts
- maxDuration
- maxToolCalls
- maxConcurrentRuns

16. Budget 초과는
AI_BUDGET_EXCEEDED 같은 명확한 Error Code로 처리한다.

17. 알림 재발송에는
일반 User Rate Limit 외에
Domain Cooldown을 적용할 수 있게 한다.

예:
orderId 단위 cooldown.

18. Cooldown과 Idempotency를 구분한다.

- Idempotency:
  동일 Logical Action 중복 방지
- Cooldown:
  서로 다른 요청이어도 과도한 반복 방지

19. 관리자 Bulk Action에
최대 선택 건수 제한을 추가할 수 있게 한다.

대량 작업은
Background Bulk Job으로 넘길 수 있게 한다.

20. Pagination API의
page size에 Max Limit을 적용한다.

Client가 과도한 limit 값을 보내도
전체 데이터를 한번에 조회하지 않게 한다.

21. Search UI에 Debounce가 제대로 적용되어 있는지 확인한다.

동일 검색 Query 중복 호출도 줄인다.

22. Worker가 외부 Provider를 호출하는 경우
Provider별 Rate Limit / Concurrency Limit을
설정할 수 있게 한다.

예:
Notification Provider
Notion
기타 External API

23. Provider Rate Limit Error가 발생하면
Retry-After가 있는 경우 이를 우선한다.

24. Retry에는
Exponential Backoff + Jitter를 사용할 수 있게 한다.

25. 무한 Retry를 허용하지 않는다.

maxAttempts / retryDeadline을 지원한다.

26. Queue Backlog 복구 시
Worker Concurrency를 갑자기 최대치로 올려
Recovery Storm이 발생하지 않게 한다.

Controlled Drain이 가능하게 한다.

27. 오래 대기한 Job은
실행 직전 현재 Business State를 다시 확인할 수 있게 한다.

예:
과거 ORDER_COMPLETED 알림 Job인데
현재 주문이 CANCELLED라면
Blind Execution하지 않는다.

28. Deadline이 있는 Job에는
deadlineAt 또는 expiresAt을 지원할 수 있게 한다.

이미 의미가 없는 Job은 EXPIRED 처리한다.

29. Load Shedding의 최소 구조를 설계한다.

SystemLoadState:
- NORMAL
- DEGRADED
- OVERLOADED

초기에는 Metric 기반 자동 전환이 아니라
Manual/Config 기반으로 시작해도 된다.

30. Feature별 Priority를 정의할 수 있게 한다.

예:
CRITICAL
HIGH
NORMAL
LOW

31. DEGRADED 상태에서는
LOW Priority 기능을 제한할 수 있게 한다.

예:
- AI 분석
- 추천
- 무거운 통계

32. OVERLOADED 상태에서는
핵심 주문/관리 기능을 우선 유지하도록 한다.

33. 기존 Feature Flag/Kill Switch 시스템이 있다면
중복 구현하지 않고 연결한다.

34. Rate Limit/Quota 설정에는 Validation을 적용한다.

예:
- limit < 0 금지
- 지나치게 높은 값 Warning
- window 유효성 검사

35. enabled와 limit=0의 의미를 분리한다.

0이 unlimited인지 disabled인지
모호한 구조를 만들지 않는다.

36. 임시 Emergency Override가 필요하면
expiresAt을 지원할 수 있게 한다.

37. Rate Limit 설정 변경을 Audit에 기록한다.

- actor
- before
- after
- reason
- timestamp

38. 다음 Metric을 추가할 수 있게 한다.

- rate_limit_allowed_total
- rate_limit_rejected_total
- quota_exceeded_total
- queue_depth
- queue_oldest_age
- worker_active
- load_shed_total

39. userId/adminId 같은 High Cardinality 값을
Metric Label로 무분별하게 사용하지 않는다.

40. Structured Log는 다음 Context만 최소한으로 남긴다.

- endpoint/action
- limiter policy
- result
- errorCode

PII 원문을 남기지 않는다.

41. Rate Limiter 저장소 장애 시
Endpoint 중요도별 Failure Policy를 정의할 수 있게 한다.

예:
- 일반 상품 조회: Fail Open
- 위험한 Bulk Action: Fail Closed 또는 제한적 처리

42. Redis 기반 Limiter를 사용한다면
짧은 Timeout을 사용한다.

Rate Limit 검사 자체가 API Latency의 병목이 되지 않게 한다.

43. 다음 Reliability Test를 작성한다.

- Limit 미만 요청
- Limit 초과 요청
- Window Reset
- Domain Cooldown
- Export Queue Full
- AI concurrency limit
- Provider 429 + Retry-After
- Backoff + Jitter
- Queue backlog
- Expired Job
- Limiter storage unavailable
- DEGRADED 상태 Low Priority 기능 차단
- NORMAL 복구

44. 기존 Production Queue나 실제 고객 요청을 사용하지 말고
Integration Test 환경에서 재현한다.

45. 기존 프로젝트가 아직 낮은 Traffic이라면
대형 Distributed Rate Limiting 시스템을 만들지 말고,

- Endpoint Guard
- Queue Concurrency
- Retry Backoff
- Domain Cooldown
- Queue Metrics

정도의 최소 구조를 우선 구현해줘.

✅ 356. Queue Capacity 분석용 Codex 프롬프트

현재 Queue / Worker 구조를 분석해서
어디에 Backpressure가 필요한지 정리해줘.

코드를 수정하지 않고 분석만 한다.

검토 대상:

- Notification
- Export
- Webhook
- Scheduled Job
- Workflow
- AI Task

각 Queue에 대해:

## Producer

어디에서 Job을 생성하는가?

## Consumer

어떤 Worker가 처리하는가?

## 평균 작업 비용 후보

- DB 중심
- CPU 중심
- 외부 API 중심
- File 중심

실제 Metric이 없으면 처리량을 임의로 숫자로 단정하지 않는다.

## 현재 Concurrency

## Retry 정책

## Deadline 여부

## Queue가 쌓였을 때 업무 영향

## Rate Limit 필요 여부

## Concurrency Limit 필요 여부

## Backlog Limit 필요 여부

## Load Shedding 가능 여부

## Priority

CRITICAL / HIGH / NORMAL / LOW

마지막에 다음 세 가지를 정리한다.

1. 가장 먼저 Queue 폭주 위험을 줄여야 하는 영역

2. Concurrency를 낮추는 것이 좋은 영역

3. Worker를 늘리기 전에 DB/Provider 병목을 확인해야 하는 영역

✅ 357. Load Test 설계 프롬프트

현재 NestJS API에 대한
안전한 Staging Load Test Plan을 작성해줘.

Production이나 실제 고객 데이터를 사용하지 않는다.

목표는 최대 TPS 기록이 아니라
어느 지점부터 Latency/Error/Saturation이 급증하는지 찾는 것이다.

테스트 대상:

1. Product Read
2. Search
3. Order Admin List
4. Export Request
5. Notification Request

각 대상마다:

- 요청 패턴
- 점진적 RPS 증가 단계
- 테스트 시간
- 예상 병목 후보
- 관찰 Metric
- 중단 조건
- 성공 기준

을 정리한다.

반드시 관찰할 Metric:

- p50 / p95 / p99 latency
- error rate
- DB connections
- DB query latency
- CPU
- memory
- queue depth
- oldest queue age

중단 조건 예:

- 오류율 급증
- DB Connection Pool 포화
- p95 급격한 상승
- 시스템 Health 이상

실제 수치는 현재 Infrastructure Capacity를 확인한 뒤
조정할 수 있게 작성한다.

✅ 358. 과부하 Incident Runbook

# Overload Incident

## 1. 증상 확인

- API Error Rate
- p95/p99 Latency
- DB Connection Pool
- DB CPU
- Queue Depth
- Oldest Job Age

## 2. Traffic 확인

- 특정 Endpoint 급증?
- 특정 IP/User?
- Bot?
- Client Retry Loop?
- Webhook Burst?

## 3. Retry Storm 확인

- 429/503 이후 즉시 Retry?
- Worker Retry 증가?
- Provider 장애?

## 4. Low Priority 작업 제한

- AI Worker Pause
- Export 제한
- Heavy Report Pause
- Recommendation OFF

## 5. Queue 확인

- Notification
- Export
- AI
- Workflow

## 6. Provider 확인

- Error Rate
- Latency
- 429
- Timeout

## 7. Controlled Recovery

- Worker Concurrency 점진 증가
- Retry Rate 제한
- Backlog Drain

## 8. Reconciliation

오래 대기한 Job이
현재도 유효한 업무인지 확인.

## 9. 정상화

- Latency 정상
- Queue Lag 정상
- Error Rate 정상

## 10. 복구한 Feature 재활성화

LOW Priority부터 단계적으로 복구.

✅ 359. 실무 체크리스트

Rate Limit

  • 모든 Endpoint에 같은 Limit을 사용하지 않는가?
  • IP/User/Admin/API Key 중 적절한 Key를 쓰는가?
  • PII를 Key에 사용하지 않는가?
  • 429를 명확히 처리하는가?
  • Retry-After를 활용할 수 있는가?

Quota

  • 단기 Rate와 장기 Quota를 구분하는가?
  • Export/AI 같은 고비용 기능에 Budget이 있는가?
  • Reset Timezone이 명확한가?
  • 임시 Override에 Expiry가 있는가?

Queue

  • Queue Depth를 보고 있는가?
  • Oldest Job Age를 보고 있는가?
  • Processing Rate를 알고 있는가?
  • Queue가 무한 Buffer가 아니라는 것을 전제로 하는가?
  • Backlog Limit이 필요한가?

Worker

  • Concurrency가 명시되어 있는가?
  • Concurrency를 무조건 높이지 않는가?
  • Provider별 호출 제한이 있는가?
  • Retry에 Backoff/Jitter가 있는가?
  • Worker가 Deadline을 확인하는가?

Backpressure

  • Consumer보다 Producer가 빠를 때 감지 가능한가?
  • Queue Full 시 신규 작업을 제한할 수 있는가?
  • Interactive 작업과 Async 작업을 구분하는가?
  • 오래 기다리면 가치 없는 Job을 Expire하는가?

Load Shedding

  • 기능별 Priority가 있는가?
  • 과부하 시 AI/Export 등 Low Priority 기능을 끌 수 있는가?
  • 핵심 주문 기능을 우선 보호하는가?
  • Kill Switch가 있는가?
  • 복구 시 단계적으로 기능을 다시 켜는가?

Bulk Action

  • 최대 선택 건수가 있는가?
  • 큰 작업은 Background Job으로 보내는가?
  • Chunking을 사용하는가?
  • Progress를 확인할 수 있는가?
  • 실패 대상만 Retry하는가?

Database

  • Pagination 상한이 있는가?
  • 무거운 Query에 Timeout이 있는가?
  • DB Connection Pool 대기열만으로 과부하를 처리하지 않는가?
  • Load Test로 Saturation Point를 확인하는가?

AI

  • maxConcurrentRuns가 있는가?
  • maxToolCalls가 있는가?
  • maxAttempts가 있는가?
  • maxDuration이 있는가?
  • Budget을 AI 스스로 늘릴 수 없게 했는가?

Observability

  • Rate Limit Reject 수를 보는가?
  • Queue Lag를 보는가?
  • Worker Active/Capacity를 보는가?
  • Retry가 증가하는지 보는가?
  • Load Shedding 횟수를 추적하는가?

📌 요약

1004에서는:

Cache

를 이용해 같은 Read가 계속 DB까지 내려가지 않도록 만들었다.

하지만 Cache가 아무리 좋아도:

Traffic 폭증

잘못된 Retry

Queue 폭주

AI Job 동시 실행

대량 Export

이 발생하면 시스템 Capacity를 넘을 수 있다.

1005의 핵심은:

시스템이 감당할 수 없는 일을 전부 받아들이는 것이 좋은 서비스가 아니라는 것

이다.

첫 번째 방어선은:

Rate Limit

이다.

누가

어떤 기능을

얼마나 자주

사용할 수 있는지 제한한다.

그다음:

Quota

를 통해 장기간 사용량을 제한할 수 있다.

예:

분당 3회

하루 50회

처럼 서로 다른 목적을 가진다.

Queue에서는:

Producer
>
Consumer

상태가 계속되면 Backlog가 끝없이 증가한다.

따라서:

Queue Depth

Oldest Job Age

Throughput

을 같이 보면서 Backpressure를 걸어야 한다.

또:

Worker Concurrency

와:

초당 처리 Rate

는 서로 다르다.

장시간 작업에서는 Concurrency를 제한하고, Provider에는 Rate Limit을 적용해야 한다.

과부하가 실제로 시작되면 모든 기능을 동일하게 보호하려고 하지 않는다.

CRITICAL
주문

HIGH
알림

NORMAL
Export

LOW
AI 분석

처럼 Priority를 나누고,

Low Priority 기능부터 제한

하는 것이 Load Shedding이다.

즉:

전체 기능이 같이 죽는 것

보다:

부가 기능 일부 제한
+
핵심 기능 생존

이 훨씬 낫다.

특히 Retry는 과부하 상황에서 매우 위험하다.

Timeout
↓
즉시 Retry
↓
다시 Timeout
↓
더 많은 Retry

가 장애를 증폭하기 때문이다.

그래서:

Backoff

Jitter

Retry Limit

Retry Deadline

이 필요하다.

그리고 Queue 장애가 복구됐다고:

밀린 Job 전체를 한 번에 실행

해서도 안 된다.

Controlled Drain

으로 천천히 처리해야 한다.

현재 프로젝트에서는 거대한 Traffic Platform을 만들기보다 먼저:

로그인 Rate Limit

검색 Debounce

Pagination Max Limit

Export 제한

Notification Cooldown

AI Concurrency Limit

Queue Depth/Age Monitoring

Retry Backoff

정도만 적용해도 효과가 크다.

전체 운영 흐름으로 보면:

Traffic
↓
Cache
↓
Rate Limit
↓
Admission Control
↓
Application
↓
Concurrency Limit
↓
Queue
↓
Backpressure
↓
Worker Rate Limit
↓
DB / Provider

가 된다.

그리고 Capacity를 넘기기 시작하면:

NORMAL
↓
DEGRADED
↓
OVERLOADED

상태를 인식하고 낮은 Priority 기능부터 줄인다.

결국 Rate Limiting·Backpressure의 핵심은

“최대한 많은 요청을 처리하는 것”이 아니라, 시스템이 감당할 수 있는 범위 안에서 중요한 작업을 먼저 처리하고, 과부하가 다른 계층으로 전파되기 전에 의도적으로 속도를 늦추거나 일부 작업을 거절하는 것

이다.

0개의 댓글