본문 바로가기

Development/관심거리

Blocking, Non-Blocking, Synchronous, Asynchronous

 

많이 들었으면서도 자주 헷갈리는 개념들. 

일단 결론부터 정리하자면, 

 

Blocking / Non-Blocking 방식은 Server 에서 Client 를 처리하는 Socket 동작 방식이고, 

동기 / 비동기 방식은 프로세스를 처리하는 방식이다.

 

 

 

 

* Blocking and Non-Blocking 방식.

 

1. Blocking 방식.

 

- single thread 방식.

server, client 작동 방식. request 를 받고 server 에서 처리 후 response 를 던져줄때까지 처리결과를 알 수 없었다.

server 의 프로세스를 한번에 한개의 (자식)thread 가 사용한다는 의미.

임의의 A 메소드를 호출하는 뒤의 요청은 앞의 요청이 끝날때까지 기다려야 한다는 뜻.

이런 방식은 thread 의 blocking 이 발생하기 때문에 multi thread 에 대한 처리가 불가능하다.

 

- multi thread 방식.

client 가 server 에 접속하면 server socket 의 accept() 메서드에서 socket 을 얻어오고 새로운 thread 를 생성해서 각각의 client 에 대한 요청을 처리하는 방식.

accept() 메서드가 병목지점이며 client 수가 많을 경우 대기시간이 길어질 수 있다.

접속하는 client 가 증가하면 thread 수도 증가하고 OOM 오류가 발생할 가능성이 있다.

 

- thread pool 방식.

위의 multi thread 를 개선한 방식. 미리 생성한 thread 를 pool 에 넣어두고 재사용한다.

위와 동일한 accept() 병목문제가 있다.

garbage collection 과 context switching 에 관한 문제가 있다.

 

 

2. Non-Blocking 방식.

 

위의 blocking 방식 문제들을 해결하기 위해서 나온 방식.

blocking, non-blocking 방식의 가장 큰 차이점은 I/O 처리방법이다.

단일 thread 로 동작하며 I/O 이벤트가 발생하면 목록에 저장하고 처리한다. 처리한 요청은 목록에서 삭제한다.

데이터를 읽고 쓰는 부분의 로직이 완전히 분리되어 있으며 socket 으로 부터 읽은 데이터는 각 이벤트에서 공유하는 데이터 객체를 생성하고 그 객체를 통해서 각 socket channel 로 전송한다.

blocking 방식은 여러개의 client 에 대한 요청을 여러개의 thread 를 이용해서 처리(multi thread, thread pool)하는 반면에 non-blocking 방식은 한개의 thread 가 처리한다.

 

예) netty 를 예로 들면.

netty 에서는 EventLoopGroup 을 사용해서 client 의 연결을 수락하는 parent thread 는 단일 thread 로 동작하는 NioEventLoopGroup 객체를 생성하고, 연결된 client 의 socket 으로부터 데이터 입출력 및 이벤트 처리를 담당하는 child thread 는 NioEventLoopGroup 객체를 이용해서 일반적으로 CPU 코어 수의 2배로 생성해서 사용한다.(임의의 갯수로 설정도 가능.)

 

 

 

 

* Synchronous and Asynchronous 방식.

 

- 비동기 방식의 경우 반환형으로 void 나 future pattern 사용.

- client 가 request 를 보내면 server 에서는 이를 받아서 1, 2, 3번 메소드를 실행한다고 가정할때 처리 시간이 오래 소요되는 1번 메소드가 종료되지 않아도 future 값을 설정하고 2, 3번 메소드를 실행한다. 이후 1번 메소드의 완료된 처리결과를 future 에 다시 할당한 뒤 마지막 메소드에서 이를 처리하고 response 에 담아서 반환하는 방식.