(2019-10-06에 작성된 글입니다.)
나는 원래 Java를 사용하여 개발을 했는데, 이제는 Node.js 기반으로 개발을 하는 입장으로서 Non-Blocking에 대한 개념이 중요하게 됐고,
이에 더해서 Sync와 Blocking에 대한 차이도 이해하는 것이 필요하다고 느꼈는데,
최근 Slipp에서 주최한 세미나에서 자바지기님의 발표를 통해서 이러한 점이 명쾌하게 이해가 되었다.
이번 글은 그 기반으로 Sync & Async / Blocking & Non-Blocking 에 대해서 알아보고 정리한 것이다.
Sync & Async / Blocking & Non-Blocking
Sync와 Blocking, Async와 Non-Blocking 서로 비슷한 개념이라고 생각할 수 있다.
나 역시 이 점에 대해 다른 것이 없다고 생각해왔었다.
하지만 분명한 차이가 있고 그 차이는 이해하기 어렵지 않다.
Blocking vs Non-Blocking
I/O를 담당하는 함수를 호출했을 때 바로 리턴을 하느냐 아니냐
가 관심사이다.
- Blocking: 바로 리턴하지 않음
- Non-Blocking: 바로 리턴
Sync vs Async
I/O를 담당하는 함수의 작업 완료 여부를 누가 신경쓰느냐
가 관심사이다.
- Sync: Application
- Async: Kernel
I/O Models
앞서 살펴본 대략적인 개념만 기억하고 있으면 I/O Model에 대해 쉽게 이해할 수 있다.
(IBM 블로그 글을 보고 정리하였다.)
Synchronous blocking I/O
Synchronous blocking I/O는 가장 간단한 I/O model이다.
Application이 I/O 함수를 호출했을 때 바로 리턴을 하지 않고(Blocking) 끝날 때까지 대기한다.
이러한 대기 동안 아무것도 할 수 없다는 것이 가장 큰 단점이다.
Synchronous non-blocking I/O
Synchronous non-blocking I/O model의 경우,
Application이 I/O 함수를 호출했을 때 바로 리턴(Non-Blocking)을 한다.
하지만 Application이 I/O 작업이 끝났음을 알기 위해서 Application이 주기적으로 I/O 작업이 완료되었는지를 확인(Sync)해야한다.
주기적으로 확인하는 사이사이 다른 작업을 할 수 있지만 계속 확인해야하는 비효율성을 갖고있다.
Asynchronous blocking I/O
Asynchronous blocking I/O model의 경우,
Application이 I/O 함수를 호출했을 때 I/O 작업이 완료될 때 까지 blocking이 된다.
(함수 호출 후 바로 리턴을 받지만 Application은 다른 작업을 하지 않고 blocking 상태가 된다.)
I/O 작업이 끝나 Kernel에서 완료됨을 Application에게 알리면서(Async) Application의 blocking이 풀리게된다.
Asynchronous non-blocking I/O (AIO)
Asynchronous blocking I/O model에서 I/O 작업이 완료될 때까지 blocking이 되지 않고 다른 작업을 실행한다면 Asynchronous non-blocking I/O이다.
위와 같이 I/O System call을 호출하면 바로 응답을 받고(Non-Blocking),
I/O 작업이 완료되면 Kernel이 Application에게 I/O 작업 완료 signal을 보낸다(Async).
이 model의 장점은 Application이 I/O 요청 후 작업 완료를 직접 확인하지 않아, CPU가 다른 요청을 효과적으로 처리할 수 있다는 것이다.
Node.js와 Async I/O
Node.js의 Event Loop가 Single thread로도 많은 요청을 처리할 수 있는 것은 Async I/O 기반으로 I/O 작업을 처리하기 때문이다.
Node.js는 내부에 libuv
를 사용하는데 이를 통해 Node.js가 Async I/O를 사용할 수 있는 것이다.
libuv is a multi-platform support library with a focus on asynchronous I/O.
from libuv document
libuv의 내부 구조를 보면 아래와 같이 되어있는데 여러 OS에서도 일관된 AIO 인터페이스를 사용할 수 있도록 구현되어 있다.
Windows의 경우 IOCP
라는 Async I/O를 지원하는데, Windows가 아닌 경우 epoll, kqueue 등을 사용하여 Async I/O를 구현한 uv__io_t
라는 AIO Wrapper를 사용한다.
참고:
'ETC' 카테고리의 다른 글
WebSocket Server에서 Connection 'close' 이벤트를 받지 못할 때 (2) | 2021.01.06 |
---|---|
BCrypt로 Password Hashing 하기 (0) | 2021.01.02 |
logrotate 사용법 (0) | 2021.01.02 |
Github - Slack 연동 (w/ user mentioning) (0) | 2020.12.31 |
validation => insert V.S. insert => catch (0) | 2020.12.28 |
댓글