Spring/프로젝트 코드 리뷰

프로젝트 : CDN과 24년 선거 대비 자체 이미지 서버 개발 및 최적화

code2772 2025. 2. 14. 14:42
728x90
반응형

CDN(Content Delivery Network) 적용 및 운영 경험

CDN은 전 세계 여러 지역에 분산된 엣지 서버(Edge Server)를 통해 사용자에게 정적 및 동적 컨텐츠를 빠르고 안정적으로 전달하는 기술입니다. 대규모 트래픽을 효율적으로 분산하고, 웹사이트의 로딩 속도를 단축하며, 서버 부하를 줄이는 데 중요한 역할을 합니다.

 

프로젝트 배경

  • 24년 선거 기간 중 Kakao, RCS, MMS 메시지 대량 발송 시 서버 다운 및 전송 속도 저하 문제 발생 가능성
  • 기존 메시지 서버에서 이미지 트래픽이 혼합되어 처리되면서 부하 급증
  • 트래픽 폭증에도 안정적으로 이미지 전송을 처리할 수 있는 독립적인 이미지 서버 필요

 

✅ 주요 개발 내용

  1. 자체 이미지 서버 설계 및 구축
    • 메시지 본문과 이미지 트래픽을 분리하여 전용 서버에서 이미지 처리
    • Spring Boot 기반 비동기 API 설계로 트래픽 처리 효율 향상
  2. CDN을 활용한 부하 분산 및 전송 최적화
    • 이미지 캐싱 및 TTL 설정 최적화로 원본 서버 부하 경감
    • 엣지 서버 기반의 글로벌 분산 처리로 원거리 사용자 요청 속도 향상
    • L4/L7 로드밸런서 연동을 통한 트래픽 자동 분산 처리
  3. 자동 삭제 및 용량 최적화
    • 일정 기간이 지난 이미지 자동 삭제 기능 적용
    • 스토리지 사용량 최적화 및 운영 비용 절감

 

🔹 주요 구성 요소 설명

1️⃣ L4 로드밸런서 (트래픽 분산)

  • 클라이언트 요청을 **API 서버(API #1, API #2)**에 균등하게 배분하여 부하를 방지.
  • 특정 서버로 과부하가 집중되지 않도록 Failover 설정 적용.

2️⃣ API 서버 (비즈니스 로직 처리)

  • 클라이언트 요청을 받아 WAS 서버로 전달.
  • Spring Boot 기반 비동기 API 처리(@Async) 로 응답 속도 최적화.

3️⃣ WAS 서버 (이미지 저장 및 제공)

  • API 서버에서 받은 요청을 처리하여 디스크(DISK)에서 이미지 저장 및 제공.
  • 저장 경로를 /YY/MM/DD 형식으로 구조화하여 관리 효율성 향상.

4️⃣ 고객수용GW / 사업자수용GW

  • 고객수용GW: 클라이언트에서 요청한 URL의 유효성 검사 (URL Validation).
  • 사업자수용GW: Wget 방식으로 요청을 수행하여 이미지 제공.

5️⃣ 데이터베이스 (Oracle DB #1, DB #2)

  • GW에서 URL 유효성 검증 및 이미지 메타데이터 저장.
  • DB 샤딩 및 읽기/쓰기 분리 아키텍처 적용으로 성능 최적화.

 

✅ 성과 및 결과

서버 부하 최소화 및 안정성 보장

  • 메시지 서버에서 이미지 트래픽을 분리함으로써 서버 다운 위험 감소

전송 속도 향상

  • CDN 및 자체 이미지 서버 최적화를 통해 선거 기간 중 원활한 대량 발송 가능

스토리지 효율 개선 및 운영 비용 절감

  • 자동 이미지 삭제로 스토리지 비용 절감 및 DB 최적화
  • 로드밸런서 적용으로 서버 다운 없이 대량 트래픽 처리 가능
  • 선거 기간 중 트래픽 피크 타임에도 무중단 서비스 운영 성공

 

주요 기술 적용 및 성과

1) CDN(Content Delivery Network) 활용 – 글로벌 엣지 캐싱

💡 CDN을 활용하여 원본 서버 부하를 줄이고 이미지 전송 속도를 최적화

  • 캐싱된 이미지를 사용자에게 직접 제공하여 원본 서버로의 요청을 최소화.
  • TTL(Time To Live) 설정 최적화를 통해 불필요한 원본 서버 요청 제거.
  • 결과: 전송 속도  향상, 원본 서버 부하 감소

 

2) 로드밸런서(L4/L7) 적용 – 트래픽 분산 및 라우팅 최적화

💡 L4/L7 로드밸런서를 적용하여 안정적인 트래픽 처리

  • L4 (TCP/UDP 부하 분산) → API 서버 간 균등한 트래픽 분배.
  • L7 (애플리케이션 레벨 부하 분산) → URL을 분석하여 최적의 WAS 서버로 라우팅.
  • 결과: 트래픽이 한 곳에 몰리는 현상 방지, 서버 다운 방지

 

3) 자동 이미지 삭제 및 저장 최적화

