면접에서 동기 & 비동기 묻는 이유

YoungHo-Cha·2022년 10월 1일
189

Web Flux

목록 보기
1/6
post-thumbnail

면접에서 단골질문으로 동기 및 비동기를 물어보는 이유가 무엇일까?

분명 중요해서 물어보는 것이다.

거기에 대해서 지극히 나의 개인적인 생각으로 글을 써볼 계획이다.

오늘은 Web에서 동기와 비동기를 만나게되는 상황을 살펴보자.


🚗 목차

  • 전통적인 서버
  • 새로운 서버
  • 결론

🔍 전통적인 서버

먼저 Web Server에서 전통적인 동기 방식에 대해서 살펴보자.

전통적인 서버는 다음과 같이 동작한다.

  1. Client에서 요청이 들어온다.

  2. 웹 서버에 Request가 도착한다.

  3. Thread Manager가 Thread pool을 확인한다.

  4. Thread pool에 쉬고있는 Thread가 존재하면 Request에 Thread를 할당하여 요청에 대한 처리를 진행한다.

  5. Thread pool에 남아있는 Thread가 존재하지 않는다면, Task Queue에 Request를 담고 Thread가 나올 때 까지 기다린다.

원래 minimum 만큼만 Thread를 할당하고 queue에 담는다. 여기서 queue가 꽉차면 thread pool의 thread 개수를 늘린다. 그렇게 반복되었을 때 Thread 최대 개수만큼 증가한다.

전통적인 서버의 단점

수 많은 요청이 생기고, 모든 Thread가 할당받아서 처리되는 중일때 엄청난 latency가 발생한다.

  • 엄청난 latency가 발생하는 이유가 무엇일까?

정답부터 말하면 Context Switching + Blocking때문이다.

Context Switching 부터 살펴보자.

Apache Tomcat 기준으로 default로 Thread pool의 Thread 개수는 200개이다.

cpu core가 5개라고 가정하고, 200개를 할당했을 때를 생각해보자.

코어는 대충 1개당 40개의 쓰레드를 번갈아가면서 돌린다.

각 코어마다 40개의 쓰레드를 스케줄링 알고리즘에 따라 골고루 cpu 할당 및 실행이 이루어진다.

이 경우에 엄청난 Context Switching이 이루어질 것이다. 그래서 latency가 발생한다.

물론 40개는 엄청나게 작을 수 있고, 무리가 없을 수 있다고 판단된다. 하지만 뒤에서 나오는 Blocking과 콜라보가 되면 시너지 효과때매 latency가 발생한다고 판단된다.

Blocking 을 살펴보자.

위에서 이야기를 했듯이, 한 코어당 40개의 쓰레드(스케쥴링에 따라 다를 수 있음)를 실행하게된다.

근데 여기서, 다음과 같은 상황이 있을 때를 생각해보자.

  • 다른 서버의 API에 데이터를 요청한다.
  • 디스크 I/O를 실행한다.

위의 두 경우에는 어떻게 해야하는가?

전통적인 방식에서는 다음과 같이 수행된다.

  • 다른 서버 API 또는 디스크 I/O가 끝날 때 까지, 해당 요청을 가지고 있는 쓰레드는 대기상태에 빠진다.

그럼 이 상황에 1개의 코어가 대기에 빠졌다는 것을 알 수 있다.

남은 코어는 4개이다. 4개의 코어가 199개의 요청을 전담마크해야한다.

거기다가 다른 코어에서도 blocking 되어버리면?

답이 없는 상황이다.

한마디로 blocking & Sync 되는 동안 Cpu가 놀게 된다.

새로운 서버

위와같은 문제들을 해결하기 위해서 새로운 형식의 서버가 언급이 되었다.

그림부터 살펴보자.

새로운 서버구성은 다음과 같이 동작한다.

  1. Request가 들어온다.

  2. 먼저 Event Queue에 담는다.

  3. 처음에 설정해둔 1개 이상의 쓰레드가 모든 Event를 스케쥴링하여 수행한다.

  4. 다른 API 호출 및 디스크 I/O가 존재할 경우, 쓰레드는 대기상태로 기다리지 않는다.

  5. 사용자에게 우선 return을 한다.

  6. 그리고 해당하는 작업이 완료되면, 비동기적으로 결과 값을 받는다.

  7. 완료된 작업을 사용자에게 Return한다.

