Virtual Thread (feat. Java 21)

0_0_yoon·2023년 9월 6일
0
post-thumbnail

서론

지난달 Final RC 가 끝난 Java 21 은 9월 19일에 출시된다. 새로운 기능 중 이번에 정식으로 제공되는 Virtual Thread 에 대해서 알아봤다.(19,20 에서 preview 기능으로 제공)

본론

Virtual Thread 가 만들어진 배경

Thread Per Request

10개의 요청을 동시에 처리하여 초당 200개의 요청을 처리할 수 있는 애플리케이션이 있다고 가정해 보자. 사용자 수가 늘어 초당 2,000개의 요청을 처리해야 한다면 100개의 요청을 동시에 처리할 수 있도록 해야 한다. 그러면 서버는 스레드 수를 늘려 문제없이 요청을 처리할 수 있다. 나중에 사용자수가 더 늘어 초당 20,000개의 요청을 처리해야 하는 경우 마찬가지로 서버는 스레드 수를 늘려 문제없이 요청을 처리할 수 있을까? 아쉽게도 그럴 수 없다. 자바에서 생성할 수 있는(polling 할 수 있는) 스레드 수는 한계가 있다. 그 이유는 OS 스레드를 기반으로 1:1 대응되어 만들어져서 생성할 수 있는 스레드 수가 서버 하드웨어에 한정되기 때문이다.

Async

그렇다면 어떻게 처리량을 늘릴 수 있을까?
자바 애플리케이션은 기본적으로 하나의 요청을 하나의 스레드가 처리한다. 즉 요청을 처리하면서 네트워크 I/O, 파일 I/O 등과 같은 다른 I/O 작업이 발생하면 해당 스레드는 blocking 된다.(외부 작업이 끝날 때까지 자바 스레드는 대기하게 된다) 이런 대기 상태의 스레드를 다시 새로운 요청을 받을 수 있도록 하면 한정된 하드웨어를 최대한 활용해서 처리량을 높일 수 있다. 하지만 이 방법에는 문제점이 있다.

  1. 스레드의 Context switching 이 자주 발생
  • 다른 I/O 작업이 발생하면 해당 스레드는 poll 로 반환되고 다른 스레드가 다음 요청을 처리한다. 즉 Thread Per Request 보다 빈번하게 Context switching 되어 오버헤드가 발생한다.
  1. 디버깅이 어려움(프로그램 동작을 이해하기 어렵다)
  • Thread Per Request 의 경우 예외가 발생하면 요청을 처리한 스레드 1개만 확인하면 됐지만 비동기로 동작하면 1개의 요청을 N 개의 스레드가 처리하게 되므로 N 개의 스레드를 일일이 확인해야 한다.

Virtual Thread

애플리케이션의 처리량을 늘리는 동시에 위와 같은 문제점을 해결하고자 JDK 개발자들은 가상 스레드를 만들었다. 가상 스레드는 플랫폼 스레드(기존의 자바 스레드)와 다르게 OS 스레드와 연결되어 있지 않다. 즉 가상 스레드는 일반적인 인스턴스이기 때문에 생성 비용이 저렴하다.
때문에 요청을 처리하는 도중 다른 I/O 작업이 발생하면 해당 가상 스레드는 blocking 되고 새로운 가상 스레드 객체를 만들어 다음 요청을 처리한다.
그리고 요청을 처리하는 도중 CPU 에서 계산을 수행하는 동안에만 플랫폼 스레드를 사용한다. 즉 플랫폼 스레드 측에서 봤을 때 1개의 플랫폼 스레드를 N 개의 가상 스레드가 사용한다.(둘을 같이 놓고 보면 많은 수(M)의 가상 스레드가 더 적은 수(N)의 OS 스레드에서 실행된다)

  1. 스레드의 Context switching 이 자주 발생하는 문제 해결
  • 다른 I/O 작업이 발생하면 새로운 가상 스레드를 만들어 요청을 처리한다.
    가상 스레드는 일반적인 인스턴스이기 때문에 Context switching 이 발생하지 않는다. 플랫폼 스레드의 경우 OS 의 스케줄러에 의존하는 반면, 가상 스레드의 경우 JDK 의 자체 스케줄러에 의존한다.
  1. 디버깅이 어려운 문제 해결 -> 1개의 가상 스레드가 1개의 요청을 처리한다.
  • 다른 I/O 작업이 발생하면 해당 가상 스레드는 blocking 됐다가 작업이 완료되면 해당 가상 스레드가 이어서 요청을 처리한다.

결론

비유하자면 물리주소는 메모리 크기에 한정되지만 CPU 가 사용하는 논리주소는 메모리 크기에 한정되지 않는 것처럼(메모리 + 스왑영역) OS 스레드는 하드웨어(메모리 + 스왑영역)에 의해 한정되지만, 자바 런타임의 가상 스레드는 OS 스레드에 한정되지 않는다.
Virtual Thread 를 사용하면 OS 스레드를 blocking 없이 효율적으로 활용해서 애플리케이션의 처리량을 늘릴 수 있으며, Virtual Thread 는 요청과 1대1로 대응되기 때문에 프로그램 흐름을 쉽게 파악할 수 있다는 이점이 있다.

참고 https://openjdk.org/jeps/444

profile
꾸준하게 쌓아가자

0개의 댓글