💡 불필요한 이미지 파일을 자동 정리하여 저장 공간 확보 및 성능 최적화

  • 일정 기간(예: 30일)이 지난 이미지를 자동 삭제하여 스토리지 관리.
  • Redis 캐시 레이어 적용으로 DB 부하 감소.
  • 결과: 스토리지 비용 절감 + DB 응답 속도 개선 📊

 

4) Spring Boot 기반 비동기 처리 – 성능 향상

💡 비동기 API(@Async) 적용으로 동시 요청 처리 성능 개선

  • 클라이언트 요청 시 즉시 응답 반환 후, 백그라운드에서 이미지 처리 수행.
  • 결과: API 응답 속도 개선 + 동시 요청 처리 성능 향상

 

Spring Boot 기반 코드 예제 (실 프로젝트와 다름)

 

✅ 1. CDN을 활용한 글로벌 엣지 캐싱

CDN을 활용하면 정적 파일(이미지, CSS, JS 등)의 요청을 원본 서버가 아닌 엣지 서버에서 처리하도록 설정할 수 있습니다.

📌 예제: Spring Boot에서 CDN URL 반환하기

Spring Boot에서 업로드된 이미지 URL을 CDN 경로로 반환하도록 구성할 수 있습니다.

@RestController
@RequestMapping("/images")
public class ImageController {

    private static final String CDN_URL = "<https://cdn.example.com/images/>";

    @GetMapping("/{imageName}")
    public ResponseEntity getImageUrl(@PathVariable String imageName) {
        String cdnImageUrl = CDN_URL + imageName;
        return ResponseEntity.ok(cdnImageUrl);
    }
}

