여러 요청이 동시에 들어오면, Spring Boot는 어떻게 처리할까?

2025. 3. 9. 21:03·삽질로그

1. 들어가며

지난 글에서는 웹소켓 핸들러를 Event 기반으로 처리하여 동기 방식으로 해결했다.

이를 통해 코드가 더 깔끔해지고 유지보수가 쉬워졌지만, 한 가지 새로운 고민이 생겼다.

 

🔗 이전 글: 2025.03.03 - [삽질로그] - 복잡한 웹소켓 핸들러, Event로 깔끔하게 해결하기

 

복잡한 웹소켓 핸들러, Event로 깔끔하게 해결하기

1. 들어가며최근 아두이노 기반 대여기 시스템을 구축하면서, 서버와 대여기가 WebSocket을 통해 실시간으로 메시지를 주고받는 구조를 만들게 되었다. 하지만 기존 방식으로 WebSocket을 처리하는

mingking2.tistory.com

 

💡 만약 동시에 많은 대여 요청이 들어온다면 어떻게 될까?

  • 아두이노(대여기)는 여러 요청을 동시에 처리할 수 있을까?
  • 한 요청이 진행되는 동안 다른 요청은 대기해야 할까?
  • Spring Boot는 이러한 다중 요청을 어떻게 처리할까?

대여기에서 발생하는 동시 요청이 결국 Spring 서버에서 먼저 처리되는 구조이기 때문에,

이번 포스팅에서는 Spring Boot가 다중 요청을 처리하는 방식을 먼저 살펴보려 한다.


2. Spring Boot는 동시 요청을 어떻게 처리하는가?

Spring Boot는 기본적으로 멀티스레딩(Multi-threading) 기반의 동작 방식을 사용한다.

즉, 여러 클라이언트의 요청이 동시에 들어와도 각 요청을 처리할 개별적인 스레드가 존재하므로 동시 처리가 가능하다.

 

📌  스레드와 멀티스레딩

본 포스팅에서는 스레드(Thread)와 멀티스레딩(Multi-threading)에 대한 깊은 설명보다는 개념적인 정의만 다룬다.
더 자세한 내용이 궁금하다면 아래 링크를 참고하면 좋다.
 

👩‍💻 멀티 프로세스 vs 멀티 스레드 비교 💯 완전 총정리

멀티 프로세스와 멀티 스레드는 한 어플리케이션에 대한 처리방식 이라고 보면 된다. 단순히 프로그램을 여러개 띄워놓는 것이 멀티 프로세스가 아니라 이 둘은 언제 어느때에 어떤 방식으로

inpa.tistory.com

  • 스레드(Thread) : 프로세스 내에서 실행되는 작은 실행 단위
  • 멀티스레딩(Multi-threading) : 하나의 프로세스에서 여러 개의 스레드가 동시에 실행되는 방식

 

📌 Spring의 요청 처리 흐름

Spring Boot는 기본적으로 내장된 웹 컨테이너(Tomcat)을 사용하여 HTTP 요청을 처리한다.

이 웹 컨테이너는 스레드풀(Thread Pool)을 활용하여 동시 요청을 처리할 수 있다.

  1. 사용자가 API 요청을 보냄
  2. Tomcat (기본 웹 컨테이너)이 요청을 수신
  3. Tomcat의 스레드풀(Thread Pool)이 요청을 처리할 스레드를 할당
  4.  해당 요청을 처리하는 Controller의 로직이 실행됨
  5.  응답을 반환하고, 사용된 스레드는 다시 풀(Thread Pool)로 반환됨

✅ 여러 사용자의 요청이 동시에 들어와도 각 요청을 처리할 개별적인 스레드가 존재하므로 동시에 처리할 수 있음.


3. Thread Pool

스레드풀은 미리 일정 개수의 스레드를 생성해두고 요청이 들어오면 해당 스레드를 할당하여 처리하는 방식이다.

즉, 스레드를 매번 새로 생성하는 것이 아니라, 재사용 가능한 스레드를 유지하면서 요청을 처리한다.

 

✅ 요청이 끝나면 스레드는 제거되지 않고 다시 풀(Pool)로 반환되어 다른 요청을 처리할 수 있다.

 

📌 스레드풀이 필요한 이유

