본문 바로가기

01. 시스템 계층과 요청 흐름

이 장의 핵심 연결: (시작하는 장) 이후 모든 장이 확대할 전체 지도를 폅니다.
다음 질문: 한 LLM 요청이 도착해 토큰이 나오기까지, 어떤 계층을 지나는가? 그리고 왜 그 여정을 두 갈래(control path / data path)로 나눠 봐야 하는가?
목표:
  • 한 요청의 여정을 계층으로 그리고, control path와 data path를 구분한다.
  • 이후 각 장이 이 여정의 "어느 부분"을 확대하는지 위치를 잡는다.

먼저: 왜 "여정"으로 시작하나요?

이 안내서는 개념을 하나씩 나열하지 않습니다. 대신 하나의 LLM 요청이 시스템을 통과하는 여정을 척추로 삼고, 각 장에서 그 여정의 한 부분을 확대합니다. 비트가 무엇인지(02장), 정밀도가 무엇인지(03장), 가속기가 무엇인지(04장)를 따로 배우는 대신, "요청이 지나가는 이 지점에서 비트가·정밀도가·가속기가 무슨 역할을 하는가"로 잇는 것이죠.

그래서 첫 장의 일은 지도를 펴는 것입니다.

일상 비유: 주방에 들어온 주문서

식당에 주문이 들어왔다고 합시다. 두 가지 다른 흐름이 동시에 일어납니다.

  • 주문서가 오가는 흐름: 손님 → 서버 → 주방장 → "몇 번 테이블, 파스타 하나" → 담당 요리사 배정. 이건 무엇을 언제 누가 할지 정하는 흐름입니다. 정보량은 적지만 결정이 여기서 납니다.
  • 재료와 요리가 오가는 흐름: 냉장고에서 재료를 꺼내고 → 도마·불 → 접시에 담아 → 손님에게. 이건 실제 무거운 것이 이동하고 가공되는 흐름입니다. 양이 많고, 병목도 대개 여기서 생깁니다.

LLM 요청도 똑같이 두 흐름으로 나뉩니다. 결정을 나르는 얇은 흐름과, 무거운 데이터를 나르는 두꺼운 흐름. 시스템을 읽을 때 이 둘을 섞으면 "왜 느린가"를 잘못 짚습니다.

정확한 정의: control path와 data path

  • control path(제어 경로): 요청을 어떻게 처리할지 정하는 흐름. 요청 접수, 인증, 큐잉(대기열에 넣기), 스케줄링(어느 워커·어느 가속기에 언제 배정할지 결정), 배치(batching) 구성 등. 오가는 정보량은 대체로 작습니다.
  • data path(데이터 경로): 실제 무거운 데이터가 이동하고 연산되는 흐름. 모델 가중치(weight)·입력 토큰·중간 활성값(activation)·캐시가 메모리와 가속기 사이를 오가고, 행렬 연산이 일어납니다. 양이 크고, 성능 병목이 주로 여기에 있습니다.
약어·용어 풀이
  • 워커(worker): 실제 추론 연산을 수행하는 프로세스. 대개 하나 이상의 가속기를 붙들고 있습니다.
  • 스케줄러(scheduler): 어떤 요청을 언제 어느 워커에 보낼지 정하는 구성요소.
  • 배치(batch): 여러 요청을 묶어 한 번에 연산하는 것. 묶으면 가속기를 더 알차게 쓸 수 있지만, 대기와 지연이 생길 수 있습니다(08장에서 지표로 다룹니다).
  • 활성값(activation): 모델이 계산 도중 만들어내는 중간 값들. 입력이 아니라 "계산 중간 산물"입니다.

이 두 경로를 나누는 이유는 단순합니다. "요청이 느리다"의 원인이 control path(대기·스케줄링)에 있는지, data path(연산·데이터 이동)에 있는지를 섞으면 진단이 어긋나기 때문입니다.

시각적 직관: 한 요청의 여정

flowchart TB
    subgraph CTRL[control path · 결정을 나르는 얇은 흐름]
        direction TB
        A[요청 도착<br/>API 게이트웨이]:::req --> B[인증·검증]:::req
        B --> C[큐 대기]:::req
        C --> D[스케줄러<br/>배치·워커 배정]:::req
    end

    subgraph DATA[data path · 무거운 데이터가 흐르는 두꺼운 흐름]
        direction TB
        E[워커 프로세스]:::compute --> F[가속기에서 연산<br/>행렬 곱]:::hw
        F --> G[메모리 오가기<br/>가중치·활성값·캐시]:::mem
        G --> F
        F --> H[토큰 하나 생성]:::result
        H --> F
    end

    D --> E
    H --> I[응답 스트리밍]:::result

    classDef req fill:#fef9c3,stroke:#ca8a04,color:#713f12
    classDef compute fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef mem fill:#ede9fe,stroke:#7c3aed,color:#4c1d95
    classDef hw fill:#cffafe,stroke:#0891b2,color:#164e63
    classDef result fill:#dcfce7,stroke:#16a34a,color:#14532d

주목할 점: data path 안에서 가속기 ↔ 메모리 사이를 여러 번 오가고(F↔G), 토큰이 하나씩 반복 생성(F→H→F)됩니다. 이 "반복"과 "오가기"가 뒤 장들(05 병목, 06 메모리, 08 지표)의 핵심 소재가 됩니다.

요청 여정을 시간순으로: 두 국면(prefill과 decode)

LLM 추론에는 성격이 다른 두 국면이 있습니다. 지금은 이름과 감만 잡고, 자세한 병목 분석은 05장에서 합니다.