설명:

  • 클라이언트가 GET /images/sample.jpg 요청을 보내면,→ CDN URL (https://cdn.example.com/images/sample.jpg)을 반환하여 엣지 서버에서 이미지를 가져가도록 함.
  • 이를 통해 원본 서버 부하를 줄이고 빠른 이미지 전송을 가능하게 함.

 

✅ 2. L4/L7 로드밸런서 도입

로드밸런서를 활용하여 트래픽을 균등하게 분산할 수 있습니다.

📌 예제: L7 로드밸런서를 위한 Spring Boot Nginx 설정

Nginx를 사용하여 API 요청을 L7 레벨에서 라우팅하는 방식입니다.

1️⃣ nginx.conf 설정 (L7)

server {
    listen 80;

    location /api/ {
        proxy_pass <http://backend-server:8080/>;
    }

    location /images/ {
        proxy_pass <http://image-server:8081/>;
    }
}

설명:

  • /api/ 요청은 백엔드 서버(8080 포트)로 전달
  • /images/ 요청은 이미지 서버(8081 포트)로 전달
  • L7에서 요청을 분석하여 적절한 서버로 라우팅

 

✅ 3. 자동 이미지 삭제 및 저장 최적화

이미지 저장 공간을 효율적으로 관리하기 위해 일정 기간이 지난 이미지를 자동 삭제할 수 있습니다.

📌 예제: Spring Boot + Redis를 활용한 자동 이미지 삭제

1️⃣ Redis 설정 (application.yml)

spring:
  redis:
    host: localhost
    port: 6379

2️⃣ 이미지 업로드 및 캐싱

@Service
public class ImageService {

    private static final long EXPIRATION_TIME = 86400; // 1일 (초 단위)

    @Autowired
    private StringRedisTemplate redisTemplate;

    public void cacheImage(String imageName, String imageUrl) {
        redisTemplate.opsForValue().set(imageName, imageUrl, EXPIRATION_TIME, TimeUnit.SECONDS);
    }

    public String getCachedImage(String imageName) {
        return redisTemplate.opsForValue().get(imageName);
    }

    public void deleteExpiredImages() {
        Set<String> keys = redisTemplate.keys("*");
        if (keys != null) {
            keys.forEach(redisTemplate::delete);
        }
    }
}

3️⃣ 일정 시간마다 자동 삭제 (스케줄링)

@Component
public class ImageCleanupScheduler {

    @Autowired
    private ImageService imageService;

    @Scheduled(cron = "0 0 3 * * ?") // 매일 새벽 3시 실행
    public void cleanExpiredImages() {
        imageService.deleteExpiredImages();
    }
}

설명:

  • Redis를 캐시 레이어로 사용하여 최근 요청된 이미지를 저장
  • 24시간 후 자동 삭제 → 스토리지 공간을 절약
  • 스케줄링을 사용하여 매일 새벽 3시에 만료된 이미지 삭제

 

✅ 4. Spring Boot 기반 비동기 처리

Spring의 @Async 기능을 사용하여 이미지 처리를 비동기 방식으로 수행하면 응답 속도를 최적화할 수 있습니다.

📌 예제: 비동기 이미지 처리

1️⃣ @Async를 활용한 비동기 이미지 처리

@Service
public class AsyncImageService {

    private static final Logger logger = LoggerFactory.getLogger(AsyncImageService.class);

    @Async
    public CompletableFuture<String> processImage(String imageUrl) {
        try {
            // 이미지 처리 로직 (예: 썸네일 생성, 압축)
            Thread.sleep(2000); // 2초 대기 (예제용)
            logger.info("이미지 처리 완료: " + imageUrl);
            return CompletableFuture.completedFuture("처리된 이미지 URL: " + imageUrl);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return CompletableFuture.completedFuture("처리 실패");
        }
    }
}

2️⃣ 컨트롤러에서 비동기 처리 실행

@RestController
@RequestMapping("/async-images")
public class AsyncImageController {

    @Autowired
    private AsyncImageService asyncImageService;

    @GetMapping("/{imageUrl}")
    public CompletableFuture<String> processImage(@PathVariable String imageUrl) {
        return asyncImageService.processImage(imageUrl);
    }
}

설명:

  • @Async를 활용하여 비동기적으로 이미지 처리
  • 클라이언트 요청 시 즉시 응답을 반환하고 백그라운드에서 이미지 처리 수행
  • CPU를 효율적으로 사용하여 처리 속도 최적화

 

정리

기능 기술 주요 효과

CDN을 활용한 글로벌 엣지 캐싱 CDN URL 제공 원본 서버 부하 감소, 전송 속도 향상
로드밸런서(L4/L7) 도입 Nginx 설정 트래픽 균등 분산, 서버 과부하 방지
자동 이미지 삭제 및 저장 최적화 Redis 캐싱, 스케줄링 불필요한 이미지 제거, 저장 공간 최적화
Spring Boot 기반 비동기 처리 @Async API 처리 빠른 응답 속도, 서버 리소스 효율적 사용

 

번외 주요 용어 추가 설명

 

1. CDN (Content Delivery Network)

CDN은 전 세계에 분산된 엣지 서버(Edge Server)를 활용하여 웹 콘텐츠(이미지, CSS, JavaScript, 동영상 등)를 사용자에게 빠르고 안정적으로 제공하는 기술입니다.

핵심 개념

  • 엣지 서버(Edge Server): 사용자와 가까운 위치에서 캐싱된 콘텐츠를 제공하는 서버
  • 캐싱(Caching): 자주 요청되는 데이터를 저장하여 원본 서버의 부하를 줄이고 응답 속도를 높이는 기술
  • TTL(Time-To-Live): 캐싱된 데이터가 유지되는 시간으로, 적절한 TTL 설정이 성능 최적화에 중요함
  • GSLB(Global Server Load Balancing): 지역별 최적의 서버로 트래픽을 분산하는 로드밸런싱 기술

CDN 도입의 이점

  • 서버 부하 감소: 원본 서버로 가는 트래픽을 줄여 성능 최적화
  • 전송 속도 향상: 사용자와 가까운 서버에서 응답하므로 대기 시간 최소화
  • 대량 트래픽 처리 가능: 트래픽을 여러 엣지 서버로 분산하여 대규모 요청을 효율적으로 처리
  • DDoS 공격 방어: 분산 구조 덕분에 특정 서버에 집중된 공격을 완화

 

2. L4/L7 로드밸런서

로드밸런서는 네트워크 트래픽을 여러 서버로 분산하여 시스템의 성능과 안정성을 높이는 장치입니다.

L4 로드밸런서 (Layer 4, 전송 계층)

  • IP 주소 및 포트 기반으로 트래픽을 분산
  • 클라이언트의 요청을 서버 상태에 따라 균등 분배
  • 빠른 처리 속도를 제공하지만, 애플리케이션 레벨의 트래픽 분석이 어려움

L7 로드밸런서 (Layer 7, 애플리케이션 계층)

  • HTTP, HTTPS, WebSocket 등 프로토콜을 분석하여 트래픽 분산
  • 특정 URL, 쿠키, 헤더 값에 따라 맞춤형 분배 가능
  • 트래픽의 정교한 제어가 가능하여 웹 애플리케이션에서 자주 활용됨

3. Redis Cluster

Redis는 메모리 기반의 NoSQL 데이터베이스로, 빠른 데이터 처리가 필요할 때 사용됩니다.

Redis Cluster의 특징

  • 샤딩(Sharding) 지원: 여러 노드에 데이터를 분산 저장하여 성능 향상
  • 자동 Failover: 특정 노드가 장애를 일으켜도 클러스터가 자동으로 복구
  • 고속 캐싱 기능: 데이터베이스 부하를 줄이면서 빠른 조회 속도 제공

4. Kafka

Kafka는 대량의 데이터를 실시간으로 처리하는 분산 메시징 시스템입니다.

Kafka의 주요 개념

  • 프로듀서(Producer): 데이터를 생성하여 Kafka에 전송
  • 컨슈머(Consumer): 데이터를 읽어가는 클라이언트
  • 토픽(Topic): 데이터가 저장되는 공간
  • 파티션(Partition): 하나의 토픽을 여러 개의 분할된 저장소로 구성하여 확장성 제공

Kafka를 활용하면 대량의 메시지를 빠르고 안정적으로 처리할 수 있어, 비동기 데이터 처리 및 이벤트 스트리밍에 적합합니다.

반응형