멀티 스레드

브라우저가 요청을 보내면 WAS가 응답을 한다. 요청을 했을 때 TCP 커넥션이 연결되면서 서블릿이 호출된다.

그런데 이 서블릿 객체는 누가 호출하는 걸까? 바로 스레드다.

스레드

  • 애플리케이션 코드를 하나하나 순차적으로 실행한다.

  • 자바 메인 메서드를 처음 실행하면 main이라는 이름의 스레드가 실행된다.

  • 스레드가 없다면 자바 애플리케이션 실행이 불가능하다.

  • 스레드는 한 번에 하나의 코드 라인만 수행한다.

  • 동시 처리가 필요하면 스레드를 추가로 만들어야 한다.

단일 스레드

스레드가 하나만 있다고 가정해보자.

단일 요청

요청이 오면 스레드를 할당한다. 이 스레드를 가지고 서블릿을 실행한다.

다 실행하고 나면 응답을 보낸다.

다중 요청

요청 1이 들어와서 스레드를 사용해 서블릿을 요청한다. 여러 가지 이유로 인해 처리에 시간이 많이 걸린다고 해보자.

이때 요청 2가 들어오면 스레드를 사용할 수 있을 때까지 기다린다. 이렇게 되면 둘 다 죽게된다. 1번이 잡고 있으니 2번이 실행 자체를 못하게 되고 결국 타임 아웃이 발생하는 것이다.

다중 스레드

문제를 해결하려면 요청마다 스레드를 생성하면 된다.

요청마다 스레드 생성

요청 1이 들어오고 처리가 지연되어도 요청 2가 오면 새로 스레드를 만든다. 같은 서블릿을 호출해도 스레드는 다르기 때문에 각 스레드대로 요청을 처리하고 응답을 보낸다. 응답이 끝나면 스레드를 날린다.

장점

  • 동시 요청을 처리할 수 있다.

  • 리소스(CPU, 메모리)가 허용할 때까지 처리할 수 있다.

  • 하나의 스레드가 지연되어도 나머지 스레드는 정상 동작한다.

단점

  • 스레드는 생성 비용이 매우 비싸다.

    • 고객 요청이 올 때마다 스레드를 생성하면 응답 속도가 늦어진다.

  • 스레드는 컨텍스트 스위칭 비용이 발생한다.

    • 스레드는 코어 수만큼 동시에 돌아간다.

      • 2개라고 치면 사실 둘은 동시에 수행하는 게 아니라 번갈아가면서 수행한다.

      • 너무 빨라서 동시에 한다고 느껴지는 것 뿐이다.

    • 이 두 개를 전환할 때 비용이 발생하는데 이것을 컨텍스트 스위칭 비용이라고 한다.

    • 스레드가 많아지면 이 비용 자체가 점점 커지게 된다.

  • 스레드 생성에 제한이 없다.

    • 고객의 요청이 너무 많이 오면 CPU와 메모리 임계점을 넘어서 서버가 죽을 수 있다.

스레드 풀

요청마다 생성하는 단점을 보완해 스레드 풀 안에 스레드를 미리 만들어놓고 쓰는 방법이다.

요청이 오면 스레드 풀에서 스레드를 가져다 쓴다. 200개니까 2개가 줄어 198개가 된다. 응답을 보내고 나면 스레드를 다시 반납해서 200개로 돌아간다.

만약 200개보다 더 많은 요청이 온다면 추가적인 요청들은 대기하고 있다가 200개 중에 응답을 보내고 반납한 스레드를 사용할 수 있다. 그래도 감당하기 힘들면 거절을 하기도 한다.

특징

  • 필요한 스레드를 스레드 풀에 보관하고 관리한다.

  • 스레드 풀에 생성 가능한 스레드의 최대치를 관리한다.

    • 톰캣은 최대 200개가 기본 설정이며 변경 가능하다.

  • 스레드가 필요하면 이미 생성되어있는 스레드를 스레드 풀에서 꺼내 사용한다.

  • 사용을 종료하면 스레드 풀에 해당 스레드를 반납한다.

  • 최대 스레드가 모두 사용중이어서 스레드 풀에 스레드가 없다면?

    • 기다리는 요청은 거절하거나 특정 숫자만큼만 대기하도록 설정할 수 있다.

장점

  • 스레드가 미리 생성되어 있어 스레드를 생성, 종료하는 비용(CPU)이 절약되고 응답 시간이 빠르다.

  • 생성 가능한 스레드의 최대치가 있으므로 너무 많은 요청이 들어와도 기존 요청은 안전하게 처리할 수 있다.

    • 물론 너무 많은 요청이 들어오면 클라이언트에선 계속 연결이 안되겠지만 성공한 사람은 어찌저찌 내부에서 로직이 돌아간다.

실무 팁

  • WAS의 주요 튜닝 포인트는 최대 스레드 수이다.

  • 값을 너무 낮게 설정하면?

    • 동시 요청이 많을 때 서버 리소스는 여유롭지만 클라이언트는 금방 응답이 지연된다.

  • 값을 너무 높게 설정하면?

    • 동시 요청이 많으면 CPU, 메모리 리소스 임계점 초과로 서버가 다운된다.

  • 장애가 발생하면?

    • 클라우드라면 일단 서버부터 늘리고 이후에 튜닝한다.

    • 클라우드가 아니면 열심히 튜닝한다.

스레드 풀을 너무 낮게 설정했을 경우 가능한 스레드의 100개의 요청이 온다면 90개가 대기한다. 리소스를 확인하면 CPU를 5%로만 사용하고 있다고 나온다.

안에서 10개만 정상적으로 수행되고 요청은 계속 쌓인다. 내가 처리하는건 10개인데 요청은 더 많으니 밀리면서 장애가 발생한다. WAS는 살아있어도 서버 전체는 장애가 난다.

사실 이럴 경우 못해도 CPU를 50%는 써줘야 한다. 설정 하나만 잘해줘도 늘어나는데 잘못해서 5%밖에 못쓴다고 인스턴스를 늘리고 있으면 돈만 그만큼 나간다.

스레드 풀의 적정 숫자

  • 애플리케이션 로직의 복잡도, CPU, 메모리, IO 리소스 상황에 따라 모두 다르다.

  • 최대한 실제 서비스와 유사하게 성능 테스트를 시도하자.

    • 아파치 ab, 제이미터, nGrinder

WAS의 멀티 스레드 지원

  • 멀티 스레드에 대한 부분은 WAS가 처리한다.

  • 개발자가 멀티 스레드 관련 코드를 신경쓰지 않아도 된다.

  • 개발자는 마치 싱글 스레드 프로그래밍을 하듯 편리하게 소스 코드를 개발한다.

  • 멀티 스레드 환경이므로 싱글턴 객체(서블릿, 스프링 빈)은 주의해서 사용한다.

Last updated