Notice
Recent Posts
Recent Comments
Link
250x250
반응형
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- graph
- 정보보안기사
- 보안솔루션
- Database
- 보안
- 프로그래밍
- 그래프 데이터베이스
- GraphDB
- SQLD
- IT보안
- 사이버보안
- concurrency
- 사이버 보안
- 보안 분석
- security
- cypher
- 위협 탐지
- go
- neo4j성능
- 그래프데이터베이스
- 정리
- 정보보안
- 공부
- 해킹
- 랜섬웨어
- 데이터모델링
- Neo4j
- Golang
- 자격증
- 시험
Archives
- Today
- Total
Jamie the programmer
Go에서 Throttling과 Debouncing? 요청은 줄이고 효율은 높이자! 본문
Contents
접기
반응형
1. Rate Limiting이란?
- *속도 제한(Rate Limiting)*은 리소스에 대한 접근을 일정 시간당 특정 횟수로 제한하는 메커니즘을 말한다.
- 예: API 요청, 디스크 I/O, 네트워크 트래픽 등
- 주요 목적
- 서비스의 품질 유지: 지나치게 많은 요청이 몰려와도 안정적으로 처리
- 악의적 공격 방어: 무차별 암호 대입 공격(Brute force)이나 Dos/DDoS 등 방지
- 공정성(Fairness): 특정 사용자나 특정 작업이 과도하게 자원을 사용하지 않도록 제어
- 시스템 부하 관리: 지나친 트래픽으로 인한 시스템 장애 예방
Go에서는 고루틴(goroutine), 채널(channel), 그리고 **티커(ticker)**를 활용하여 쉽게 Rate Limiting 기능을 구현할 수 있다.
2. Throttling & Debouncing
2.1 Throttling(쓰로틀링)
- 연속적으로 들어오는 요청을 일정 주기로 하나씩만 처리하도록 하는 기법
- 예: 키보드 이벤트가 연속적으로 들어올 때, 1초마다 한 번씩만 처리
2.2 Debouncing(디바운싱)
- 연속적인 요청 중에서 마지막 요청만 처리하는 기법
- 예: 검색창 자동완성에서 사용자가 입력을 멈췄을 때 마지막 입력만 처리
Throttling과 Debouncing은 비슷해 보이지만, 실제 적용 시점과 로직이 다르다.
3. 대표적인 Rate Limit 알고리즘
Rate Limiting을 구현하기 위한 알고리즘은 여러 가지가 있다. 각 알고리즘은 장단점과 사용 목적이 다르므로, 상황에 맞게 선택해야 한다.
- Leaky Bucket Algorithm
- 물이 새는 양동이처럼 요청을 일정 속도로 처리
- 일정 속도로만 빠져나가므로 버스트(순간 집중 트래픽)에 대응하기 어려울 수 있음
- Fixed Window Algorithm
- 고정된 시간 단위(예: 1초, 1분)별로 카운트를 해서 요청 제한
- 경계 시점에 요청이 몰릴 수 있는 문제(“경계 문제”) 발생 가능
- Sliding Window Algorithm
- 이동하는 시간 창을 기준으로 요청 횟수를 계산
- Fixed Window의 경계 문제를 어느 정도 해소
- Token Bucket Algorithm
- 일정 속도로 토큰이 버킷에 채워지고, 요청 시 토큰을 소모
- 버킷에 토큰이 없으면 요청을 대기하거나 거부
- 버스트(단기간 몰리는 트래픽)를 어느 정도 허용하면서도 평균 속도를 제한
자세한 내용은 4 Rate Limit Algorithms Every Developer Should Know 문서를 참고하자.
4. Go에서 Rate Limit 구현
Go 표준 라이브러리 확장 모듈인 golang.org/x/time/rate는 내부적으로 Token Bucket Algorithm을 사용한다.
- go.uber.org/ratelimit는 Leaky Bucket Algorithm 기반으로 Rate Limiting을 제공하는 라이브러리다.
4.1 Token Bucket 예시 (golang.org/x/time/rate)
import (
"fmt"
"time"
"golang.org/x/time/rate"
)
func main() {
// 초당 1회 요청 허용, 버스트(동시 요청) 1회
limiter := rate.NewLimiter(1, 1)
for i := 0; i < 5; i++ {
// 요청이 가능해질 때까지 대기
err := limiter.Wait(nil)
if err != nil {
fmt.Println("Error:", err)
}
fmt.Printf("Request #%d at %v\\\\n", i, time.Now())
}
}
5. 직접 구현한 throttling 패키지 소개
5.1 패키지 개요
- 목적: 특정 도메인/경로(API)별로 Rate Limit를 적용하고, IP나 Cloud Account 단위로도 트래픽을 제한
- 구성 요소
- Throttling 구조체: Rate Limit의 전반적인 설정
- Limiter 구조체: golang.org/x/time/rate.Limiter를 내부적으로 사용
- Url 구조체: 도메인과 경로를 관리, 경로 변수(ContainsPathVar) 지원
- safemap.SafeMap: 동시성 안전한 맵 구조를 사용하여 여러 고루틴에서 안전하게 접근 가능
5.2 주요 설정(옵션) 메서드
- WithLimitBaseIp(), WithLimitBaseCloudAccount(), WithLimitBaseService()
- Rate Limit의 기준(Identifier)을 IP, Cloud Account, 혹은 Service로 설정
- WithLimiter(...)
- 사용할 Limiter 목록을 등록
- 내부적으로 rate.NewLimiter(rate.Every(time.Second), 1) 형태로 Token Bucket 생성
- WithUrl(...), WithUrlIgnore(...)
- Rate Limit을 적용할 URL, 제외할 URL을 등록
5.3 사용 예시
func main() {
throttling.Register(
throttling.WithLimitBaseIp(),
throttling.WithUrl(
&throttling.Url{
Domain: "api.ucloudbiz.olleh.com",
Path: "/d1/identity/auth/tokens",
},
// ... 필요한 경로 추가 ...
),
throttling.WithUrlIgnore(
&throttling.Url{
Domain: "192.168.219.158:14268",
Path: "/api/traces",
},
),
throttling.WithLimiter(
&throttling.Limiter{
Identifier: throttling.LimitBaseIP,
RateLimiter: rate.NewLimiter(rate.Every(time.Second), 1),
},
),
)
throttling.Activate()
// 이 이후부터는 http.DefaultTransport가 교체되어,
// 등록된 URL로 가는 요청은 Rate Limit이 적용됨
}
5.4 실제 동작 시 문제점 및 보완
- 1초에 1건씩 호출 설정했음에도, 실제로는 간헐적으로 1초 미만 간격으로 요청이 처리되어 429 오류가 발생할 수 있다.
- 원인: Wait()가 정확히 1초를 보장하지 않고, OS 스케줄링이나 시간 측정 오차 등으로 인해 1초보다 조금 빠른 시점에 다음 요청을 허용할 수 있음
- 해결책:
- 여유 시간을 더 두는 방식(1초 + α)
- 별도의 타이머 혹은 Sleep을 통해 실제 1초가 지났음을 보장
- 커스텀 로직으로 요청 시간 간격을 정확히 계산해서 보정
이 문제로 인해 다른 방식을 모색하거나, Rate Limit 기준 시간에 여유 버퍼를 주는 방법 등을 고민할 수 있다.
6. 결론
- Rate Limiting은 트래픽 제어와 시스템 보호를 위해 필수적인 기능이다.
- Go에서는 표준 라이브러리와 오픈소스 라이브러리를 통해 다양한 알고리즘을 간편히 구현할 수 있다.
- 직접 작성한 throttling 패키지처럼, 세부 요구사항(IP·CloudAccount·Service 단위 제어 등)에 맞춰 커스텀 로직을 추가하는 것도 가능하다.
- 다만, 실제 환경에서는 정확한 시간 측정 오차나 OS 스케줄링 등의 요인으로 인해 예상치 못한 이슈(429 에러 등)가 발생할 수 있으므로, 여유 버퍼나 추가 로직을 고려해야 한다.
참고 자료
728x90
반응형
'programming > golang' 카테고리의 다른 글
Go 개발 환경 정복하기: 패키지, 모듈, 그리고 워크스페이스 (0) | 2025.03.10 |
---|---|
Go에서 Rate Limiting으로 공격 방어하기: Token Bucket vs Leaky Bucket (0) | 2025.03.10 |
고루틴도 편히 쉬어야 한다! Go에서 Graceful Shutdown 구현하기 (0) | 2025.03.10 |
Go 언어, 이렇게 쓰면 GOAT 된다 - 실전 꿀팁 12개! (0) | 2025.03.10 |
Go 코드에서 UML 다이어그램 뽑아내기 – 개발자 생산성 200% UP! (0) | 2025.03.07 |