CS 잡지식

Netty 서버(feat. 단일 스레드 이벤트 루프, 비동기,스프링은 비동기/Blocking..)

JIN_YOUNG _KIM 2023. 6. 26. 02:08

스프링 부트는 Spring [React] Web 사용 시, 톰캣이 아닌 Netty 서버를 자동으로 내장 서버로 등록을 한다. 

이것은 [싱글 스레드 이벤트 루프 기능과]  [비동기 기능]을 지원하는 서버이다. 

https://effectivesquid.tistory.com/65

 

Netty의 스레드 모델

Netty는 비동기 네트워크 프레임워크 입니다. 이번 글에서는 이 비동기 프레임워크가 어떻게 동작하는지 살펴 보겠습니다. Netty는 Channel에서 발생하는 이벤트들을 EventLoop가 처리하는 구조입니다.

effectivesquid.tistory.com

자세한 내용은 위 사이트를 참조

(톰캣도 단일 스레드 이벤트 루프와 비공기 기능을 지원하지만, 스프링 부트가 자동으로 Netty 서버로 등록을 해버린다.)

 

 

우선, 왜 Netty 서버를 쓰는지를 이해하기 위하여 [서블릿 기반의 스프링] 서버(스프링 4.0까지는 모두 서블릿 기반)가 어떤 방식으로 동작을 하는지를 알아야 한다.

 

서블릿 기반 스프링

클라이언트가 요청을 할 떄마다 쓰레드를 생성을 한다.(Multi Threading)

이 과정에서 일어나는 일을 구체적으로 한 번 알아 보자.

예를 들어, 클라이언트 a가 서버에 요청을 하게 되면, 서버에서 쓰레드를 생성해 낸다. 

이 쓰레드가 DB에 쿼리를 보내고, 쿼리 응답을 받는 시간까지 약 1초가 걸린다고 하자.

(DB가 다른 서버에 있다고 가정을 하자)

그럼 해당 쓰레드는 1초 동안 CPU를 차지하면 안 되고, CPU 사용을 대기하고 있는 다른 쓰레드에게

CPU를 양보해야 한다. 

고로 a 쓰레드에 Blocking이 걸린다.(쿼리 응답이라는 I/O 작업에 의해서!!)

1초가 지나면, CPU를 사용 중이던 다른 쓰레드에게 BLOCK이 걸리고, 다시 CPU 사용권을 a 쓰레드가 갖게 된다. 

여기에서 멀티 쓰레딩의 단점이 들어난다.

바로, 멀티 쓰레딩은 Context Switching 비용이 많이 들어 간다는 것이다. 

(물론 요청이 적어서 쓰레드가 많이 없으면 비용이 미미하지만, 요청이 많은 경우에는 비용이 의미있게 많아 진다.)

( 여기서 주의해야 할 점은 멀티 쓰레딩이라고 해서 꼭 Context Swtiching이 많이 들어가는 것은 아니다. 

non-blocking I/O 프로그래밍을 효울적으로 한 경우, 멀티 쓰레딩이여도 CPU 멀티 코어 환경을 잘 이용하여 Context Swiching 비용을 줄일 수가 있다. https://jbluke.tistory.com/109 참조)

 

위와 같은 [서블릿 기반 스프링]의 Context Swtiching 비용 문제를 해결하기 위하여 Spring 5.0부터는 비동기 처리 && 단일 

스레드 기법이 나와서, Context Swtiching 비용을 없앨 수 있게 되었다. 

Netty 서버가 바로 비동기 && 단일 스레드 서버이다. 

 

Netty 서버는 단 1개의 쓰레드만을 가진다. 

1] a로부터 요청이 들어옴

2] waiting queue에 a의 요청 처리 시간을 저장

3] 그 직후에 바로 b로부터 요청이 들어옴

4] waiting queue에 b의 요청 처리 시간을 저장

그런데 이 이후에 클라이언트로부터 아무 요청이 없다면 단일 쓰레드(Netty 서버)는 대기열에 가서 

a,b의 요청 시간이 다 되었는지를 확인하고, 다 되었다면 응답을 각 클라이언트에게 보내준다. 

5] c로부터 요청이 들어옴

6] c는 대기 시간이 없으므로, 대기열에 시간을 저장하지 않고 바로 응답을 보내 준다. 

7] 이 이후에 아무런 요청이 없다면 단일 쓰레드(Netty 서버)는 다시 대기열에 들어가서 체크를 한다. 

-> 위 과정을 반복한다. 

Netty 서버는 단일 쓰레드로 동작을 하기 때문에 Context 비용이 전혀 들지 않는다. 

 

서버가 비동기라면 DB도 비동기여야 한다. 

이게 Netty 서버(비동기 서버)가 MongoDB(비동기 DB)를 사용해야 하는 이유이다. 

 

만약 비동기 서버가 [동기] DB를 사용한다면 어떤 문제가 일어날까?

a 클라이언트가 요청을 보냈다고 하고, 그 요청을 처리하는 데에 DB가 3초 걸린다고 하자. 

동기 DB는 순차적으로 작업을 실행을 하기 때문에 3초 동안 다른 그 어떤 클라이언트로부터 요청을 받지 못한다.

(한 번에 하나의 요청 작업만을 DB에서는 실행하게 된다.) 

(원래 RDBMS는 동기 DB였으나, 최곤 R2DBC 라는 라이브러리를 사용하면, 비동기 사용이 가능하다고 한다.)