본문 바로가기
  • 시 쓰는 개발자
1일 1개념정리 (24년 8월~)/운영체제

1일1개 (2) - 멀티 쓰레드 & spring 동시 요청 처리

by poetDeveloper 2024. 8. 10.
반응형

1일 1개념정리 24.08.09.금 ~ 

 

큰 결정에 큰 동기가 따르지 않을 때도 있다. 하지만 큰 결심이 따라야 이뤄낼 수 있다.

무조건 무조건 1일 1개의 개념 정리하기 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!


#2. 멀티 쓰레드

스프링을 공부하다보면, 쓰레드, 멀티쓰레드 등에 대해서 접하곤 한다. 일단 타자 치기 편하게 스레드라고 표현하겠다.

 

먼저 스레드에 대해서 알아보자. 스레드는 프로세스 내에서 작업이 수행되는 주체이다. 스레드를 보통 맥, 흐름 정도로 이야기하기도 하는데 프로세스 내에서 작업이 이루어지는 흐름이 묶여서 스레드라는 단위로 표현되었다고 이해하면 될듯하다. 그리고 이런 스레드가 여러개 있는 것을 멀티 스레드라고 한다. 프로세스와 스레드의 차이에 대해서는 다음 게시물을 참고하자. 스레드에 대해 모른다면 꼭 읽고오기.

https://100won-developer.tistory.com/entry/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-vs-%EC%93%B0%EB%A0%88%EB%93%9C

 

프로세스 vs 쓰레드

선 요약프로세스 = 독립적인 실행공간, 쓰레드 = 스택만 독립적이고 나머지는 공유 프로세스 = "프로그램"의 인스턴스 (= HDD에서 메모리로 올라온 프로그램을 의미)독립적인 실행 환경(자신만의

100won-developer.tistory.com

 

쓰레드 왜 쓰지 ?

  • 메모리 절약 : 스레드의 또 다른 이유는 바로 "경량 프로세스"이다. 매우 적은 메모리를 사용하므로 메모리를 절약할 수 있다. 아래 내용들도 결국 경량 프로세스라는 것으로 귀결된다.
  • context switching 좋음 : 경량 프로세스이기 때문에, context switching 비용 또한 적다. 예를 들어 컨텍스트 스위칭을 프로세스가 해야한다면 기억해야하는 정보가 많은데 스레드는 적기 때문에 빠르게 왔다갔다 할 수 있다는 것이다.
  • 동시성
    • 멀티 태스킹: 스레드를 사용하면 한 프로세스 내에서 여러 작업을 동시에 처리할 수 있다. 예를 들어 우리가 지금 블로그 글을 쓰면서도 백그라운드에서는 여러 작업이 돌아가는 것 처럼 말이다.
    • I/O 대기 시간 최소화: 파일 I/O처럼 시간이 오래 걸리는 작업이 스레드에서 처리되면 메인 스레드는 이런 작업 안기다리고 다른 작업을 계속할 수 있어서 효율적이다.

멀티 쓰레드

위에서 동시성에 대한 내용을 보면 결국 여러 작업을 동시에 처리할 수 있다는 말이다. 그럼 Spring에서 이를 어떻게 처리하는 것일까?? 대규모 서비스라면 많게는 몇백만명, 적어도 몇천명 몇만명이 동시에 사용하고 있을텐데 이를 어떻게 처리할까?? 여기선 대규모라는 맥락보단, 동시에 여러 요청을 처리한다는 맥락에 주목해보자. 한마디로 요약하면 이 다중요청을 처리하기 위해서 바로 멀티 스레드라는 개념이 사용된다.

 

<상황> - 지어낸 것임.

AI로 그린 그림이다 ...

 

여기, 손님이 오면 과일을 팔아야하는 상점이 있다. 가게가 너무 잘돼서 손님이 붐빌때가 있는데 이때 사장님 혼자서 모두를 대하기 어려워서 그냥 돌아가는 손님도 있었다. 일손이 부족해서 과일을 못파는 것은 사실 큰 손해이다.... 이를 해결하기 위해 사장님은 제자를 기르기로 결심했다! 제자들은 사장님의 비법을 전수받아서 과일을 팔기 시작한다. 이제 상점은 100명의 손님도 거뜬히 받을 수 있게 되었다. 근데 문제가 조금 있다.

  • 문제1) 일단, 제자를 얼마나 기를 것인지에 대한 문제이다. 손님이 얼마나 올지 모르는데 무턱대고 제자만 많이 뽑는다면 비용을 감당할 수가 없다. 그리고 적게 뽑았다면 손님이 갑자기 많아졌을 때 대응할 수가 없다 ...
  • 문제2) 그리고 사과가 많을 땐 괜찮은데, 사과가 거의 떨어진 경우 문제이다. 왜냐면 제자1과 제자2가 마지막 1개 남은 사과를 동시에 잡는다면 그 사과를 누구에게 팔 것인가?? 이는 모든 사과가 제자들에게 공유되어 생긴 문제이다.

