기타

[3차시] 스프링 부트 내장 톰캣 최적화 및 NGINX 연계 : 효율적 요청 처리 환경 만들기

킨글 2025. 3. 17. 23:03
  • 스프링 부트 내장 톰캣의 주요 기능
    • HTTP 요청 및 응답 처리 : GET, POST 등의 HTTP 메서드 처리
    • SSL/TLS를 통한 HTTPS 지원
    • 스레드 풀 관리 : 동시 요청 처리를 위한 스레드 관리 기능
    • 압축 및 Keep-Alive와 같은 네트워크 최적화 기능
  •  내장 Tomcat과 일반 Tomcat의 차이
    • [내장] 애플리케이션 내부에서 실행
      VS [외장] 별도의 서버로 설치
    • [내장] JAR로 패치징
      VS [외장] WAR로 배포
    • [내장] 빠른 테스트 및 배포 
      VS [외장] 대규모 인프라 관리에 유리
    • [내장] 어플리케이션 중심 설정 관리 -> 개발과 환경별 대응이 유연
      VS [외장] 서버 중심의 설정 관리 -> 통합적이고 운영자 친화적
  • 내장 톰캣의 기본 설정
    • 스레드 풀 : 기본적으로 200개의 스레드 처리
      server.tomcat.threads.max=200
    • 포트 : 기본적으로 8080 포트에서 실행
      server.port=8080
    • 타임아웃 : 기본 연결 타임아웃 설정
      server.connection-timeout=20000 (20초)
  • 내장 톰캣 최적화 방안
    • 스레드 풀 최적화 : 요청 처리 효율을 높이기 위한 스레드 관리
    • 커넥터 설정 : Connection Timeout, Keep Alive Timeout 설정 최적화
    • 압축 설정 : Gzip, Brotli 등을 사용해 네트워크 트래픽 감소
    • 메모리 관리 : JVM 옵션을 통한 메모리 사용 최적화

내장 톰캣의 스레드 풀 최적화

  • 스레드 풀 설정 기본 요소
    • Max Threads : 최대 스레드 수 (기본값 : 200)
      • 최적의 max Threads 값은 서버 하드웨어와 트래픽 패턴에 따라 다름
        (트래픽 분석이 필요)
      • 너무 낮게 설정하면 과부하 시 요청 대기 시간이 길어짐
      • 너무 높게 설정하면 메모리 부족 및 Context Switching으로 인해 성능 저하 발생
      • 트래픽 분석 후 적정 값으로 설정 필요 
    • Min Spare Threads : 유휴 상태에서 유지할 최소 스레드 수 (기본값 : 10)
      • 요청이 발생하면 미리 준비된 스레드를 사용해 빠르게 응답
      • 너무 낮게 설정 시 초기 요청 처리 속도가 느려질 수 있음
      • 트래픽 패턴에 따라 적절한 설정 필요
    • Accept Count : 스레드가 모두 사용 중일 때 대기열에 넣을 수 있는 최대 요청 수 (기본값 : 100)
      • 스레드가 모두 사용 중일 때 대기할 수 있는 요청의 수
      • 대기열이 가득 차면 추가 요청은 거절됨
      • 과부하 상황을 대비해 충분히 큰 값으로 설정 필요
      • 너무 큰 값 설정 시, 대기 시간이 길어질 수 있음
    • Keep Alive Time : 유휴 상태 스레드의 유지 시간
      • 동적 확장 : 요청 증가 시 새로운 스레드 생성
      • 동적 감소 : 유휴 스레드가 일정 시간 유지되면 해제
      • 자원 효율성을 높이기 위한 핵심 기능
      • 유휴 상태의 keep Alive Time을 적절히 설정하여 최적화
  • 스레드 풀과 CPU 사용률
    • 스레드가 많을수록 Context Switching 빈도가 증가
    • CPU 리소스의 과도한 사용으로 성능 저하 발생
    • CPU 코어 수와 스레드 수의 비율을 적절히 맞춰야 함
    • 일반적으로 CPU 코어 수의 2배에서 4배 정도의 스레드 수 추천
    • 실제 서버 성능 테스트를 통해 최적의 스레드 수 조정 필요
  • 스레드 풀 설정의 성능 영향
    • 스레드 풀이 너무 작으면 : 동시 처리량 부족 -> 응답 시간 증가 
    • 스레드 풀이 너무 크면 : 서버 자원 낭비 및 성능 저하
    • Accept Count가 가득 차면 새로운 요청이 거절될 수 있음
    • 모니터링 도구를 사용해 스레드 풀 상태를 실시간으로 관찰
    • 필요 시 스케일 아웃(서버 추가)로 부하 분산
  • 스레드 풀 크기 최적화
    • 어플리케이션의 트래픽 패턴 파악
    • CPU 코어 수와 메모리 용량에 맞춘 스레드 풀 설정
    • 부하 테스트를 통해 적정 값 도출 
  • 스레드 풀 모니터링
    • Spring Boot Actuator를 통한 스레드 풀 모니터링
    • 실시간 트래픽에 맞춰 스레드 풀 상태 확인
    • 문제가 발생했을 때의 사전 조치 가능

