> For the complete documentation index, see [llms.txt](https://leehyokyun.gitbook.io/openbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://leehyokyun.gitbook.io/openbook/2-4..md).

# 2-4. 동기 / 비동기

제어권 위임을 기반으로 한 동기/비동기에 대하여

### 1. 동기/비동기 및 블로킹/논블로킹 : 본질적 제어권 기준 정의

* 동기/비동기 체계를 결정짓는 정확한 인식의 핵심 기준은 대기열 큐(Queue)의 유무나 큐의 활용 방식 자체가 아니며, 프로세스 간에 제어권을 넘기느냐 아니면 그대로 가지고 있느냐에 대한 주체성이다.
* 동기(Sync): 호출한 측이 상대방의 응답을 받을 때까지 작업을 대기하는 방식이다. 호출자가 제어권을 본인이 직접 계속 가지고 있으며, 이로 인해 상대방의 응답이 올 때까지 해당 스레드를 멈추는 흐름을 취한다.
* 비동기(Async): 호출자 측에서 요청을 전달하면, 그 작업에 대한 제어권을 처리를 전담하는 상대방 측으로 완전히 넘겨버리고 자신은 결과를 기다리지 않는 방식이다. 이 제어권을 넘긴다는 본질적 개념을 구현할 때, 애플리케이션(Application) 측에서 내부적으로 큐(Queue) 자료구조로 관리하느냐 아니면 또 다른 별도의 자료구조를 응용하여 관리하느냐의 세부 선택 사안이 존재하게 된다.
* 블로킹(Blocking)과 논블로킹(Non-blocking): 동기/비동기가 호출자의 응답 대기 여부와 제어권 향방을 다룬다면, 블로킹/논블로킹은 이 통신 제어로 인하여 실제 스레드(Thread)가 물리적으로 멈추느냐 움직이느냐를 결정하는 상태 기준이다.
  * 블로킹: 특정 시스템콜이나 데이터 요청 시 응답이 올 때까지 호출자 스레드를 강제로 대기 상태로 고립시킨다.
  * 논블로킹: 스레드가 물리적으로 대기하지 않으며, 응답을 기다리는 동안 아무것도 하지 못하는 유휴(Idle) 상태가 되지 않도록 제어권을 즉시 반환받아 프로세스를 지속 구동한다.

### 2. 비동기 통신 메커니즘의 물리적 실체와 복합 모델(Async + Blocking)

* 비동기(Async)의 구조적 본질: 비동기는 메시지 버퍼(Buffer)에 메시지를 임시 저장하고, 호출하는 측은 즉시 반환(return immediately)받아 기다리지 않는 것이 핵심 구조다. 즉시 반환 처리를 통해 결과적으로 처리 제어권을 처리 측에 위임하는 메커니즘을 달성한다.
* 통신 완료의 통지 원리: 버퍼에 저장된 메시지가 물리적으로 도달 완료했을 때, 시스템은 epoll() 등과 같은 커널 탐색 모듈을 통해 주기적으로 상태를 탐색 및 감지하여 콜백(Callback), 퓨처(Future), 이벤트(Event) 형태로 상위 스레드에 최종 완료를 전달한다.
* Async + Blocking 복합 모델: Kafka Producer의 작동 방식처럼, 프레임워크 호출 결과 자체는 비동기적으로 즉시 반환(Async)받았으나 내부 시스템 설계 구조나 특정 자원 점유 상황으로 인하여 스레드가 최종 응답이 확정될 때까지 물리적으로 대기하며 멈추는(Blocking) 형태의 처리 방식도 인프라 환경에서 명확히 존재할 수 있다.

### 3. 전통적인 Web MVC(Thread per Request) 모델의 Blocking I/O 프로세스와 한계점

* 전통적인 Spring Web MVC 구조처럼 요청 한 개당 스레드 하나를 동적으로 배정하는 Thread per Request 구조에서는, 다중 자원 경쟁이나 동기화 발생 시 기본적으로 블로킹(Blocking) 연산에 의존하게 된다.
* CPU 유휴화 및 리소스 낭비: 각 스레드가 내부 파일 시스템 및 데이터베이스(DB) 등 외부 시스템에 I/O 요청을 보낼 때, read() 시스템콜 호출 시점부터 데이터 응답이 수신될 때까지 스레드가 통째로 멈춘다. 데이터가 올 때까지 기다리는 동안 CPU는 아무런 일도 하지 않는 유휴 상태로 전환되므로 하드웨어 리소스 낭비가 극심해진다.
* 컨텍스트 스위칭(Context Switching) 비용 폭발: 처리해야 할 동시 요청 수가 많아져 스레드가 기하급수적으로 늘어날수록, CPU가 한정된 코어 위에서 여러 스레드를 전환하며 실행하기 위해 레지스터 상태를 바꾸는 스레드 전환 비용(컨텍스트 스위칭 오버헤드)이 비대하게 증가한다.
* 메모리 사용량 증가와 스케일 한계: 자바 환경에서 스레드가 생성될 때마다 각 스레드 고유의 독립적인 스택 메모리(Stack Memory) 영역이 필수적으로 할당되어야 하므로 메모리 사용량이 증가한다. 결과적으로 1만 개의 동시 요청이 들어왔을 때 1만 개의 스레드를 물리적으로 띄워 처리하는 방식은 스케일 아웃 및 장비의 한계로 인해 현실적으로 구현이 불가능하다.

### 4. Redis TCP 기반 요청 처리 프로세스 중심의 OS 커널 멀티플렉싱 I/O 제어 메커니즘

* 최초 요청 발생 및 네트워크 전송 단계: 클라이언트 측에서 분산 캐시 시스템인 Redis에 특정 데이터를 조회하거나 저장하기 위해 TCP 기반의 요청을 전송하면, 해당 요청은 TCP 패킷 형태로 네트워크 카드(NIC)를 거쳐 호스트 환경으로 인입된다.
* OS 커널의 접수 및 버퍼 적재 단계: 운영체제 커널(Kernel)이 이 물리적인 네트워크 요청을 일단 받고 통신 창구인 소켓(Socket) 버퍼에 안전하게 저장하고 관리한다.
* 커널 멀티플렉싱 I/O 감지 프로세스: 커널 레벨에서는 epoll 연산이 가동되어 수많은 소켓 연결 대상 중 실제로 읽을 수 있는 상태가 완료된 소켓들을 식별한다. 예를 들어 "3번 소켓에 읽을 데이터 있음"과 같은 상태 변화를 명확하게 감지하고 추적하는 것까지가 OS 커널 멀티플렉싱 I/O 영역의 경계이자 본질적 역할이다.

### 5. Application(Redis) 레이어 인계 및 이벤트 루프(Event Loop) 실행 프로세스

* 시스템콜을 통한 제어권 이양 단계: Redis 애플리케이션 측에서 커널이 제공하는 시스템콜인 epoll\_wait()을 동적으로 호출하여 "읽을 준비가 된 소켓이 있으면 나에게 알려줘"라고 요청한다. 이 명령을 통해 readable 상태로 판별된 소켓 목록과 제어권이 운영체제 경계를 넘어 애플리케이션 레이어로 인계된다.
* 이벤트 큐(Event Queue) 적재 프로세스: Redis는 인계받은 소켓의 상태 변화 요청을 감지하여 이를 개별 '이벤트(Event)'로 전환하고, 내부의 Callback Queue(대기열)에 차례대로 추가(Event to Queue)한다.
* 이벤트 루프의 추출 및 Call Stack 배치 단계: 단일 스레드(Single Thread) 기반으로 구동되는 무한 루프인 이벤트 루프(Event Loop)가 가동되어 Queue에 쌓여 있는 이벤트 작업을 하나씩 순차적으로 추출한 뒤, 현재 실행 중인 작업 공간인 Call Stack에 올려둔다.
* 최종 실행 및 응답 전송 프로세스: Call Stack에 배치된 작업 명령어가 최종 실행 완료되면 클라이언트에 최종 응답을 전송한다. 만약 타이머 연산(`setTimeout`)이 인입되는 경우, 동기적 작업은 Call Stack에서 즉시 처리되고 타이머 인스턴스는 Web API / OS I/O 처리 레이어로 위임되어 Timer Queue에 등록된다. 이후 이벤트 루프는 메인 Call Stack이 완벽히 비는 시점을 감시했다가 Timer Queue의 콜백을 꺼내와 최종 실행을 완수한다.

### 6. 이벤트 루프의 동기적 제약과 하부 비동기 I/O를 통한 "본질적 동작 원리"의 완성

* 런타임의 철저한 동기적 제약: Redis 이벤트 루프 자체는 단일 스레드로 구동되므로, 큐에서 작업을 하나씩 꺼내 Call Stack에 넣고 실행할 때 하나의 실행이 완벽하게 끝날 때까지 해당 스레드 점유를 그대로 유지한다. 만약 Call Stack에 올라간 특정 처리 작업이 CPU 연산을 과도하게 소모하거나 처리 시간이 오래 걸린다면, 스레드 점유가 지속되어 후속 이벤트들이 전부 가로막히는 대기 정체가 발생한다. 즉, 개별 실행 자체는 매우 철저하게 동기적(Synchronous)으로 수행된다.
* 하부 비동기 I/O를 통한 비동기 처리 환경 구축: 실행 자체는 동기적임에도 불구하고 Redis 시스템 전체가 초고속 비동기 엔진으로 작동하는 본질적 원리는, 요청과 응답에 대한 물리적인 하부 네트워크 I/O 완료를 스레드가 직접 멈춰 서서 기다리는 블로킹(Blocking) 동작을 전면 배제했기 때문이다. 결과 즉시 반환을 통해 처리 제어권을 처리 측에 위임하고, 제어권이 처리 측에서 유기적으로 보유 및 순환하는 비동기적 처리 환경을 확보했기 때문이다.
* 자원 효율성 및 동기화 오버헤드 제거: 이 구조적 이점을 통해 멀티스레드 인프라에서 필연적으로 발생하는 스레드 생성/관리 비용을 파격적으로 줄이고, CPU 레지스터를 교체하는 컨텍스트 스위칭 비용을 원천적으로 제거한다. 나아가 데이터 무결성을 위해 멀티스레드가 자원을 잠그는 뮤텍스(Mutex)나 동기화(Synchronization) 제어 작업이 전혀 존재하지 않으므로, CPU가 놀지 않고 가용 연산을 100% 쏟아부을 수 있는 고도로 최적화된 자원 방어력을 완성한다.

### 7. 동기 시스템콜(epoll)과 애플리케이션 결합을 통한 비동기적 효과의 실체

* 커널과 애플리케이션의 명확한 경계 분리: 인프라 통신 아키텍처 관점에서 OS Kernel의 Multiplexing I/O 연산과 Application(Redis)의 Event loop 동작은 서로 완전히 분리된 별개의 레이어 개념이다. epoll를 통해 요청 소켓들을 버퍼에 저장하는 것은 커널의 역할이며, 시스템콜을 통해 해당 준비된 소켓을 가져가는 것은 애플리케이션의 동작이다.
* 동기 시스템콜 기반의 역설적 비동기 연동: Redis가 호출하는 epoll 시스템콜 자체는 데이터가 반환될 때까지 대기해야 하는 명백한 동기(Sync) 시스템콜이다. 외부 클라이언트로부터 외부 유입된 요청(이벤트)이 아예 없을 때, 시스템은 epoll() 시스템콜 내부에서 제어권을 커널에 넘긴 채 그대로 유휴(Idle) 상태로 대기한다.
* 본질적 동작 원리를 통한 비동기 효과의 완성: 그러나 네트워크 카드로부터 물리적인 요청 패킷이 유입되는 바로 그 순간 epoll()이 즉각적으로 깨어나 소켓 목록을 애플리케이션에 전달한다. 따라서 시스템콜 자체는 동기일지라도 요청이 수입된 시점에만 정밀하게 결합하여 동작하기 때문에 무의미한 유휴 상태로 인한 자원 낭비가 사실상 전혀 없는 실질적인 비동기적 제어 효과를 창출한다.
* 애플리케이션 사이드의 최종 처리 책임: epoll() 시스템콜을 통해 커널 영역에서 준비된 소켓 데이터를 애플리케이션 메모리 영역으로 복사해 가는 동작(read() 호출)은 철저히 애플리케이션의 몫이다. 최종적으로 인계받은 소켓 데이터를 내부 이벤트 루프 상에서 동기적 기반으로 순차 처리할 것인가, 아니면 또 다른 내부 비동기 파이프라인으로 위임하여 처리할 것인가에 대한 아키텍처적 판단과 세부 연산 제어는 전적으로 애플리케이션 사이드(Application Side)의 권한이자 책임으로 귀속된다.

### 8. @Async

* 비동기 스레드 풀은, 동작하고자 하는 특정 스레드를 비동기 스레드 풀에 제출한 후, 해당 환경에서 워커 스레드가 제어권을 넘겨받아 동작하는 원리이다.
* 그 환경이 단일 스레드 기반(Redis의 단일 스레드 Event loop와 같은)일 수 있고, 병렬 처리를 위한 멀티 스레드 기반의 환경일 수 있다.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://leehyokyun.gitbook.io/openbook/2-4..md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