sequenceDiagram
    participant U as 사용자
    participant S as 스케줄러(control)
    participant W as 워커+가속기(data)
    participant M as 메모리(data)

    U->>S: 프롬프트 전송
    S->>W: 워커 배정
    Note over W,M: prefill 국면<br/>입력 토큰 전체를 한 번에 처리
    W->>M: 가중치·입력 읽기
    W->>W: 병렬 연산
    W-->>U: 첫 토큰 (TTFT 시점)
    Note over W,M: decode 국면<br/>토큰을 하나씩 반복 생성
    loop 토큰마다
        W->>M: 캐시 읽고 쓰기
        W->>W: 다음 토큰 계산
        W-->>U: 토큰 하나
    end
용어 풀이
  • prefill(프리필): 입력 프롬프트 전체를 한꺼번에 처리해 첫 토큰을 준비하는 국면.
  • decode(디코드): 그다음부터 토큰을 하나씩 이어서 생성하는 국면.
  • TTFT(Time To First Token, 첫 토큰까지의 시간): 요청이 들어와 첫 토큰이 나오기까지 걸린 시간. 08장에서 정식으로 다룹니다.

이 두 국면은 일하는 성격이 다릅니다. prefill은 많은 토큰을 한 번에 처리하고, decode는 토큰 하나를 만드는 일을 계속 반복합니다. 왜 이 차이가 병목을 가르는지는 05·06장에서 설명합니다. 지금은 "요청은 하나여도, 안에서 성격이 다른 두 국면이 있다"만 챙기면 됩니다.

조건 명시: 이 그림이 성립하는·성립하지 않는 범위

내용
성립하는 조건서버 기반 LLM 추론 서비스의 일반적 구조를 개념적으로 그린 것. 계층을 나누고 두 경로를 구분하는 관점은 폭넓게 적용됩니다.
성립하지 않는 결론이 그림은 특정 제품·프레임워크의 실제 아키텍처가 아닙니다. 구성요소 이름·개수·경계는 시스템마다 다릅니다. 또한 이 그림만으로 "어디가 병목이다"를 말할 수 없습니다 — 병목은 워크로드·하드웨어 조건에 달렸고, 05장 이후의 소재입니다.

🔬 증거 읽기: 이 장의 주장은 어떤 유형인가

이 안내서는 모든 성능·사양 주장에 대해 출처 등급주장 유형을 밝히는 습관을 기릅니다. (자세한 틀은 09장, 부록.)

  • 출처 등급: PRIMARY(원 논문·공식 표준·제품 사양·공식 문서) / REPRODUCTION(조건·코드·결과를 공개한 독립 재현) / SECONDARY(해설·맥락).
  • 주장 유형: measured(공개 조건에서의 관측) / vendor-reported(owner·vendor의 보고) / calculated(공개 입력과 식을 남긴 산술) / inferred(자료를 연결한 해석).

이 장의 내용은 성능 수치가 아니라 개념적 구조입니다. 즉 특정 measured 값이 아니라, 시스템을 읽는 틀(inferred·교육적 모델)입니다. 그래서 "이 계층이 항상 이렇게 생겼다"는 vendor-reported 사실로 읽으면 안 됩니다.

⚠️ 흔한 오해

  • "느리면 GPU가 느린 것이다." — 아닙니다. 지연은 control path(큐 대기·스케줄링)에서 올 수도, data path(연산·데이터 이동)에서 올 수도 있습니다. 나누기 전엔 원인을 단정할 수 없습니다.
  • "요청 하나 = 연산 한 번." — 아닙니다. decode 국면은 토큰마다 반복됩니다. 요청 하나가 수백 번의 반복 연산일 수 있습니다.

이 장에서 배운 것

  • 이 안내서의 척추는 하나의 LLM 요청이 시스템을 통과하는 여정이고, 각 장은 그 여정의 한 부분을 확대한다.
  • 여정은 control path(결정을 나르는 얇은 흐름)data path(무거운 데이터가 흐르는 두꺼운 흐름)로 나눠 읽는다.
  • 추론에는 성격이 다른 두 국면, prefill과 decode가 있다.
  • "느리다"의 원인은 두 경로 어디에나 있을 수 있으므로, 나누기 전엔 단정하지 않는다.

🔎 이 장의 '지지하지 않는 결론'

  • 이 장의 계층 그림으로 "어디가 병목인지" 말할 수 없다. 병목은 워크로드·하드웨어 조건에 달렸고(05장), 이 개념도만으로는 판단 불가.
  • 이 그림은 특정 제품의 실제 아키텍처가 아니다. 구성요소의 이름·개수·경계를 이 그림에서 그대로 읽어내면 안 된다.

✍️ 확인 문제

  1. 어떤 요청이 "느리다"고 할 때, 원인이 control path에 있는 경우와 data path에 있는 경우를 각각 하나씩 예로 들어 보세요.
  2. prefill 국면과 decode 국면의 "일하는 성격"은 어떻게 다른가요? (한 국면은 왜 반복적인가요?)
  3. [조건 묻기] "이 계층 그림은 모든 LLM 서비스의 실제 구조다"라는 주장은 왜 이 장의 내용으로 지지되지 않나요? 이 그림이 실제로 지지하는 범위는 어디까지인가요?
다음 장: 02 · bit, byte, parameter, tensor — data path에 "무엇이 흐르는가"를 채웁니다. 파라미터를 담는 데 최소 얼마의 storage가 필요한지 직접 계산해 봅니다.