"요청이 들어올 때마다 새로운 스레드를 만들면 되지않나?"
❌ 스레드를 계속 생성하면 성능이 오히려 저하될 수 있다.


스레드를 무조건 새로 생성하면 발생하는 문제

  1. 메모리 사용량 증가 → 스레드를 새로 만들 때마다 CPU와 메모리 리소스를 사용
  2. 컨텍스트 스위칭 비용 증가 → 너무 많은 스레드가 생성되면 CPU가 작업을 전환하는 데 추가 비용이 발생
  3. 스레드 관리 어려움 → 너무 많은 스레드가 생성되면 오히려 성능이 저하될 수 있음

✅ 해결책: "스레드풀(Thread Pool)"을 활용하여 미리 생성한 스레드를 재사용하자!

 

📌 스레드풀의 동작 과정

스레드풀의 동작 과정

  1. 요청이 들어오면 사용 가능한 스레드가 있는지 확인
  2. 사용 가능한 스레드가 있으면 즉시 할당하여 요청을 처리
  3. 모든 스레드가 사용 중이라면, 요청을 대기 큐에 저장
  4. 대기 큐가 가득 차면 새로운 스레드를 추가 생성
  5. 작업이 끝난 스레드는 다시 풀(Thread Pool)로 반환

✅ 즉, Spring Boot는 요청이 들어올 때마다 스레드를 새로 만드는 것이 아니라, 미리 생성해둔 스레드 풀을 활용하여 성능을 최적화한다.

 

📌 Java vs Spring Boot

자바(Java)와 스프링 부트(Spring Boot)에서 사용하는 스레드풀(Thread Pool)은 개념적으로 비슷하지만, 사용 목적과 동작 방식이 다르다.

  Java 스레드풀 (ExecutorService) Spring Boot 스레드풀 (Tomcat)
사용 목적 비동기 작업 HTTP 요청 처리
스레드 생성 방식 개발자가 직접 정의
Executors.newFixedThreadPool()
Tomcat이 자동 관리
큐(Queue) 관리 BlockingQueue<Runnable>을 사용하여 대기 작업 저장 accept-count만큼 대기 요청을 저장
새로운 스레드 추가 생성 설정에 따라 동적으로 가능
newCachedThreadPool()
기본적으로 추가 생성하지 않음, 요청을 거부
💡 Java는 왜 스레드풀을 자동으로 관리하지 않을까?
Java는 범용 프로그래밍 언어(웹, 모바일, 임베디드)로 모든 환경에 맞춰 자동으로 관리하기 어렵다.
따라서 개발자가 직접 필요에 맞게 스레드풀을 정의해야 한다.

 

Java의 ExecutorService와 Spring Boot의 스레드풀을 비교하는 방식이 잘못되었다는 피드백을 받았다.
잘못된 비교를 바로잡고, 더 정확한 내용을 정리했으니 아래 링크에서 확인해주세요! 👇
2025.03.16 - [삽질로그] - Spring Boot 비동기 처리 = 스레드풀?
 

Spring Boot 비동기 처리 = 스레드풀?

1. 들어가며이전 포스팅에서 Java의 ExecutorService와 Spring Boot의 스레드풀을 비교하는 방식이 잘못되었다는 피드백을 받았다. 2025.03.09 - [삽질로그] - 여러 요청이 동시에 들어오면, Spring Boot는 어

mingking2.tistory.com

 


4. 궁금증 해결하기

위의 설명을 통해 Spring Boot가 요청을 동시에 받을 수 있다는 것을 알 수 있다.
그렇다면 요청을 동시에 받았을 때 내부에서는 어떻게 동작하는지에 대한 의문이 들었다.

 

여기서는 Spring Boot가 요청을 처리하는 방식과 동기/비동기의 개념을 명확히 정리하려고 한다.

💡 Spring Boot가 요청을 동시에 받는거고 결국 내부에서는 동기적으로 동작하는건가?

Spring Boot는 멀티스레딩 기반으로 동작하며, 요청을 동시에 받을 수 있다.

하지만 각 요청을 처리하는 로직은 기본적으로 동기(Synchronous) 방식으로 실행된다.

동작 과정을 실제 테스트를 통해 알아보자.

📌 내부 동작 테스트

