1. 소개
- 현대의 소프트웨어 시스템은 점점 더 많은 동시 사용자와 데이터를 처리해야 합니다.
- 전통적인 동기-블로킹 방식의 프로그래밍은 이러한 요구사항을 감당하기 어려워졌고, 이는 비동기-논블로킹 프로그래밍의 필요성으로 이어졌습니다.
1.1 학습 목표
- 이 문서를 통해 다음을 이해할 수 있습니다
- 비동기-논블로킹 프로그래밍의 기반이 되는 각 계층의 핵심 개념
- 하위 계층의 기술이 상위 계층에서 어떻게 추상화되고 발전하는지
- 네트워크 프로토콜부터 웹 애플리케이션까지 전체 스택의 유기적 관계
1.2 왜 비동기-논블로킹인가?
- 전통적인 동기-블로킹 방식의 한계
- 요청당 하나의 스레드 필요
- 스레드 생성과 컨텍스트 스위칭 비용
- 메모리 사용량 증가
- 확장성 제한
- 비동기-논블로킹 방식의 이점:
- 적은 수의 스레드로 많은 요청 처리
- 시스템 리소스 효율적 사용
- 높은 처리량과 확장성
- 반응성 향상
- 이제 이러한 비동기-논블로킹 아키텍처가 어떻게 발전해왔는지, 가장 기본이 되는 네트워크 프로토콜부터 살펴보겠습니다.
2. 신뢰성 있는 데이터 전송의 시작: TCP
- TCP는 신뢰성 있는 데이터 전송을 보장하는 프로토콜입니다.
2.1 연결 생명주기
- 연결 수립 (3-way Handshake)
- SYN → SYN+ACK → ACK
- 초기 시퀀스 번호 동기화
- 양방향 통신 준비
- 데이터 전송
- 시퀀스 번호로 순서 보장
- ACK를 통한 신뢰성 확보
- 윈도우 사이즈로 흐름 제어
- 정상 종료 (4-way Handshake)
- FIN → ACK → FIN → ACK
- TIME_WAIT 상태로 안전한 종료
2.2 TCP 비정상 종료
- TCP 연결이 정상적인 4-way Handshake 과정을 거치지 않고 종료되는 경우를 비정상 종료라고 합니다.
- 비정상 종료는 크게 두 가지 형태로 발생합니다
- RST 패킷을 통한 강제 종료: 연결 종료 시 상대방에게 RST 패킷을 전송하여 즉시 연결을 끊는 방식
- 묵시적 비정상 종료: 물리적 연결 단절이나 시스템 장애로 인해 아무런 종료 신호 없이 연결이 끊어지는 경우
- 묵시적 비정상 종료를 감지하고 대응하기 위해 다음과 같은 방법을 사용합니다
- TCP Keep-Alive: TCP 프로토콜 수준에서 연결 상태를 주기적으로 확인
- Application Layer Heartbeat: 응용 프로그램 수준에서 주기적으로 상태 확인 메시지를 교환
2. OS 레벨의 진화: I/O 모델과 멀티플렉싱
2.1 I/O 모델의 발전
IO Models에서 설명하는 네 가지 I/O 모델의 진화:
- 블로킹 I/O
- 가장 기본적인 모델
- 작업 완료까지 스레드 대기
- 리소스 활용의 비효율성
- 논블로킹 I/O
- 즉시 제어권 반환
- 지속적인 상태 확인 필요
- CPU 자원 낭비 문제
- IO Multifexing
- 하나의 스레드로 여러 I/O 감시
- select/poll의 등장과 한계
- epoll을 통한 성능 개선
- Asynchronous IO
- 완전한 비동기 처리
- Linux의 io_uring 시스템 콜
- 커널이 I/O 완료 통지
- 가장 효율적인 리소스 활용