Virtual Thread 를 알아보기전에 기존의 Native Thread 의 context switching 이 발생하는 원리에 대해 알아보자

기존의 JVM 에 존재하는 톰캣 스레드는 커널스레드와 1대1로 매핑되어 실행이 되는 구조이다.
지금까지 CPU 코어가 톰캣 스레드를 context switching 하여 스케줄링을 하는 구조라고 알고있었지만 , 그것은 커널스레드와 Native Thread가 1대1 대응이 되기때문에 중간과정이 생력된 것이였다.

운영체제 시간에 배웠듯이 context switching 이란
스레드가 sleep, I/O 처리 등을 진행할 동안 다른 OS 커널 스레드는 다른 Thread를 점유하여 작업하는 것을 말한다.
스레드는 프로세스의 공통영역을 제외하고 만들어지기 때문에, 프로세스에 비해 크기가 작아서 생성 비용이 적고, 컨텍스트 스위칭 비용이 저렴했기 때문에 주목받아 왔다.
그러나, 요청량이 급격하게 증가하는 서버 환경에서는 갈수록 더 많은 스레드 수를 요구하게 되었다. 스레드의 사이즈가 프로세스에 비해 작다고 해도, 스레드 1개당 1MB 사이즈라고 가정하면, 4GB 메모리 환경에서도 많아야 4,000개의 스레드를 가질 수 있다. 이처럼 메모리가 제한된 환경에서는 생성할 수 있는 스레드 수에 한계가 있었고, 스레드가 많아지면서 컨텍스트 스위칭 비용도 기하급수적으로 늘어나게 되었다.
Context Switching 과정에서 발생하는 과정은 생력하겠지만,간단하게 말하면
1.커널이 개입해서 현재 스레드의 상태를 PCB(Process Control Block) 에 저장
2.새 스레드의 PCB를 불러와서 레지스터, 스택 포인터, 프로그램 카운터(PC) 복원
3.TLB flush, CPU 캐시 무효화, 유저↔커널 모드 전환
이런 전체 과정이 전부 커널 모드에서 수행되기 때문에
CPU 캐시, TLB, 커널 진입 비용이 발생합니다.
결과적으로 스위칭 하나당 수 µs 이상 걸립니다.
서버는 더 많은 요청 처리량과 컨텍스트 스위칭 비용을 줄여야 했는데, 이를 위해 나타난 스레드 모델이 경량 스레드 모델인 Virtual Thread입니다.

Virtual Thread는 기존 Java의 스레드 모델과 달리, 플랫폼 스레드와 가상 스레드로 나뉜다. 플랫폼 스레드 위에서 여러 Virtual Thread가 번갈아 가며 실행되는 형태로 동작합니다. 마치 커널 스레드와 유저 스레드가 매핑되는 형태랑 비슷하다.
가장 큰 특징은 Virtual Thread는 컨텍스트 스위칭 비용이 저렴하다는 것이다.
Thread는 기본적으로 최대 2MB의 스택 메모리 사이즈를 가지기 때문에, 컨텍스트 스위칭 시 메모리 이동량이 큽니다. 또한 생성을 위해선 커널과 통신하여 스케줄링해야 하므로, 시스템 콜을 이용하기 때문에 생성 비용도 적지 않다
하지만 Virtual Thread는 JVM에 의해 생성되기 때문에 시스템 콜과 같은 커널 영역의 호출이 적고, 메모리 크기가 일반 스레드의 1%에 불과합니다. 따라서 Thread에 비해 컨텍스트 스위칭 비용이 적다

용어 정리 :
Platfrom Thread : 톰캣 스레드, new Thread()로 만든 스레드, 즉 OS 커널스레드와 1대1 대응하는 스레드는 모두 Platfrom Thread이다.
Carrier Thread: Platfrom Thread 의 한종류, Virtual Thread를 실행시키는 스레드이다.

JDK21 에서의 Park() 하는 과정이다.
기존의 Thread가 Virtual 인지 일반 Thread 인지 확인을 한다.

unpark()를 하는 과정을 보면
vthread.switchToCarrierThread() 함수를 볼수있다.
이 과정에서 UNPARKED 된 Virtual Thread 를 unmound()하고 다른 기존의 Carrier 스레드에게 mount()하는 과정이 발생한다.
context switching 비용에서 발생하는 성능테스트를 위해서
docker compose 를 비용해 CPU 코어수 1개, 스레드당 sleep(30ms) 을 가정하고 테스트를 진행하였다.


<기존 PlatFrom Thread인 경우>

<기존 Virtaul Thread인 경우>

가상의 유저를 500으로 하였을경우 위와 같은 결과가 발생하였지만
더 많은 트래픽이 발생할수록(Context Switching이 많이 발생) 할수록 성능차이가 많이 날것이다.