TCP/IP 네트워크 프로그래밍 공부를 하면서 나름 정리한 개념인데
만들어보면서도 알 것 같으면서도 어려운 개념인것 같다. 저기 어디에 메모 짱박아두다가 이제 정리 해 본다.
많은 사람들이 블록킹과 동기식을, 논블로킹과 비동기를 같은 용어로 생각하는데 엄연히 다른용어다.
우선 bloking I/O(블록킹), Non-blocking I/O(논블록킹)는 소켓의 동작방식을 나타내는 말이고,
그리고 Syncronous(동기), Asyncronous(비동기)는 서비스나 함수의 동작방식을 나타내는 말이다.
● Blocking I/O
블로킹 입출력 방식은 요청한 작업이 완료되지 않으면 응답을 돌려주지 않는다.
버퍼가 비어있을 경우, 입력이 들어올 때 까지 대기하며 그 동안 다른작업을 할 수 없다.
그러므로 자원의 낭비가 발생하게 된다.
blocking i/o와 달리 nio방식은 다수의 클라이언트의 요청을 처리할 수 있는데,
blocking i/o 에서는 스레드를 사용하여 해결할 수 있다.
하지만 과도한 요청수 만큼 발생한 스레드(멀티쓰레드)는 OOM(Out Of Memory)를 발생 시킬 수 있다.
이를 방지하고자 스레드를 사용하고 반납하는 형식으로 스레드의 개수를 제한하는 스레드풀을 사용한다.
스레드풀의 크기를 정하는 것에는 두가지 관점에서 생각할 필요가 있다고 한다.
첫 번째는 스레드의 개수는 힙에 할당된 메모리의 크기에 의존하는데
클 수록 관리해야 할 스레드 개수가 늘어나므로 가비지 컬렉션의 수행속도가 감소한다.
두 번째는 많은 스레드가 Context Switching(CPU를 점유하기 위한 상태변경)을 하면서
엄청난 오버헤드를 발생시킨다. 이는 cpu 성능저하의 원인이 된다.
쓰지 말라는 것이 아니고 용도에 맞게 적절하게 사용하는 것이 맞다.
하지만 멀티스레드를 사용하는 병렬처리는 공유자원에 대한 dead lock의 위험 때문에 프로그래밍 하는것이 쉽지 않다.
● Non-Blocking I/O (NIO)
논블로킹은 셀렉터(selector)나 폴(poll)에 여러 소켓을 바인딩 시킨 후
하나의 채널(싱글스레드)에서 관리하는 방식이다. 멀티플렉서에 비유한 것을 본 것 같기도하다.
셀렉터는 주기적으로 채널에 데이터가 들어왔는지 확인하는데
버퍼가 비어있을 경우 즉각 return 시키고 다음 요청을 받을 수 있기 때문에
멀티스레드에 비해 오버헤드가 적다.
● Syncronous (동기)
"동기" 라는 용어는 기본적으로 둘 사이의 싱크를 맞춘다는 말이다.
행위나 목적이 같은것을 시작과 끝을 맞추어 동시에 이루어 지는 방식이다.
● Asyncronous (비동기)
비동기는 요청이 들어와도 꿋꿋이 내가 하던 일을 한다. 들어온 요청은 맡겨버리고 "그 일 다끝나면 알려줘~" 하는 것이다.
그러므로 비동기는 수행되는 순서 및 시작과 끝을 알 수 없다.
동작방식은 메인스레드에서는 내가 하던일을 함과 동시에 요청받은 작업이 별도의 스레드에서 진행되는 거다.
작업이 끝나면 "다 끝났어 가져가" 하며 콜백으로 알려준다. 이러한 방식에는 델리게이트, 퓨처, 프로미스, 콜백 등이 있다.
동기와 비동기의 간단한 예제를 살펴보자.
1. 싱글스레드 + 동기식
스레드에서 순서대로 요청받은 작업을 처리한다.
하지만 앞의 작업이 모두 끝날 때 까지 뒤의 작업은 무한대기다.
2. 멀티스레드 + 동기식
각각의 스레드에서 요청을 1:1로 맡아 작업을 처리한다.
3. 싱글스레드 + 비동기식
일단 모든 요청을 결과에 상관없이 반환한다.
그리고 작업이 끝남과 동시에 결과를 알려준다.
4. 멀티스레드 + 비동기식
모든 요청을 여러 스레드가 나누어 결과에 상관없이 반환한다.
그리고 작업이 끝남과 동시에 결과를 알려준다.
가장 빠른 속도가 예상되며 2번과 3번을 섞은 느낌이다.
아래는 동기와 비동기 방식의 간단한 예제다 (출처 : http://malchooni.name/)
동기방식은 A노드와 B노드사이의 작업 처리 단위(transaction)를 동시에 맞추겠다는 뜻이다. ‘얄순이에게 보내는 말춘이의 오천원‘ 예를 보자. - 말춘계좌는 오천원을 뺄 생각을 하고 있다.
- 말춘계좌는 얄순계좌에게 오천원을 전송한다.
- 얄순계좌는 오천원이 수신되었단 걸 인지 하고 말춘계좌에게 ‘받았음’을 전송한다.
- 이로써 말춘계좌는 -5000원을 하고 얄순계좌는 +5000원을 한다.
이 예제에서 눈여겨 볼 부분은 마지막이다. 말춘계좌와 얄순계좌는 서로의 요청과 응답을 확인한 후 같은 일을 동시에 진행했다. ‘계좌이체’라는 작업단위는 위의 그림처럼 동기화를 해야한다. 그래야지 한쪽이 보냈는데 못받았거나, 안보냈는데 받은 상황이 없을 것이다. 비동기방식은 이와 반대로 노드사이의 작업 처리 단위를 동시에 맞추지 않아도 된다는 것이다. ‘말춘학생의 시험지는 얄순선생이 채점한다‘ 예를 보자. - 말춘학생은 시험지를 열심히 푼다.
- 시험지에 답안 작성을 완료한 말춘학생은 시험지를 얄순선생에게 전송한다.
- 얄순선생은 말춘학생의 시험지를 채점한다.
- 채점이 다 된 말춘학생의 시험지를 다시 전송한다.
- 말춘학생은 얄순선생이 채점한 시험지를 받아 본다.
말춘학생과 얄순선생은 시험지라는 연결고리가 있지만 시험지에 행하는 행위(목적?)은 서로 다르다. 한사람은 시험지를 푸는 역할을 또 한 사람은 그 시험지를 채점하는 역할을 한 것이다. 그래서 둘의 작업 처리 시각을 따지자면 일치하지 않는다. 일치하지 않아도 된다. 여기서 블록과 논블록의 차이를 간략히 설명해 보겠다. 말춘학생이 시험지를 얄순선생에게 건낸 후 얄순선생의 얼굴만 바라보며 채점 된 시험지를 받기 기다린다면 말춘학생은 블록 상태인 것이다. 하지만 말춘학생이 시험지를 건낸 후 채점이 완료 됐다는 이벤트를 받기 전까지 춤을 춘다거나 클래시오브클랜을 한다던가 다른 일을 하게 된다면 말춘학생의 상태는 논블록 상태인 것이다. 동기와 비동기, 블록과 논블록은 헷갈리기 쉬운 개념이다. * 자바네트워크 프로그래밍 블록과 논블록 * 마지막으로 정리를 하자면 동기와 비동기는 어떤 작업 혹은 그와 연관된 작업을 처리하고자 하는 시각의 차이이다. 동기는 추구하는 같은 행위(목적)가 동시에 이루어지며, 비동기는 추구하는 행위(목적)가 다를 수도, 동시에 이루어지지도 않는다. |