관리 메뉴

피터의 개발이야기

[JAVA] JDK21, Virtual Thread, Continuation에 대한 이해 본문

Programming/JAVA

[JAVA] JDK21, Virtual Thread, Continuation에 대한 이해

기록하는 백앤드개발자 2024. 5. 9. 10:29
반응형

ㅁ 들어가며

ㅇ JDK21에 정식으로 채택된 기술인 Virtyal Thread에 대해서 공부하였다.

ㅇ Reative Streams 방식보다 더 쉽게 적용이 가능하였다.

[4월 우아한테크세미나] ‘Java의 미래, Virtual Thread를 시청하고 작성한 글이다.

ㅇ 목표: Virtyal Thread의 장점을 이해하고, 어떻게 구현되어 있는고, 어떤 상황에 사용 시 이점이 있는지 알 수 있다.

 

ㅁ Virtual Thread 소개

ㅇ 스레드 생성 및 스케줄링 속도가 기존 스레드보다 빠르고 저렴하다.

ㅇ 스레드 스케줄링을 통해 Nonblocking I/O 지원

ㅇ Thread 상속: 기존 스레드를 상속하여 코드 호환성이 높다.

 

ㅁ Thread vs Virtual Thread 생성 리소스 차이

Thread

- 스레드 생성 시 속도와 비용이 크기 때문에 스레드 풀을 생성하여 사용하였다.

- 스레드의 생성 시 사용 메모리 크기가 크다.

- OS에 의해 스케줄링 된다. 

  ㄴ 기존 OS와 통신으로 스레드의 생성 및 소멸이 이루어져서 오버해드가 발생한다.

 

Virtual Thread

- 스레드 풀 개념이 없다. 명시적으로 선언된 스레드 풀은 없지만, 내부적인 스케줄러는 있다.

- 사용 메모리 크기가 작다.

- OS가 아닌 JVM내 스케줄링된다.

 

생성 리소스 비교

  Thread Virtual Thread
메모리 사이즈 ~2MB ~50 KB
생성시간 ~1 ms ~10us
컨텍스트 스위칭 시간 ~100us ~10us

 

ㅁ Non blocking 방식

ㅇ Spring WebFlux & Netty

  ㄴ Event queue를 이용해 Event Loop로 처리하여 비동기를 구현하였다.

ㅇVirtual Thread non blocking I/O

  ㄴ JVM 스레드 스케줄링

  ㄴ Continuation 활용

 

ㅁ 하위버젼 호환성

ㅇ Thread > BashVirturalThread > VirtualThread의 상속 구조를 가지고 있어, 상위 기능을 하위 Virtual 스레드가 리스코프 원칙에 따라 호환성을 가진다.

ㅇ ExecutorService도 newVirtualThreadPerTaskExecutor로 바꾸어도 기능구현이 가능하다. 영상

 

ㅁ Virtual Thread 작동원리

Thread

  ㄴ 플랫폼 스레드를 사용

  ㄴ OS에 의해 스케줄링된다.

     ㄴ커널 영역(OS)의 Thread와 유저영역(JVM)의 Thread를 사용하기 위해서는 JNI 통신이 필요하다.

     ㄴ 이 통신으로 인해 오버헤드가 발생한다.

  ㄴ 커널 스레드와 1:1 매핑된다.

  ㄴ 작업 단위는 Runnable이다.

 

Virtual Thread

  ㄴ 가상 스레드

  ㄴ JVM에 의해 스케줄링

  ㄴ 캐리어 스레드와 1:N 매핑

  ㄴ 작업 단위 Continuation

 

https://www.youtube.com/live/BZMZIM-n4C0?si=XWrBWEcfQKa7oa1g&t=1528

ㅇ 커널 Thread와 유저Thead를 ForkJoinPool로 만들어 스래드의 생성, 스케줄링 오버헤드를 줄였다.

ㅇ 경량화된 Virtual Thread를 큐형태로 받아 Carrier Thread가 순차적으로 수행하여 동시성과 병렬성을 얻어 비동기처리를 가능하게 했다.

 

Coroutione을 이해하기 위해서는 Thread의 locking에 대해 이해가 필요하다. Continuation은 제어흐름을 전환하여 하나의 thread의 작업을 중지, 다른 스레드를 실행하였다가 다시 시작하여 동시성, NonBlock 효과를 낼 수 있다. 

 

ㅁ Continuation 작업단위

https://www.youtube.com/live/BZMZIM-n4C0?si=EHKNUryn-O0vG2IJ&t=2018

Continuation은 Coroutine처럼 제어흐름(Control flow)의 일종이다. 제어흐름을 직접적으로 선언하여 한 작업을 중단하고 재시작할 수 있다.

Coroutine의 비동기의 핵심은 작업의 중단 및 재시작하는 runContinuation 작업이다.

 

Continuation을 더 깊이 이해하기 위해서는 LockSupport.park로 기존 스레드의 중지 재시작 메커니즘을 이해해야한다. 

 

ㅁ LockSupport.park

기존 Thread를 중단하는 경우,

 - Thread.sleep()

 - Mono.block()

 - CompletableFuture.get() 

등을 사용하였다.

 

Virtual Thread의 작업을 중단시키고 싶으면 park()를 사용한다.

Virtual Thead인 경우 park 시 Continuation의 yield를 호출하여 기존 작업을 중지하고 다음 작업으로 전환하게 한다.

작업이 block 되어도 실제로는 다른 작업으로 전환되기 때문에 NIO의 효과를 얻을 수 있다.

 

커널 스레드의 중단을 최소화하여 시스템 call에 따른 오버헤드를 줄일 수 있다. 

 

ㅁ Continuation 사용 이유

ㅇ Thread 작업 중단 시 커널 스레드를 중단하면서 시스템 통신 I/O 오버헤드 발생

ㅇ Virtual Thread는 작업 중단을 위해 continuation yield를 적용

ㅇ 작업이 block되어도 continuation의 제어권 이전으로 인해 스레드의 중단 없이 다른 작업으로 전환이 가능

ㅇ 기존 커널 스레드는 유지되어 시스템 콜로 인한 컨텍스트 수위칭 비용을 줄일 수 있다.

 

ㅁ 성능 테스트

ㅇ Thread 대비

  - I/O 작업이 더 높은 처리량

  - CPU 작업은 더 낮은 처리량

  - 특정 임계치 이상부터는 장애가 발생함

ㅇ I/O 작업처럼 CPU 사용량이 적은 Context 비용이 작업 작업 수행 시 최대 처리량을 수행

 

ㅁ 결론

ㅇ Virtual Thread는 가볍고, 빠르고, nonblocking인 경량 스레드

ㅇ Virtual Thread는 JVM 스케줄링 + Continuation

ㅇ Thread per request 사용 중이고, I/O blocking time 이 주된 병목인 경우 고려 대상

ㅇ 쉽게 적용가능

  - Reactive가 배우기 어려울 때

  - Kotlin coroution이 배우기 어려울 때

  - 기존 Thread방식에 쉽게 적용할 수 있다.

  - 리스코프 원칙에 따라 하위 호환성을 유지한다.

 

ㅁ 함께 보면 좋은 사이트

[4월 우아한테크세미나] ‘Java의 미래, Virtual Thread

 

반응형
Comments