커넥트 설정 최적화 및 압축

  • 커넥터 설정의 주요 요소
    • Connection Timeout : 요청을 처리할 때 연결을 대기하는 시간
      • 클라이언트와 서버 간 연결 유지 시간 설정
      • 너무 짧으면 요청 중단, 너무 길면 자원 낭비
      • 적절한 타임아웃 값 설정 필요
        : 트래픽 패턴 분석 후 최적의 값 결정
    • Keep Alive Timeout : 커넥션 유지 시간 설정
      • 연결 재사용을 통해 네트워크 성능 향상
      • 요청마다 새로운 연결을 설정하지 않고, 기존 연결을 유지
      • Keep-Alive 타임아웃과 최대 요청 수 설정 필요
      • 유지 시간이 길 경우, 연결이 불필요하게 점유될 수 있음
    • Max Connections : 동시에 수용할 수 있는 최대 연결 수 
      • 트래픽이 많을 경우 이 값을 늘려야 과부하 방지 가능
    • Protocol : HTTP/1.1, HTTP/2 등의 프로토콜 설정
  • 네트워크 설정 최적화
    • 네트워크 버퍼 크기 설정
      server.tomcat.max-http-post-size
    • 네트워크 스레드 수 조정
      server.tomcat.threads.max
    • 대량의 데이터 처리 성능 향상
  • 압축 설정 적용 방법
    • application.properties에서 설정 가능
      • server.compression.enabled=true
        server.compression.mime-types=text/html,text/plain,application/json
        server.compression.min-response-size=1024
    • Gzip 압축을 기본으로 사용
    • min-response-size로 압축할 최소 응답 크기 설정 (큰 데이터만 압축 가능)
  • 압축 유형과 선택 기준
    • Gzip : 가장 많이 사용되며 대부분의 브라우저에서 지원
      • 호환성이 좋고, 속도와 압축률이 균형 잡힘
    • Brotli : Google이 개발한 압축 기술로, Gzip보다 더 높은 압축률 제공
      • 압축률이 높아 정적 리소스(예 : HTML, CSS, JS)에 적합
    • 압축 설정은 리소스 유형과 사용자 환경에 따라 결정 
  • 커넥터와 압축 설정의 상호작용
    • Connection Timeout과 Keep Alive Timeout은 압축의 성능에 영향을 미침
    • 압축 적용 시 CPU 사용률 증가 가능성
    • 네트워크 부하 감소를 위해 압축 설정과 연결 설정의 균형 필요
    • 적절한 타임아웃 설정으로 압축된 데이터의 신속한 전송 가능
  • 톰캣 압축 설정 최적화
    • 압축 사용 : GZIP을 통해 데이터 압축
    • 최소 응답 크기 설정으로 작은 데이터는 압축하지 않음
    • MIME 타입을 통해 특정 콘텐츠만 압축 가능

NGINX 연계를 통한 성능 최적화

 

  • Nginx와 톰캣 연계 개요 
    • Nginx는 리버스 프록시 역할을 수행
    • 정적 콘텐츠는 Nginx가 처리, 동적 콘텐츠는 톰캣이 처리 
    • 성능 최적화 및 리소스 효율성 향상
  • Nginx와 톰캣의 연계 구성
    • Nginx를 리버스 프록시로 설정
    • 톰캣에 요청을 프록시로 전달
    • Nginx에서 SSL 종료 처리
server {
	listen 80;
    server_name example.com;
        
    location / {
    	proxy_pass http://localhost:8080; # 톰캣에 요청 전달
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwared-For $proxy_add_x_forwaded_for;
        proxy_set_header X-Forwared-Proto $scheme;
    }
    
    # 정적 파일 처리
    location /static/ {
    	root /var/www/html;
    }
}
  • 부하 분산을 통한 성능 최적화
    • Nginx가 여러 톰캣 인스턴스에 요청 분배
    • 라운드 로빈, Least Connections 등 부하 분산 방식
    • 처리량 증대 및 가용성 향상
upstream backend {
	server 192.168.0.101:8080; # 첫 번째 톰캣 인스턴스
    server 192.168.0.102:8080; # 두 번째 톰캣 인스턴스
}

server {
	listen 80;
    server_name example.com;
    
    location / {
    	proxy_pass http://backend; # 부하 분산을 통한 요청 전달
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
  • SSL 종료를 통한 HTTPS 성능 최적화
    • Nginx가 SSL 암호화/복호화 처리 
    • 톰캣은 비암호화된 요청만 처리
    • HTTPS 트래픽 처리 시 성능 향상 
  • 캐싱을 통한 성능 최적화
    • Nginx에서 정적 파일 및 API 응답 캐싱
    • 캐시를 통해 톰캣 요청 감소 및 응답 시간 단축
    • 동적 콘텐츠 캐싱도 가능
server {
	location /static/ {
    	root /var/www/html;
        expires 30d; # 30일 동안 캐시 유지
    }
    
    location /api/ {
    	proxy_pass http://localhost:8080;
        proxy_cache my_cache;
        proxy_cache_valid 200 10m; # 200 OK 응답을 10분 동안 캐시
    }
}

 

  • HTTP/2 지원을 통한 성능 최적화
    • 다중화(Multiplexing) : 하나의 연결에서 여러 요청을 동시에 처리
    • 헤더 압축 : 전송되는 HTTP 헤더의 크기를 줄여 성능 향상
    • 서버 푸시 : 서버가 클라이언트 요청 전에 리소스를 푸시할 수 있음
server {
	listen 443 ssl http2;
    server_name example.com;
    
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate /etc/nginx/sssl/server.key;
    
    location / {
    	proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
    }
}
  • Rate Limiting을 통한 보안 및 성능 최적화
    • 과도한 요청을 제한해 자원 남용 방지
    • DDos 공격 방어 및 서버 부하 완화
    • 특정 클라이언트 요청 제한 가능
http {
	limit_req_zone $binary_remote_addr zone=mylimit; 10m rate=10r/s; # 1초당 10개의 요청 허용
    
    server {
    	location / {
        	limit_req zone=mylimit burst=20; # 최대 20개의 버스트 요청 허용
            proxy_pass http://localhost:8080;
        }
    }
}