본문 바로가기
Backend

[Backend] 트래픽 폭주를 막는 4가지 방법 (Rate Limiting, Caching, Asynchronous Processing, Load Balancing)

by SeungyubLee 2026. 4. 25.

 

트래픽은 언제든 폭발할 수 있다.

서비스를 운영하다 보면 이런 상황이 반드시 온다.

  • 인기 이벤트 오픈 (예:콘서트 티켓팅)
  • 특정 시간대 트래픽 집중 (출근 시간, 점심 시간)
  • 외부 유입 급증 (광고, 바이럴)

특히 티켓팅 시스템이나 쇼핑몰에서는
짧은 시간에 수만~수십만 요청이 몰리면서 서버가 다운되는 상황이 발생할 수 있다.
이때 단순히 서버 스펙을 올리는 것만으로는 해결되지 않는다.
요청 자체를 제어하고, 분산하고, 최적화하는 구조가 필요하다.
이번 글에서는 백엔드 관점에서 트래픽 폭주를 막는 4가지 방법에 대해 정리한다.


 Rate Limiting (요청 제한)

특정 사용자(IP 또는 API Key)가 일정 시간 동안 보낼 수 있는 요청 수를 제한하는 방식

핵심 : 과도한 요청 자체를 막는다.

 

✅ Java 예시 (간단한 Rate Limiting)

실제 서비스에서는 TTL, Sliding Window, Token Bucket 등의 알고리즘을 사용하여

시간 기반으로 요청을 제어해야 한다.

import java.util.concurrent.ConcurrentHashMap;

public class RateLimiter {

    // 간단한 예제로, 시간 기반 초기화(TTL)는 생략
    // 사용자별 요청 횟수를 저장하기 위한 Map (key:userId, value:요청 횟수)
    private static ConcurrentHashMap<String, Integer> requestCount = new ConcurrentHashMap<>();

    // 최대 허용 요청 횟수
    private static final int LIMIT = 5;

    public static boolean allowRequest(String userId) {

        // 최초 요청 시 카운트 초기화
        requestCount.putIfAbsent(userId, 0);

        int count = requestCount.get(userId);

        // 제한 횟수 초과 시 요청 차단
        if (count >= LIMIT) {
            return false;
        }

        // 요청 횟수 증가
        requestCount.put(userId, count + 1);

        return true;
    }
}

 

✅ Controller 적용 예시

@GetMapping("/api/request")
public ResponseEntity<String> request(@RequestParam String userId) {

    // RateLimiter를 통해 요청 허용 여부 판단
    if (!RateLimiter.allowRequest(userId)) {
        // 429 Too Many Requests → 요청 과다
        return ResponseEntity.status(429).body("Too Many Requests");
    }

    return ResponseEntity.ok("Success");
}

 

<예방 효과>

  • 특정 사용자 폭주 요청 차단
  • DDoS 유사 트래픽 완화
  • 서버 과부하 방지

 Caching (캐싱) - DB 보호

DB 조회 결과를 메모리(캐시)에 저장하고, 같은 요청이 들어오면 DB 대신 캐시에서 응답한다.

핵심 : 동일한 요청에 대해 DB 조회를 반복하지 않도록 한다.

 

✅ Java + Redis 캐싱 예시

@Service
public class ProductService {

    private final RedisTemplate<String, String> redisTemplate;

    public ProductService(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public String getProduct(String productId) {

        String key = "product:" + productId;

        // 1. 캐시 조회 (캐시 히트 시 DB 조회 없이 바로 반환)
        String cached = redisTemplate.opsForValue().get(key);

        if (cached != null) {
            return cached;
        }

        // 2. 캐시 미스 → DB 조회
        String product = "DB에서 가져온 상품 정보";

        // 3. 조회 결과를 캐시에 저장 (TTL 60초, DB 부하 감소 목적)
        redisTemplate.opsForValue().set(key, product, 60, TimeUnit.SECONDS);

        return product;
    }
}

 

<예방 효과>

  • DB 부하 감소 (가장 중요)
  • 응답 속도 향상
  • 트래픽 급증 시 DB 보호

(실무에서는 Redis가 거의 표준)


 Asynchronous Processing (비동기 처리) - 큐

요청을 바로 처리하지 않고 큐(Queue)에 넣고 나중에 처리

핵심 : 사용자는 빠르게 응답 받고, 실제 작업은 뒤에서 처리

 

✅ Java 비동기 처리 (@Async)
@Async는 간단한 비동기 처리를 위한 방식으로, 실제 대규모 서비스에서는

Kafka, RabbitMQ 등의 메세지 큐를 사용하여 안정적인 비동기 처리 및 장애 대응을 수행한다.

@Service
public class OrderService {

    // 간단한 예제로, 메세지 큐 기반 비동기 처리는 다루지 않음
    // 비동기 처리 (@Async - 별도 스레드 풀에서 실행)
    @Async
    public void processOrder(String orderId) {
        try {
            
            // 오래 걸리는 작업 코드 구현 (예:결제 처리, DB 저장, 외부 API 호출 등)
            
            Thread.sleep(3000);

            System.out.println("주문 처리 완료:" + orderId);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 인터럽트 상태 복구
        }
    }
}

 

 Controller

@PostMapping("/order")
public ResponseEntity<String> order(@RequestParam String orderId) {

    // 비동기 작업 실행
    orderService.processOrder(orderId);

    // 실제 작업 완료를 기다리지 않고 즉시 응답
    return ResponseEntity.ok("주문 요청 접수 완료");
}

 

<예방 효과>

  • 요청 처리 지연 방지
  • 서버 블로킹 감소
  • 트래픽 순간 폭증 완화

(실무에서는 Kafka / RabbitMQ 같은 메세지 큐 사용)


 Load Balancing (서버 이중화) - 인프라

여러 서버에 트래픽을 분산시켜 특정 서버에 부하가 집중되지 않도록 하는 방식

핵심 : 여러 서버에 요청을 분산하여 특정 서버에 부하가 집중되지 않도록 한다.

 

 Nginx 기반 로드 밸런싱 (온프레미스 방식)

온프레미스 환경에서는 Nginx와 같은 소프트웨어를 통해 로드 밸런싱을 직접 구성할 수 있다.

http {
    upstream backend {
        # 트래픽을 분산할 서버 목록
        server 192.168.0.1:8080;
        server 192.168.0.2:8080;
    }

    server {
        listen 80;

        location / {
            # 클라이언트 요청을 backend 그룹으로 전달
            proxy_pass http://backend;
        }
    }
}

 

 

<예방 효과>

  • 특정 서버 과부하 방지
  • 트래픽 분산 처리
  • 서버 장애 시 서비스 유지 가능

 

 AWS ELB (Elastic Load Balancer)

AWS Elastic Load Balancer는 AWS에서 제공하는 관리형 로드 밸런서 서비스로

서버를 직접 구성하지 않아도 트래픽을 자동으로 여러 서버(EC2)에 분산해준다.

또한, 헬스 체크(Health Check)를 통해 장애가 발생한 서버를 자동으로 제외하여 안정적인 서비스 운영이 가능하다.

 

 

<예방 효과>

  • 서버 자동 확장 (Auto Scaling 연동)
  • 장애 서버 자동 우회 (Failover)
  • 트래픽 급증에도 안정적인 처리

실무 포인트 (Nginx vs AWS ELB)

항목 Nginx AWS ELB
관리 직접 설정 AWS가 관리
확장성 수동 확장 Auto Scaling
장애 대응 직접 구성 자동 Failover
운영 난이도 높음 낮음