실무 때 고민할 만한 부분

1. Servlet 초기화 시간 : 요청 시 초기화 vs 서버 기동시 초기화

요청 시 초기화(Lazy Initialization) - 기본 동작

  • 서블릿 컨테이너는 처음으로 해당 서블릿에 대한 요청이 들어왔을 때 서블릿 객체를 생성하고 init() 메서드를 호출한다.

  • 즉, 초기화는 요청이 오기 전까지 지연(Lazy) 된다.

  • 이 동작은 기본적으로 모든 서블릿에 적용된다.

장점

  • 서버 시작 시간 단축

    • 서버 시작 시 서블릿 객체를 초기화하지 않으므로, 서버 부팅 속도가 빠르다.

    • 초기화가 필요한 서블릿이 많거나 무거운 작업을 포함할 때 효과적

  • 불필요한 초기화 방지

    • 요청이 없는 서블릿은 초기화되지 않으므로, 메모리와 CPU 자원을 절약할 수 있다.

    • 테스트 단계에서 사용되지 않는 서블릿이 초기화되는 일을 방지

단점

  • 첫 요청의 지연

    • 첫 요청 시 서블릿 객체 생성 및 초기화가 동시에 이루어지므로 응답 시간이 길어질 수 있다.

    • 초기화 작업이 오래 걸릴 경우 사용자 경험이 저하된다.

  • 초기화 실패의 위험

    • 첫 요청 시 초기화에 실패하면 해당 요청에 대한 처리가 실패로 끝날 수 있다.

    • 이는 요청이 많이 몰리는 시점에서 장애를 유발할 가능성을 증진시킨다.

적합한 상황

  • 서버 부팅 시간이 중요한 환경. (Auto Scaling)

  • 서블릿이 드물게 사용되거나, 특정 요청에서만 호출되는 경우

서버 시작 시 초기화(Eager Initialization)

  • 특정 서블릿을 서버 시작 시 미리 초기화하도록 설정할 수 있다.

  • 이를 위해서 @webservlet 어노테이션이나 web.xml 파일에서 load-on-startup 설정을 사용한다.

  • load-on-startup 이 양의 정수 값이면, 서블릿 컨테이너가 서버를 시작할 때 해당 서블릿을 미리 초기화하려 한다.

    • 숫자가 클수록 초기화 우선순위가 낮아진다.

장점

  • 첫 요청 응답 시간 단축

    • 서버가 시작될 때 서블릿이 미리 초기화되므로, 첫 요청 시 지연이 없다.

    • 초기화 작업이 복잡하거나 오래 걸리는 경우 사용자 경험 개선

  • 안정성 증가

    • 서버 시작 시 초기화 오류를 확인하고 조치 가능

    • 초기화 실패 시 서버 시작 단계에서 로그 확인 및 수정 가능

  • 예상 가능한 성능

    • 초기화 작업이 서버 시작 단계에서 완료되므로, 요청 처리 중 예상 못한 작업 지연을 방지

단점

  • 서버 시작 시간 증가

    • 모든 서블릿을 미리 초기화하므로, 초기화 작업이 많거나 무거운 경우, 서버 시작 속도가 느려질 수 있다.

  • 리소스 낭비 가능성

    • 요청이 오지 않는 서블릿도 초기화되므로, 불필요하게 메모리와 CPU 를 사용할 수 있다.

    • 특히 많은 서블릿이 배포되어 있지만, 일부만 사용된다면 비효율적

    • 자주 사용되지 않는 서블릿은 load-on-startup 을 꺼두는 것이 맞다.

적합한 상황

  • 자주 호출되거나 중요도가 높은 서블릿.

  • 초기화 작업이 길고, 첫 요청 지연이 사용자 경험에 큰 영향을 주는 경우.

2. 갑자기 트래픽이 피크를 칠 때 서버 로딩타임이 길다면? (Eager Initialization)

서버 상황

  • 현재 갑자기 트래픽이 피크를 쳐서 서버 증설이 이루어지는 상황이다.

문제 상황

서버 증설 및 Auto Scaling 이 느려지는 환경

  • 서버 부팅 시 Eager Initialization 으로 모든 서블릿 및 관련 리소스를 초기화하면, 새로운 서버가 준비되는데 시간이 오래 걸린다. 이로 인해 트래픽 증가에 대한 Auto Sacling 반응이 느려질 수 있다.

초기 요청 지연

  • 서버 부팅 시간이 길어진다는 이유는 초기 요청을 받기까지 시간이 오래 걸린다는 것을 의미한다.