@RestController
@RequestMapping("/sync")
@Log4j2
public class SyncController {

	@GetMapping("/process")
	public ResponseEntity<?> process(@RequestParam String request) throws InterruptedException {
		log.info("요청 처리 시작: {} - {}", request, Thread.currentThread().getName());
		Thread.sleep(3000); // 3초 동안 대기 (동기적 실행)
		log.info("요청 처리 완료: {} - {}", request, Thread.currentThread().getName());
		return ResponseEntity.ok("처리 완료! 요청: " + request);
	}
}

 

3개의 요청(A, B, C)을 동시에 보낸다.

curl 명령어를 백그라운드 실행(&)으로 동시에 실행하면 실제 실행 순서는 운영체제의 스케줄러가 결정한다.
즉, A, B, C 요청이 정확히 순차적으로 실행되지 않을 수 있다.
curl "http://localhost:8080/sync/process?request=A" &
curl "http://localhost:8080/sync/process?request=B" &
curl "http://localhost:8080/sync/process?request=C" &

 

📌 테스트 결과

✅ 각 요청이 서로 다른 스레드에서 병렬로 실행됨 (http-nio-8080-exec-1, http-nio-8080-exec-2, http-nio-8080-exec-3)

✅ 즉, 클라이언트의 요청을 “동시에” 받아서 각각 처리할 수 있음

✅ 하지만 내부 로직은 동기적으로 실행되므로 요청별로 따로 기다려야 함 (각 요청은 개별적으로 3초 걸림)

 

📌 동작 과정 정리

  1. 클라이언트가 여러 개의 요청을 보냄 (A, B, C 요청)
  2. Spring Boot의 내장 웹 컨테이너(Tomcat)가 요청을 스레드풀에서 사용 가능한 스레드에 할당
  3. 각 요청은 개별적인 스레드에서 실행되지만, 해당 요청이 처리되는 동안은 동기적으로 진행
  4. 요청이 완료되면, 스레드는 다시 스레드풀로 반환
  5. 새로운 요청이 들어오면, 반환된 스레드를 재사용하여 요청을 처리

 

✅ 즉, 여러 요청이 동시에 들어오더라도 각각의 요청은 독립적인 스레드에서 실행되므로 “동시에 요청을 처리할 수 있음”

각 요청을 처리하는 컨트롤러의 로직은 동기적으로 실행되므로,
비동기 처리가 필요하다면 @Async나 CompletableFuture 등을 사용해야 한다.

 

 

💡 요청을 동기로 받도록 설계하면 어떻게 될까?

Spring Boot는 기본적으로 멀티스레딩을 활용해 요청을 동시에 받을 수 있지만, 내부 로직은 동기적으로 실행된다.

그렇다면 요청을 동기적으로 받도록 설계하면 어떻게 될까?

 

동기적으로 요청을 받게 만들면, 하나의 요청이 끝날 때까지 다른 요청은 대기해야 한다.

이를 테스트하기 위해 의도적으로 모든 요청을 하나의 스레드에서 실행하도록 설계해보자.

 

📌 동기적으로 요청 테스트

