출처:
https://tech.peoplefund.co.kr/2017/08/02/non-blocking-asynchronous-concurrency.html // 개념정리
https://tv.kakao.com/channel/3150758/cliplink/391418995 // 토비 강연 영상
https://ztkmkoo.github.io/2017/12/13/spring-webflux/ // 공식사이트 번역해줌
토비 강연을 보는데 WebFlux 및 Non-blocking 등이 나온다.
Non-blocking이 왜 나오는지 자세히 봐야할 것 같아 정리한다.
출처의 내용이 더욱 상세함.
Spring boot 2.0 및 Spring 5가 릴리즈 되었는데 그 특징은 아래의 그림을 참고 하자.
두가지다.
Spring WebFlux/Reactive Stack 및 기존의 Spring MVC/Servlet Stack 으로 분류 된다.
non-blocking?
어떤 쓰레드에서 오류가 발생하거나 멈추었을 때 다른 쓰레드에게 영향을 끼치지 않도록 만드는 방법들을 말한다.
공유 자원(메모리, 파일 등)를 사용하는 멀티 쓰레드 프로그래밍을 할 때, 특정 공유 자원을 사용하는 부분에서 뮤텍스나 세마포어 등을 사용하여 여러 쓰레드에서 동시에 접근하지 못하도록 개발자가 보장하는 것이 전통적인 방법이었다.
반면 Non-blocking algorithm(Wait-freedom, Lock-freedom 등)을 사용하면 공유 자원을 안전하게 동시에 사용할 수 있다.
Non-blocking I/O란,
입출력 처리는 시작만 해둔 채 완료되지 않은 상태에서 다른 처리 작업을 계속 진행할 수 있도록 멈추지 않고 입출력 처리를 기다리는 방법을 말한다.
I/O 처리를 하는 전통적인 방법은 I/O 작업을 시작하면 완료될 때까지 기다리는 방법이다.
기존에는 synchronous I/O 혹은 blocking I/O를 통해 I/O 작업을 진행하는 동안 프로그램의 진행을 멈추고(block) 기다리는 방식이 사용되었으나, 이는 수많은 I/O 작업이 있는 경우 I/O 작업이 진행되는 동안 프로그램이 아무일도 하지 않고 시간을 소비하게 만든다.
반면, Non-blocking I/O 방식을 사용하면 외부에 I/O 작업을 하도록 요청한 후 즉시 다음 작업을 처리함으로써 시스템 자원을 더 효율적으로 사용할 수 있게된다.
그러나 I/O 작업이 완료된 이후에 처리해야하는 후속 작업이 있다면, I/O 작업이 완료될 때까지 기다려야 한다.
따라서 이 후속 작업이 프로세스를 멈추지 않도록 만들기 위해, I/O 작업이 완료된 이후 후속 작업을 이어서 진행할 수 있도록 별도의 약속(Polling, Callback function 등)을 한다.
Concurrency란,
각 프로그램 조각들이 실행 순서와 무관하게 동작할 수 있도록 만들어 한 번에 여러 개의 작업을 처리할 수 있도록 만든 구조이다.
좀 더 쉽게 말해 하나의 작업자가 여러 개의 작업을 번갈아가며 수행할 수 있도록 만드는 것이다.
동시성을 확보하게 되면, 작업 순서와 상관없이 각 작업이 완료되지 않았더라도 필요에 따라 번갈아 가며 작업을 수행함으로써 전체 작업 수행 속도를 향상시킬 수 있다.
Parallelism이란,
많은 작업을 물리적으로 동시에 수행하는 것으로써, 작업자를 물리적으로 여럿 둠으로써 같은 작업을 동시에 수행할 수 있도록 만드는 것이다.
병렬성을 확보하게 되면 물리적으로 동일한 시간 내에 동일한 작업을 더 여러 번 수행할 수 있게된다.
Concurrency와 Parallelism은 혼동하기 쉬운 개념이지만, 서로 의존관계가 없이 분리되어 있는 개념이다.
Parallelism은 한 개의 프로세서에서는 확보할 수 없는 개념이다.
한 개의 프로세서가 같은 시간에 두 개의 작업을 수행하는 것은 물리적으로 불가능하기 때문이다.
반면, 한 개의 프로세서만 있다고 하더라도 동시성을 확보할 수 있다.
잘개 쪼갠 작업들이 서로 영향을 끼치지 않는다면, 하나의 작업자가 각 작업이 완료되지 않았더라도 번갈아가며 수행하는 것이 가능하다.
Concurrency는 작업을 처리하는 방식을 개선함으로써 효율화를 가져오는 것이 목적이며,
Parallelism은 자원 자체를 늘림으로써 작업의 처리량을 늘리는 것이 목적이다.
Asynchronous Programming(비동기 프로그래밍)
프로그램의 주 실행흐름을 멈추어서 기다리는 부분없이 즉시 다음 작업을 수행할 수 있도록 만드는 프로그래밍 방식.
이는 코드의 실행 결과 처리 및 활용을 별도의 채널에 맡겨둔 뒤 결과를 기다리지 않고 바로 다음 코드를 실행하는 방식으로 프로그램을 진행한다.
결과를 처리하는 방식은 크게 보아 언어에서 지원하는 방식(future, promise와 같은 객체 형태의 결과를 요청 즉시 돌려받는 방식이나, Python의 코루틴(Coroutine)과 같은 언어의 문법을 이용하는 방식 등)을 사용하는 방식과 함수 전달을 통해 처리하는 방식(함수를 값처럼 사용(First-class function)하는 것을 지원하는 언어에서 콜백 함수(Callback function)를 전달하여 결과를 처리하는 방식) 등이 있다.
Non-blocking과 Asynchronous 그리고 Concurrency
Non-blocking은 앞서 짚어본 바와 같이 Non-blocking I/O를 의미할 수도 있고, Non-blocking 알고리즘을 의미할 수도 있다.
또한 Async라는 용어는 Asynchronous I/O를 의미할 수도 있고, Asynchronous Programming을 의미할 수도 있다.
I/O 작업을 멈추지 않고 기다리는 방식을 구체적으로 분류하면 Synchronous Non-blocking I/O와 Asynchronous blocking I/O 등으로 구분할 수 있기 때문에 이를 비교해보는 것은 의미가 있다.
그러나 Non-blocking I/O와 Asynchronous Programming은 비교 대상이 되기 어렵다. 각 개념이 바라보는 관점이 다르기 때문이다.
Asynchronous Programming을 위한 재료로써 Concurrency를 확보하거나 혹은 Non-blocking I/O를 활용할 수 있으나, 이것이 Asynchronous Programming의 필수조건은 아니다.
예를 들어 Event-loop를 사용하여 동시성을 확보했으나, I/O 작업의 성격에 따라 그 처리를 위해 blocking I/O 모델을 사용할 수 있다.
Blocking I/O를 사용했어도 이 부분이 별도의 채널을 통한 작업으로 이루어짐으로써 이 프로그램의 주 실행흐름(event-loop)을 막지 않았다면, 이 프로그램은 Asynchronous Programming이라고 부를 수 있다.
그럼 WebFlux가 왜 생겼냐??
- 더 적은 스레드와 더 적은 하드웨어 리소스로 동시성 문제(concurrency)를 non-blocking 웹 스택으로 해결하기 위해서
- Servlet 3.1에서도 non-blocking I/O를 지원하는 API를 제공하는 반면, 사용하게 되면 다른 Servlet API(Filter, Servlet, getParamter, getPart 등)를 사용하기 어렵다. 하지만 여러 서버들은 Netty 같은 비동기, non-block으로 잘 구성되어 있기 때문에 서버 runtime에서 non-block 기반 새로운 API를 제공할 필요성이 생겼다.
- 또 한 가지 이유는 함수형 프로그래밍. WebFlux는 Java 8에서 기존 어노테이션 컨트롤러와 함수형 웹 엔드포인트 두 가지 선택권을 부여함으로써 더 좋은 프로그래밍 모델을 만들수 있게 된다.
장점이 훨씬 많다.
CompletableFuture는 단순 비동기 I/O라 볼수 있다.
이후 내용은 테스트를 하면서 진행하는데 아래 링크를 보면 좋다!
https://zabdahan.tistory.com/entry/%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%84%9C%EB%B2%84%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0
'프로그래밍 > JAVA' 카테고리의 다른 글
Thread Dump & Heap Dump (0) | 2019.08.31 |
---|---|
자바8 Optional (0) | 2019.04.23 |
Collection remove에 대해 (0) | 2019.03.20 |
String, StringBuffer, StringBuilder (0) | 2019.03.19 |
Object의 메서드/equals/hashCode/clone (0) | 2019.03.19 |