로드 밸런서의 부하 증가

  • 초기화가 완료되지 않은 서버가 트래픽을 처리할 준비가 되지 않으면, 로드 밸런서는 기존 서버에 과도한 트래픽을 전달하게 된다. 이로 인해 기존 서버의 부하가 증가하고 성능이 저하될 수 있다.

생각해 볼 부분

  • 위와 같이 고가용성을 요구하는 환경에서는 "서버가 요청을 받을 수 있는 상태로 빠르게 전환되는 것" 이 중요한 요구사항이다.

  • 때문에, 첫 요청 시 초기화 비용을 감수하고서라도 빠르게 서버가 요청 받을 수 있는 상태로 바뀌는 것이 더 중요할 수 있다.

3. 서버 로딩 타임을 줄일 수 있는 방법은?

해결방안

  • Eager Initailization -> Lazy Initialization 변경

Lazy Initailization 이점

빠른 가용성 확보

  • 서버가 초기화 작업 없이 즉시 요청을 받을 수 있기 때문에, 서버 추가 과정에서의 지연 시간이 줄어든다.

  • 예를 들어, Auto Scailiing 으로 새 인스턴스를 추가할 때 서버가 전체 리소스를 미리 초기화하지 않고 요청을 받을 준비가 된 상태로 부팅할 수 있다.

리소스 효율성

  • 사용되지 않는 리소스를 초기화하지 않으므로 불필요한 리소스 소비를 줄이고, 서비스 부팅 시간을 단축할 수 있다.

  • 초기화 작업이 트래픽 패턴에 따라 분산되므로 CPU, 메모리 등의 리소스 사용이 급격히 치솟는 현상을 완화한다.

확장성과 가용성 강화

  • Lazy Initailization 을 통해서 일부 요청의 응답이 늦어질 수는 있지만, 동시에 요청을 처리할 수 있는 서버의 수가 늘어나므로 전반적인 서비스 안정성이 강화된다.

  • 첫 요청에서 초기화가 끝난 뒤부터는 해당 서버가 빠르게 트래픽을 처리할 수 있다.

Lazy Initialization 과 고가용성의 트레이드오프

  • Lazy Initialization은 가용성을 우선시하며, 초기화 시간으로 인해 발생할 수 있는 첫 요청의 느린 응답을 일부 요청의 희생으로 감수하는 접근 방식이다.

  • 만약 첫 요청의 응답 시간이 중요한 환경이라면 Lazy Initialization 이 적합하지 않을 수 있다.

4. 서블릿 초기화 설정 가이드

일반적인 상황

  • 일반적인 운영 반영의 상황에서 반영하는 서버를 내리더라도 운영중인 서버에 부하가 많지 않다는 것을 가정!

  • 사용자 경험 측면에서, 초기화를 통해 응답이 늦어진다는 것이 긍정적인 경험이 아닐 것으로 보여지기 때문에, 초기화 비용이 많이 드는 서블릿에 대해서는 Eager Initialization 을 사용

스케일 업 상황

  • 스케일 업 상황에서는 올라가는 서버가 요청을 받을 수 있는 상태로 변하는 것이 가장 중요하다.

  • 때문에, 초기화 비용을 감수하더라도 Lazy Initialization 을 통해서 빠르게 서버가 올라가는 것이 좋다.

5. 서블릿이 차지하는 메모리 비용을 예측할 수 있을까?

  • 서블릿들이 차지하는 메모리 비용은 서블릿 자체의 객체 크기뿐 아니라 서블릿 초기화 시 생성하는 리소스들(예 : DB 연결, 캐시, 객체 풀 등) 의 메모리 사용량에 따라 달라진다.

  • 따라서 정확한 비용을 예측하려면 여러 요소를 고려해야 한다..

6. 서비스를 좀 더 내 마음대로 모니터링 할 수 있게 하려면?

  • ServletContextListener 를 사용해보자.

  • Spring Interceptor 와 비슷한 기능을 수행한다.

6-1. ServletContextListener

ServletContextListener 란?

  • 웹 컨테이너는 웹 어플리케이션이 시작, 종료 되는 시점에 특정 클래스의 메서드를 실행할 수 있는 기능을 제공한다.

  • 이 기능을 통해 웹 어플리케이션 시 필요한 초기화 작업 또는 종료된 후 사용된 자원을 반환하는 작업 등을 수행

7. URL 매핑에 들어가는 비용은?

  • 정확하게 찾기가 어렵다 ..

Last updated