역할부터 해석해보자.

  • 손님 : 요청
  • 과일 : 응답
  • 상점(사장님) : 프로세스
  • 제자 : 쓰레드

자, 그럼 문제를 하나씩 해결해보자.

 

문제 1 해결책 : 쓰레드 풀

손님이 많을 땐 제자가 적으면 문제고, 손님이 적을 땐 제자가 많은 게 문제다. 그러므로 제자를 미리 뽑아두는 것이다!! 딱 100명의 제자만 두고, 이들만 사용한다. 즉, 스레드를 미리 생성해두고 요청이 들어오면 그때마다 재사용 한다. 미리 생성된 스레드가 저장되는 곳을 바로 쓰레드 풀 이라고 한다. 제자를 뽑는 비용(스레드 생성비용)이 많이 들기 때문에 미리 뽑아두고 손님이 올때 계속 재사용한다는 것이다. 여기서 말하는 "비용"은 스레드 생성시 사용되는 메모리와 CPU 시간 등을 의미한다.

 

좀 더 구체적으로는, 다음과 같은 과정을 거쳐서 요청이 처리된다.

  1. 일단 스레드 풀은 Tomcat 안에 있다. 다중 요청을 처리하기 위해서 스레드 풀에는 미리 만들어진 스레드가 들어있다.
  2. 유저의 요청이 들어오면 스레드 풀에서는 스레드 하나를 꺼낸다. (200개의 스레드 저장)
  3. 이 스레드는 필터를 거친 후, 디스패처 서블릿에 의해 특정 작업에 할당된다.
  4. 작업이 끝나면 스레드는 다시 스레드풀로 돌아온다.

심화) 이를 그럼 Spring의 서블릿과 연관지어서 이해해보자 !!!

  1. 클라이언트가 요청 날림.
  2. 서블릿 컨테이너(Tomcat)는 요청을 받아서, 이를 처리할 디스패처 서블릿 호출함.
  3. 디스패처 서블릿은 요청을 분석하고, 이를 처리할 수 있는 적절한 서블릿을(controller를 의미) 호출함.
  4. 이때 서블릿이 요청을 "처리"할때 스레드가 사용되는 것임. 요청을 담당하는 서블릿까지 왔으면, 이제 클라이언트가 원하는 요청을 적절히 조합해서 응답을 만들어야하는데, 이 역할을 스레드가 하게 된다.
  5. 스레드가 요청 처리하고 결과를 생성해서 다시 디스패처 서블릿에게 반환함.
  6. 디스패처 서블릿은 결과를 HTTP 응답으로 변환하여 클라이언트에 반환함.
  7. 반환까지 끝났으니, 스레드는 다시 스레드풀로 반납함.

 

문제 2 해결책 : 동기화

하나의 프로세스 내에 여러 스레드가 있다. 스레드는 프로세스의 자원을 공유한다. 왜냐하면 쓰레드는 Stack만 독립적으로 가지고 있고, Code, Data, Heap은 공유하기 때문이다. 그래서 이런 문제가 발생한 것이다. 마지막 남은 사과는 공유 사과이다. 여러명의 제자가 상점의 과일을 공유하며 팔고 있으므로 제자1과 제자2가 동시에 이를 잡을 수 있다. 이를 "동시성 문제" 라고 한다.

  • 이를 해결하기 위해서 자원을 접근할 때 하나의 스레드만 접근할 수 있도록 제어한다. 즉, 하나의 사과는 한명의 제자만 잡을 수 있다.
  • Java에서는 synchronized 키워드를 사용하거나, Lock 객체를 사용해 특정 코드 블록에 대한 동시 접근을 제어할 수 있다. 이를 통해 어떤 제자가 사과를 잡고 있다면 다른 제자는 대기하고 있게 된다.

멀티쓰레드의 장단점

지금까지 멀티 쓰레드를 이야기 한 것이다. 최종 정리해보자.

 

장점

  • 동시에 여러 요청을 처리 가능.
  • CPU, 메모리가 허용하는 한 여러 요청 처리가 가능함.
  • 하나의 쓰레드에서 장애가 나도, 다른 쓰레드는 영향을 받지 않는다. 즉, 내가 어떤 사이트 들어갈 때 실패했는데 옆사람은 성공할 수 있다는 것. 물론, 스레드가 처리하는 요청이 시스템의 코어에 해당하는 요청이었다면 이것이 실패했을 때 시스템의 전체 장애로 이어질 수 있다.

단점 -> 해결책은 위에 상황 예시에 나온 것들

  • 쓰레드 생성에 제한이 없다면 CPU, 메모리 과부화로 인해서 서버 다운 가능. 물론 이는 스레드 풀을 이용해서 개수 정해놓고 관리 가능. (요청 200개 초과시 201번부턴 대기)
  • 스레드간 자원을 공유하기 때문에, 이때 동시성 문제가 발생할 수 있다.
반응형