얼마 전 회식자리에서 팀원이랑 이야기하다가 "CPU 쓰로틀링" 이야기가 나왔습니다. 평소 같았으면 그냥 넘겼을 주제지만, 자꾸 꼬리에 꼬리를 무는 질문들이 떠오르기 시작했죠.
"CPU 쓰로틀링이 뭐였더라...?"
"내가 알고 있는 디바운싱이나 쓰로틀링이랑 같은건 아닌데 뭐였지..?"
순간 머릿속이 복잡해졌고, ‘오케이! 이참에 블로그에 제대로 정리하면서 확실히 하자!’ 라는 결심이 섰습니다.
실무에서 마주치는 디바운싱(Debouncing), 쓰로틀링(Throttling), 그리고 CPU 쓰로틀링까지 개념을 다시 한번 정리해보았습니다.
디바운싱은 일정 시간 동안 연속해서 발생하는 작업 중 가장 마지막 요청만 처리하는 방식입니다. 이 개념은 주로 클라이언트에서 사용되지만, 백엔드에서도 대량 요청을 효율적으로 제어할 때 활용됩니다.
사용자가 필터나 조건을 바꿀 때마다 요청이 들어오면, 서버는 매번 DB 조회를 해야 합니다. 이때 디바운싱 로직을 걸어두면 요청이 잠시 멈출 때까지 대기한 후, 마지막 요청만 수행하도록 만들 수 있습니다.
Spring WebFlux나 Kotlin Coroutine 기반에서 debounce()
오퍼레이터로 쉽게 처리할 수 있습니다.
flowOf("a", "ab", "abc")
.debounce(300)
.collect { value ->
println("처리된 값: $value")
}
쓰로틀링은 단위 시간당 처리 횟수를 제한하는 방식입니다. REST API 서버에서 다음과 같은 형태로 많이 사용됩니다.
예를 들어 사용자가 초당 10번 이상 특정 API를 호출하면 서버에 과부하가 생길 수 있습니다. 쓰로틀링을 걸어두면 초과 요청은 거절하거나 큐에 대기시킬 수 있습니다.
대표적인 구현 방식:
// Bucket4j를 이용한 쓰로틀링 예제
Bandwidth limit = Bandwidth.classic(10, Refill.greedy(10, Duration.ofSeconds(1)));
Bucket bucket = Bucket4j.builder().addLimit(limit).build();
if (bucket.tryConsume(1)) {
// 요청 처리
} else {
// Too Many Requests 응답
}
항목 | 디바운싱 | 쓰로틀링 |
---|---|---|
실행 조건 | 일정 시간 대기 후 마지막 요청 처리 | 일정 시간 간격으로 요청 제한 |
사용 예시 | 검색 조건 API, 이벤트 취합 | API 호출 제한, 리소스 보호 |
장점 | 불필요한 연산 제거 | 시스템 안정성 확보 |
단점 | 반응성 떨어질 수 있음 | 요청 일부 거절될 수 있음 |
디바운싱, 쓰로틀링은 애플리케이션 레벨에서의 제어지만, CPU 쓰로틀링은 운영체제 또는 하드웨어에서 일어나는 성능 제어입니다.
CPU의 온도가 너무 높아지거나, 전력 제한 조건에 도달하면 시스템은 CPU 클럭 속도를 자동으로 낮춥니다. 이를 통해 과열로 인한 시스템 장애를 방지합니다.
클럭 속도와 전력 소비 간의 관계를 나타낸 이미지 (DVFS: Dynamic Voltage and Frequency Scaling)
성능 문제는 종종 예상치 못한 병목 지점에서 발생합니다. 디바운싱과 쓰로틀링은 클라이언트만의 개념이 아니라는 점, 그리고 CPU 쓰로틀링까지 이해하고 있으면 서비스의 안정성과 확장성을 높이는 데 큰 도움이 되지 않을까요?