• 티스토리 홈
  • 프로필사진
    알쓸개잡
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
알쓸개잡
  • 프로필사진
    알쓸개잡
    • 분류 전체보기 (93)
      • 스프링부트 (52)
      • AWS (5)
      • 쿠버네티스 (7)
      • 자바 (19)
      • 인프라 (1)
      • ETC (8)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      • 반응형
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • spring boot 가상 스레드 적용해보기
        2023년 12월 03일
        • 알쓸개잡
        • 작성자
        • 2023.12.03.:45
        반응형

        JDK 21부터 가상 스레드(virtual thread)가 정식 릴리즈 되었다. 또한 spring boot 3.2부터는 가상 스레드가 지원되어 spring boot 애플리케이션에서 가상 스레드를 시험해 볼 수 있게 되었다. 이번 포스팅에서는 spring boot 웹 애플리케이션에서 가상 스레드를 적용한 샘플코드를 작성해 보고 jmeter를 통해서 가상 스레드와 플랫폼 스레드의 처리량의 차이를 비교해 보고자 한다.

         

        가상 스레드에 대한 내용은 다음 포스팅에서 정리하였다.

        2023.11.24 - [자바] - java 21 처리량 향상을 위한 대안 - virtual thread 알아보자

        2023.11.26 - [자바] - java21 - scoped value에 대해서 알아보자

         

         

        사전 조건

        virtual thread를 적용하기 위해서는 JDK 21을 설치해야 한다.

        intellij IDE 혹은 SKDMAN을 통해서 손쉽게 JDK 21 버전을 설치할 수 있다.

        프로젝트에는 JDK 21을 SDK 버전으로 설정해야 한다.

        SDKMAN에 대해서는 다음 포스팅을 참고하기 바란다.

        2023.09.02 - [분류 전체보기] - SDKMAN - 개발 도구 손쉽게 관리하기

         

        샘플코드

        virtual thread 적용을 위한 configuration

        내장 톰캣에서 사용하는 스레드를 virtual thread로 적용하기 위해서는 다음과 같이 configuration을 생성한다.

        package com.example.spring.virtualthread.config;
        
        import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
        import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
        import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.core.task.AsyncTaskExecutor;
        import org.springframework.core.task.support.TaskExecutorAdapter;
        
        import java.util.concurrent.Executors;
        
        @Configuration
        @ConditionalOnProperty(
        	value = "application.use-virtual",
        	havingValue = "true")
        public class ThreadConfig {
        
        	@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
        	public AsyncTaskExecutor asyncTaskExecutor() {
        		return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
        	}
        
        	@Bean
        	public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
        		return protocolHandler ->
        			protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
        	}
        }

        @ConditionalOnProperty 어노테이션을 통해서 application.use-virtual=true 인 경우에 가상 스레드가 활성화된다.
        application.use-virtual=false인 경우에는 전통적인 플랫폼 스레드가 사용된다.

        application:
          # false인 경우 플랫폼 스레드 사용
          use-virtual: true
        위와 같이 @Configuration 클래스 작성 필요 없이 다음과 같이 설정 만으로도 virtual thread를 활성화 할 수 있다.
        spring.threads.virtual.enabled=true (가상 스레드 활성화)
        spring.threads.virtual.enabled=false (가상 스레드 비활성화)

         

         

        Service

        단순히 blocking I/O를 수행하는 역할을 하는 코드로 5초간 sleep을 주었다.

        package com.example.spring.virtualthread.service;
        
        import org.springframework.stereotype.Service;
        
        @Service
        public class BlockingIOService {
        
        	public void blocking() throws InterruptedException {
        		Thread.sleep(5000);
        	}
        }

         

         

        controller

        GET /thread 호출을 통해 가상 스레드 여부와 스레드 정보를 응답하는 단순한 API를 하나 만들었다.

        package com.example.spring.virtualthread.controller;
        
        import com.example.spring.virtualthread.service.BlockingIOService;
        import lombok.Getter;
        import lombok.RequiredArgsConstructor;
        import org.springframework.http.ResponseEntity;
        import org.springframework.web.bind.annotation.GetMapping;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.RestController;
        
        
        @RestController
        @RequestMapping("/thread")
        @RequiredArgsConstructor
        public class ThreadController {
        
        	private final BlockingIOService blockingIOService;
        
        	@GetMapping
        	public ResponseEntity<ThreadInfo> getThreadInfo() throws InterruptedException {
        		blockingIOService.blocking();
        		return ResponseEntity.ok(
        			new ThreadInfo(
        				Thread.currentThread().isVirtual(),
        				Thread.currentThread().toString())
        			);
        	}
        	public record ThreadInfo(boolean isVirtual, String threadName) {}
        }

         

         

        API 호출 테스트

        application.use-virtual=true 인 경우에 /thread 호출은 다음과 같이 응답하여 가상 스레드가 사용됨을 확인할 수 있다.

        {
            "isVirtual": true,
            "threadName": "VirtualThread[#57]/runnable@ForkJoinPool-1-worker-2"
        }

         

        application.use-virtual=false인 경우에 /thread 호출은 다음과 같이 응답하여 플랫폼 스레드가 사용됨을 확인할 수 있다.

        {
            "isVirtual": false,
            "threadName": "Thread[#45,http-nio-8080-exec-2,5,main]"
        }

         

        처리량 테스트

        jmeter를 통해서 가상 스레드와 플랫폼 스레드의 처리량을 비교해 보자.

        맥 m1, m2 환경에서 jmeter를 설치하는 방법은 아래 포스팅에 정리하였다.

        2023.12.02 - [ETC] - 맥 m1, m2에 jmeter 사용하기

         

        jmeter 스레드 그룹 설정

        jmeter 스레드 그룹 설정
        jmeter 스레드 그룹 설정

        1000 개의 스레드를 생성하여 각 스레드가 100초간 반복 호출하도록 설정하였다.

         

        http 요청 설정

        jmeter http 요청 설정
        jmeter http 요청 설정

        GET http://localhost:8080/thread API를 호출하도록 설정한다.

        가상 스레드 적용 처리량

        애플리케이션의 application.use-virtual=true로 설정 후 애플리케이션을 기동 후 jmeter 테스트를 수행한 결과는 다음과 같다.

        가상스레드 처리량
        가상 스레드 처리량
        가상 스레드 응답 시간 그래프
        가상 스레드 응답 시간 그래프

        가상 스레드의 경우에는 초당 185.6건의 처리량을 보였다.

        가상 스레드의 경우 모든 응답 시간은 균일하게 5초가 소요되었다.

        제약 없이 스레드를 생성하여 처리할 수 있기 때문에 blocking I/O 작업 동안 다른 스레드의 대기가 발생하지 않기 때문이다.

        플랫폼 스레드 적용 처리량

        플랫폼 스레드의 경우에는 별도의 thread pool 개수 설정을 하지 않았으므로 디폴트 값이 200개로 수행된다.

        애플리케이션의 application.use-virtual=false로 설정 후 애플리케이션을 기동 후 jmeter 테스트를 수행한 결과는 다음과 같다.

        플랫폼 스레드 처리량
        플랫폼 스레드 처리량
        플랫폼 스레드 응답 시간 그래프
        플랫폼 스레드 응답 시간 그래프

         

        플랫폼 스레드의 경우에는 초당 39.3건의 처리량을 보였다.

        200개의 스레드로 제한되어 있기 때문에 blocking I/O 작업 동안 다른 스레드에서의 대기가 발생하기 때문이다.

        baeldung 사이트의 글과 비교했을 때 가상 스레드와 플랫폼 스레드의 응답 시간 그래프 모양은 동일하다.

         

        간단한 샘플 코드를 통해서 가상 스레드와 플랫폼 스레드 간의 처리량의 차이를 확인해 보았다. 빈번하게 blocking I/O가 발생하는 애플리케이션에 가상 스레드를 적용하면 확실하게 처리량의 향상을 얻을 수 있을 것으로 기대한다.

         


        참고 링크

        https://www.baeldung.com/spring-6-virtual-threads

        https://spring.io/blog/2022/10/11/embracing-virtual-threads

        반응형
        저작자표시 비영리 변경금지 (새창열림)

        '스프링부트' 카테고리의 다른 글

        spring data MongoDB - MongoTemplate 설정하기  (0) 2024.01.01
        spring boot data MongoDB - 연결 설정 하기  (0) 2023.12.29
        spring scheduler task에 shedlock + redis 적용방법  (0) 2023.11.20
        spring multi module 프로젝트 만들기  (0) 2023.11.19
        Spring REST 서비스 예외 처리 방법  (0) 2023.11.09
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바