위에서 언급했던 Java의 ExecutorService를 사용하여 코드를 작성했다.
private final ExecutorService executor = Executors.newSingleThreadExecutor(); // 단일 스레드 실행

	/*
	 * 단일 스레드로 요청을 동기적으로 받도록 테스트
	 * */
	@GetMapping("/sync-process")
	public ResponseEntity<?> processSync(@RequestParam String request) {
		executor.submit(() -> {
			try {
				log.info("요청 처리 시작: {} - {}", request, Thread.currentThread().getName());
				Thread.sleep(3000); // 3초 대기
				log.info("요청 처리 완료: {} - {}", request, Thread.currentThread().getName());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		return ResponseEntity.ok("처리 완료! 요청: " + request);
	}

 

curl "http://localhost:8080/sync/sync-process?request=A" &
curl "http://localhost:8080/sync/sync-process?request=B" &
curl "http://localhost:8080/sync/sync-process?request=C" &

 

📌 테스트 결과

✅ 모든 요청이 같은 스레드에서 실행됨 (pool-2-thread-1)

✅ B는 A가 끝날 때까지 대기, C는 B가 끝날 때까지 대기 (순차 실행)

✅ 총 실행 시간: 9초 (3초 x 요청 개수)

 

방식 요청 처리 방식 실행 스레드 응답 속도
동기 방식 요청을 하나씩 순차 처리 같은 스레드 느림 (3초 x 요청 개수)
비동기 방식 요청을 동시에 처리 여러 개의 스레드 빠름 (동시에 실행)

 

✔ 동기적으로 요청을 받으면, 하나의 요청이 끝나야 다음 요청을 받을 수 있어 성능이 떨어진다.

✔ Spring Boot 기본 방식(비동기 요청 처리)은 요청을 병렬로 처리할 수 있어 성능이 훨씬 뛰어나다.

 

요청을 동기로 받으면 서버의 처리 능력이 제한되며, 성능이 저하된다.

5. 결론

이번 글에서 Spring Boot가 멀티스레딩을 활용하여 동시 요청을 처리하지만, 개별 요청의 실행은 기본적으로 동기적(Synchronous)으로 진행된다는 점을 알 수 있었다.

💡 그런데, 동기 방식의 요청 처리만으로 충분할까?

지금까지의 내용만 보면, Spring Boot는 멀티스레딩을 활용하여 여러 요청을 동시에 받을 수 있으니 충분할 것처럼 보인다.

하지만, 대여기(아두이노)와의 통신을 예로 들어보자.

 

📌 대여기 시스템에서 발생할 수 있는 문제

  • 대여 요청이 동시에 여러 개 들어오면?
  • 아두이노(대여기)는 물리적으로 한 번에 하나의 요청만 처리할 수 있다면?
  • 대여기 응답이 지연되면 서버에서 요청을 대기해야 하는데, 그동안 다른 요청들은 어떻게 처리될까?

현재 동기적인 방식으로 요청을 처리하면, 하나의 요청이 완료될 때까지 다른 요청들은 대기 상태가 된다.

특히, 대여기의 응답 속도가 느려지면, 서버에서 해당 요청을 대기하고 있는 동안 새로운 요청이 빠르게 처리되지 못하는 문제가 발생할 수 있다.

 

🔍 그렇다면, 해결 방법은?

이러한 문제를 해결하기 위해서는, 서버에서 대여기 응답을 기다리지 않고 비동기적으로 처리하는 방식이 필요하다.

즉, 서버는 대여기의 응답을 기다리는 동안 다른 요청을 처리할 수 있어야 한다.

 

🚀 다음 글에서는 Spring Boot의 비동기 처리 기법을 활용하여
“서버가 대여기 응답을 기다리는 동안 다른 요청도 처리할 수 있는 방식”을 다룰 예정이다.

 

'삽질로그' 카테고리의 다른 글

Tomcat은 그냥 서버가 아니다?  (0) 2025.03.23
Spring Boot 비동기 처리 = 스레드풀?  (0) 2025.03.16
RDS 보안 정책 때문에 접속 불가?  (0) 2025.03.04
복잡한 웹소켓 핸들러, Event로 깔끔하게 해결하기  (0) 2025.03.03
Batch Insert로 API 응답 속도 175배 개선하기  (0) 2025.03.03
'삽질로그' 카테고리의 다른 글
  • Tomcat은 그냥 서버가 아니다?
  • Spring Boot 비동기 처리 = 스레드풀?
  • RDS 보안 정책 때문에 접속 불가?
  • 복잡한 웹소켓 핸들러, Event로 깔끔하게 해결하기
mingking2
mingking2
에러와 삽질 속에서 성장하는 응애 개발자의 성장 일지
  • mingking2
    Mingking의 삽질 기록
    mingking2
  • 전체
    오늘
    어제
    • 분류 전체보기 (19)
      • 삽질로그 (10)
      • 스타트업 응애기 (1)
      • 프로젝트 도전기 (2)
      • DB 모르는 백엔드 탈출기 (5)
      • 네트워크 (1)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    orm
    server
    Sync
    n:m
    batch
    context
    Java
    spring
    DB
    플로우차트
    JPA
    MVC
    WebSocket
    RDB
    Async
    @JoinColumn
    연관관계
    CompletableFuture
    Tomcat
    servlet
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
mingking2
여러 요청이 동시에 들어오면, Spring Boot는 어떻게 처리할까?
상단으로

티스토리툴바