Spring Boot를 이용해서 개발을 하다가 문득 궁금증이 생겼습니다.
Spring Boot는 여러 개의 요청을 어떻게 병렬적으로 처리할까?
바로 알아보겠습니다.
Spring Boot가 병렬적으로 처리를 하긴 하나?
아래의 코드를 보겠습니다.
@RestController()
@RequestMapping("/study")
public class StudyController {
private final Logger log = LoggerFactory.getLogger(this.getClass().getSimpleName());
@GetMapping("/threadPool")
public String threadPoolTest(){
try{
log.info("Method start!");
Thread.sleep(2000); // 2초간 딜레이
log.info("Method end!");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello?";
}
}
localhost:8080/study/threadPool으로 GET 요청을 보내면
로그 실행 - 2초 딜레이 - 로그 실행
하는 단순한 코드입니다.
만약 병렬로 처리하는 것이 아니라면,
GET 2번을 연달아 보냈을때 두번째 요청은 첫번째 요청이 완료 된 이후 최소 2초 뒤에 실행되어야 합니다.
하지만 아래의 실행 결과를 보게 된다면,
21:11:12초에 첫번째 요청이 실행이 되고, 21:11:13초 즉 1초만에 두번째 요청이 실행되는 모습을 확인 할 수 있습니다.
(※ 1초나 걸린 이유는 제가 손이 느려서 테스트할때 두번 클릭하는데 걸린 시간입니다.)
이 결과를 보면 Spring Boot는 병렬처리를 한다는 사실을 알 수 있습니다.
그럼 병렬처리는 어떻게 하는건지 알아보겠습니다.
ThreadPool
결론부터 말씀드리자면 ThreadPool이란 녀석을 이용합니다.
ThreadPool은 단어 뜻대로 하면 Thread가 모인 Pool을 의미합니다.
Thread가 무엇인지 알고 싶으신분은 아래 링크를 통해 보고 오시면 됩니다.
ThreadPool은 프로세스가 시작이 될때 정해진 갯수만큼 여러개의 Thread를 생성하여 저장해둡니다.
그리고 요청이 들어오면 일들을 Thread들에게 할당하여 처리합니다.
아래 사진으로 설명드리겠습니다.
이렇게 일(Task)가 들어올때마다 이를 처리할 Thread를 하나씩 배정하여 처리합니다.
이러한 특징은 여러 일을 병렬처리를 해야하는 경우 유리합니다. 그렇기에 웹 어플리케이션 과 같은 프로그램에서 사용하기 적합합니다. Spring Boot는 이러한 특징을 잘 살려 병렬로 처리합니다.
(※ 정확하게는 Spring Boot에서 직접 관리하는 것이 아닌 내부에 있는 Tomcat에서 처리합니다. 자세한 내용은 다음에 포스팅해보도록 하겠습니다.)
그럼 Spring Boot에서는 이방식을 사용해서 병렬처리한다는 것을 어떻게 알 수 있을까요?
위에서 병렬처리하는지 확인하는 코드의 결과를 다시 가져오겠습니다.
이번에는 시간이 아닌 Thread의 이름을 표시해봤습니다.
첫번째 GET요청을 처리한 Thread의 이름은 nio-8080-exec-1이며,
두번째 GET요청을 처리한 Thread 이름은 nio-8080-exec-3 입니다.
(※ nio는 NonBlocking I/O의 약자이며 Tomcat 버전이 8.0이상일 경우 기본값입니다. 이전에는 bio, Blocking I/O의 약자가 기본값이였습니다. 기회가 되면 자세히 한번 다뤄보겠습니다.)
여러 개의 쓰레드가 작동하는것을 확인 할 수 있습니다.
이렇기에 어떠한 일을 하고있는 상황에도 추가적인 요청이 들어오면 병렬로 처리가 가능합니다.
※ 추가로 ThreadPool에서 MultiThread를 이용하는거면 혹시나(당연히겠지만) 특징도 그대로 일까 라는 궁금증이 들어 테스트해봤습니다.
Thread는 Stack영역은 각자 할당, Data 영역은 공유한다고 하였기에 간단하게 지역변수, 전역변수로 테스트 해봤습니다.
MultiThread의 특징을 알고 싶으시면 아래 링크를 통해 확인하실 수 있습니다.
코드는 아래와 같습니다.
@RestController()
@RequestMapping("/study")
public class StudyController {
private final Logger log = LoggerFactory.getLogger(this.getClass().getSimpleName());
private static boolean status = false;
@GetMapping("/threadPool")
public void threadPoolTest(){
log.info("status : " + status);
}
@GetMapping("/changeStatus")
public void changeStatus(){
log.info("Change Status value!");
status = !status;
}
}
status라는 전역변수가 있고 초기값은 false입니다.
threadPool - changeStatus - threadPool - threadPool 로 실행을 했을때 status의 값이 공유가 된다면,
false - (change) - true - true로 출력이 되어야 정상일 겁니다.
그 결과는 아래 사진과 같습니다.
결과는 우리가 생각했던대로 잘 나왔습니다.
Thread또한 1,3,4,5번으로 각기 다른 Thread였지만 값이 잘 나온걸 보면 혹시나 ThreadPool에서의 Thread는 다른건가? 했던 걱정은 기우였던것 같습니다.
'개발잡담 > Back-End' 카테고리의 다른 글
Spring Boot에서 영상 스트리밍으로 받기 (feat. React) (0) | 2024.02.03 |
---|---|
Spring Boot에서 파일 다운로드 (feat. React) (0) | 2024.02.02 |
Spring batch 5.1.0 간단 사용 (0) | 2024.01.31 |
로그가 필요해 - 서론 (0) | 2023.11.02 |
Spring Boot에서 MQTT 사용하기 (0) | 2023.05.19 |