앞선 전통적인 방법과 무엇이 다를까?

새로운 서버 장점

  1. 우선 쓰레드의 개수가 많이 필요없다.

전통적인 방식의 서버는 1 Request = 1 Thread 방식이다. 그래서 Thread가 꼭 필요하다.

하지만 새로운 서버는 설정해둔 Thread가 거의 모든 요청을 담당하기 때문에 Thread가 1개(여러개 설정도 함)이다.

그래서 Context Switching 비용을 고려할 필요가 없다.

  1. 비동기적인 처리가 가능해졌다.

요청에 대한 응답을 기다리지 않고, 자기의 할 일을 수행한다. 응답이 오면 원할 때 작업을 처리할 수 있다.

그래서 Blocking에 대한 걱정을 할 필요가 없다.

새로운 서버 단점

  1. 일단 프로세스 흐름을 전반적으로 예상하기 힘들다.

  2. 디버깅이 힘들다.

결론

묻는 이유는 여러가지 이유가 존재하겠지만, 기본적인 서버 latency를 발생시키는 주요 원인을 물어본 것이다.

지속적으로 발생하는 문제이고, 이에 대한 해결을 해나가는게 서버 개발자이다.

그래서 거기에 해당하는 기초를 물어본 것으로 판단된다.

프로세스, 쓰레드, Sync, Async, Blocking, Non-Blocking, Multi-Thread, Multi-Process, Race Condition, Dead Lock ... 등등

그냥 전부 다, "너가 오면 이런거때매 문제를 만날건데, 기초는 알고와야하지 않니?" 라는 뜻이다.

🔍 관련 라이브러리 및 프레임워크

이와 관련하여 수많은 라이브러리와 프레임워크가 존재한다. 관련 키워드들을 살펴보자.

Java

  1. Reactive Streams
  2. Future
  3. RxJava
  4. FutureTask

Spring

  1. Spring WebFlux
  2. DeferredResult
  3. Callable
  4. ResponseBodyEmitter

수 많은 것들이 더 존재한다.


나비 효과

위와 같이 서버를 맞추다보니 다른 기술 또한 나비 효과처럼 영향을 주게 되었다.

대표적으로 비동기식으로 즉각 처리에 대한 함수형 프로그래밍의 떡상, DB(Disk) I/O, NoSql 떡상 등등..(수많은 이유가 있겠지만 위 이유 또한 영향을 주었다고 생각한다.)

나에게 하고싶은 말

끝난 줄 알았지? 더 공부해 ^^

다음 글부터 Java의 비동기 프로그래밍 변천사를 쭉 살펴보며, 최종 WebFlux까지 전반적인 반응형 리액티브 자바 프로그래밍을 살펴볼 계획이다.

(추가적으로 시간이 된다면 카산드라, 코틀린까지 적용해볼 계획이다.)

profile
관심많은 영호입니다. 궁금한 거 있으시면 다음 익명 카톡으로 말씀해주시면 가능한 도와드리겠습니다! https://open.kakao.com/o/sE6T84kf

5개의 댓글

comment-user-thumbnail
2022년 10월 9일

좋은 글 잘보았습니다!
최근에는 Java19에 Project Loom이 드디어 도입(?)되서 초경량쓰레드인 파이버를 통한 블로킹 동기 서버 개발도 다시 주목받고있는 분위기더라구요! (물론 내부에서는 논블로킹으로 동작하지만) 쓰레드를 수백만개 동시에 돌려도 서버에 무리가 가지 않으니까요.
과연 SpringBoot 진영은 블로킹과 논블로킹 어떤 기술이 major가 될지 궁금하네요 :)

1개의 답글

동기와 선배를 알아보나 물어보려고(아님)

1개의 답글
comment-user-thumbnail
2022년 10월 23일

좋은 글 감사합니다.

답글 달기