찐 개발자는 코드보다 먼저 데이터가 어디로 움직이는지 본다
Latency Numbers는 외워야 할 숫자표가 아니다. 메모리에서 네트워크, AI Agent까지 이어지는 성능의 원리를 전공 지식 없이도 개발에 적용할 수 있도록 풀어 본다.
AI는 빠르게 코드를 만들 수 있다. 개발자는 그 코드가 들어갈 시스템 전체를 보고 데이터 이동, 병목, 실패와 운영 가능성을 판단한다.
왜 이 글을 읽어야 하는가
Latency를 모르면 느린 시스템을 보고도 무엇부터 고쳐야 할지 결정하기 어렵다. 사용자는 “느리다”고 말하지만 원인은 CPU가 아니라 queue, DB round trip, cache miss, 큰 payload, 외부 API, retry 또는 물리적 거리일 수 있다. AI 서비스라면 model generation보다 tool 호출과 context 재처리가 더 오래 걸릴 수도 있다.
이 문제는 단순한 속도 취향이 아니다.
| 연결되는 문제 | Latency를 모르면 생기는 판단 착오 |
|---|---|
| 사용자 경험 | 평균 응답은 빠른데 p99 사용자는 반복해서 timeout을 겪는다. |
| 비용 | 같은 context와 tool 결과를 재전송하고 재계산하면서 token·network·GPU 비용을 늘린다. |
| 처리 용량 | throughput만 높이다 queue가 길어지고, 실제 동시 사용자에게 필요한 응답 속도를 잃는다. |
| 안정성 | 느려진 요청에 retry가 겹쳐 부하가 더 커지는 cascading failure를 만든다. |
| AI 코드 검수 | 기능 test만 통과한 N+1 query, 무제한 fan-out과 불필요한 agent loop를 승인한다. |
Google SRE의 네 가지 Golden Signals도 latency를 traffic, errors, saturation과 함께 본다. latency 증가는 시스템이 100% 사용되기 전에도 나타나는 saturation의 선행 신호가 될 수 있기 때문이다. 따라서 “이 함수가 빠른가?”보다 “어떤 부하에서 누가 무엇을 기다리고 있는가?”가 더 좋은 질문이다.
AI Agent에서는 한 번의 요청이 하나의 요청이 아니다
일반 API는 보통 요청과 응답의 경계가 비교적 선명하다. Agent는 목표 하나를 처리하는 동안 model을 여러 번 호출하고, tool과 DB를 오가며, 결과를 관찰한 뒤 다음 행동을 결정한다. handoff, subagent, guardrail, retry와 사람의 승인까지 들어가면 사용자 요청 하나는 여러 span이 이어진 trajectory가 된다.
flowchart TD
A["사용자의 목표"] --> B["Agent 판단"]
B --> C["Model call"]
C --> D["Tool·DB·API 호출"]
D --> E["결과 관찰·context 갱신"]
E --> F{"작업 완료?"}
F -->|"아니오"| B
F -->|"위임"| G["Subagent·handoff"]
G --> E
F -->|"예"| H["최종 결과"]
flowchart TD
A["사용자의 목표"] --> B["Agent 판단"]
B --> C["Model call"]
C --> D["Tool·DB·API 호출"]
D --> E["결과 관찰·context 갱신"]
E --> F{"작업 완료?"}
F -->|"아니오"| B
F -->|"위임"| G["Subagent·handoff"]
G --> E
F -->|"예"| H["최종 결과"]
Anthropic의 agent 설계 가이드는 agentic system이 더 나은 task performance를 얻는 대신 latency와 cost를 늘릴 수 있으므로, 필요한 경우에만 복잡성을 추가하라고 권한다. 2026년의 개발자에게 Latency Numbers가 더 중요해진 이유다. AI가 코드를 작성해도, loop와 tool을 몇 번 돌릴지, 어디에서 기다리고 언제 중단할지는 시스템 설계자가 결정해야 한다.
먼저 결론
Latency Numbers Every Programmer Should Know에서 정말 배워야 할 것은 숫자 암기가 아니다. 핵심은 코드 한 줄의 실행 시간보다 데이터가 어디에 있고, 어디로 이동하며, 무엇을 기다리는지가 전체 성능을 좌우한다는 감각이다.
이 관점을 익히면 서로 달라 보이던 문제가 하나로 연결된다.
메모리 계층
→ 데이터 이동과 locality
→ latency와 bandwidth
→ batching과 cache
→ queue와 tail latency
→ fan-out과 critical path
→ benchmark와 회귀 검증
내가 생각하는 ‘찐 개발자’는 모든 하드웨어 숫자를 외우는 사람이 아니다. 프레임워크와 API의 추상화 아래에서 어떤 데이터 이동과 대기가 발생하는지 질문하고, 자신의 가설을 실제 측정으로 확인하는 사람이다.
전공자가 아니어도 여기까지만 알면 된다
Latency Numbers를 이해하는 데 고급 통계나 컴퓨터 구조 지식이 꼭 필요하지는 않다. 숫자의 단위가 얼마나 차이 나는지, 평균이 무엇을 감출 수 있는지, 요청을 기다리는 시간을 어떻게 나누는지만 알면 뒤의 내용도 따라갈 수 있다.
latency는 한 숫자가 아니라 시간의 구성이다
요청이 1초 걸렸다는 사실만으로는 고칠 지점을 알 수 없다. 최소한 기다린 시간과 실제로 일한 시간을 나눠야 한다.
End-to-end latency
≈ queue wait
+ service time
+ data movement
+ external round trips
+ retry·coordination overhead
병렬 branch가 있다면 모든 시간을 단순히 더하지 않는다. 동시에 실행된 구간은 가장 늦은 branch가 critical path를 결정한다.
| 개념 | 쉬운 뜻 | 개발할 때 보는 이유 |
|---|---|---|
service time |
worker가 실제 작업을 수행한 시간 | 코드나 model 자체가 느린지 판단한다. |
queue wait |
worker를 배정받기 전에 기다린 시간 | capacity·batching·priority 문제를 찾는다. |
end-to-end latency |
사용자가 요청한 순간부터 결과를 받은 순간까지의 전체 시간 | 내부 지표가 아니라 실제 경험을 본다. |
concurrency |
같은 시간에 진행 중인 작업 수 | 동시 작업이 늘 때 queue와 contention이 커지는지 본다. |
utilization |
CPU·GPU·connection pool 같은 자원을 사용 중인 비율 | 100%에 도달하기 전부터 latency가 급격히 나빠질 수 있다. |
saturation |
들어오는 일을 제때 처리하지 못해 대기가 쌓이는 상태 | latency 증가가 단순한 일시 현상인지 용량 한계인지 구분한다. |
deadline |
이 시점 이후에는 결과의 가치가 낮아지는 완료 한계 | 불필요한 branch와 tool 작업을 취소할 기준이 된다. |
timeout |
기다림을 중단하고 실패로 처리하는 기술적 제한 | deadline보다 길거나 무제한이면 자원을 낭비한다. |
jitter |
같은 작업의 응답 시간이 들쭉날쭉한 정도 | 평균은 같아도 예측하기 어려운 사용자 경험을 드러낸다. |
latency budget |
전체 목표 시간을 구간별로 나눈 허용 시간 | 각 component가 무심코 전체 SLO를 소진하지 않게 한다. |
Google SRE의 SLO 설명은 latency를 평균보다 distribution으로 보라고 강조한다. 평균이 그대로여도 일부 요청이 20배 느릴 수 있고, workload가 다르면 interactive client와 throughput client의 목표도 분리해야 한다.
ns, µs, ms는 얼마나 다른가
컴퓨터가 다루는 시간은 너무 짧아 second만으로 나타내기 어렵다. 단위가 한 단계 바뀔 때마다 1,000배씩 차이가 난다.
| 단위 | 영문 이름 | 1초와의 관계 | 감각적으로 읽기 |
|---|---|---|---|
ns |
nanosecond | 10억 분의 1초 | CPU와 가까운 cache 접근을 설명할 때 자주 쓴다. |
µs |
microsecond | 100만 분의 1초 | memory block 처리나 매우 짧은 network 작업에서 볼 수 있다. |
ms |
millisecond | 1,000분의 1초 | disk, DB, API와 사용자가 체감하는 응답 시간을 설명할 때 자주 쓴다. |
s |
second | 1초 | 긴 network 요청, timeout과 전체 작업 시간을 살필 때 익숙한 단위다. |
1 ms = 1,000 µs = 1,000,000 ns
100 ns와 10 ms는 숫자만 보면 100과 10이라 뒤가 더 작아 보인다. 단위를 맞춰 보면 10 ms는 10,000,000 ns다. 무려 10만 배 차이다. Latency Numbers는 이런 자릿수 차이를 놓치지 않도록 정리한 표다.
average와 percentile은 무엇이 다른가
Average는 모든 측정값을 더한 뒤 개수로 나눈 평균이다. 전체 경향을 간단히 파악하기에는 좋지만, 일부 사용자가 겪는 아주 느린 요청은 가릴 수 있다.
Percentile은 측정값을 빠른 순서로 늘어놓았을 때 특정 값이 어느 지점에 해당하는지 나타낸다.
| 용어 | 쉬운 뜻 | 이렇게 읽는다 |
|---|---|---|
p50 |
중앙값에 가까운 일반적인 요청 | 요청의 약 50%가 이 시간 안에 끝났다. |
p95 |
느린 쪽 5%가 시작되는 경계 | 요청의 약 95%가 이 시간 안에 끝났다. |
p99 |
느린 쪽 1%가 시작되는 경계 | 요청의 약 99%가 이 시간 안에 끝났다. |
tail latency |
분포의 느린 끝부분 | 대부분은 빠르지만 드물게 매우 느린 요청이 생기는 문제다. |
예를 들어 100명이 같은 화면을 열었는데 99명은 금방 보고 한 명만 5초를 기다렸다고 하자. 평균만 보면 서비스가 그럭저럭 빠르게 느껴질 수 있다. 하지만 그 한 사람에게는 5초가 서비스의 실제 속도다. 결제, 검색, AI 응답처럼 반복해서 쓰는 기능에서는 이 느린 꼬리를 누군가가 계속 겪는다.
Percentile 계산 방식은 monitoring 도구마다 세부적으로 다를 수 있다. 처음에는 공식을 외우기보다 p99가 커졌다 = 느린 사용자 집단의 경험이 나빠졌다고 이해해도 충분하다.
이 글에 자주 나오는 시스템 용어
| 영문 용어 | 쉬운 뜻 | 일상적인 비유 |
|---|---|---|
latency |
요청 하나가 결과를 받을 때까지 기다리는 시간 | 주문하고 음식이 나오기까지 걸린 시간 |
bandwidth |
한 번에 옮길 수 있는 데이터의 양 | 도로의 차선 수 |
throughput |
일정 시간 동안 끝낸 작업의 양 | 한 시간에 처리한 주문 수 |
round trip 또는 RTT |
요청이 갔다가 응답이 돌아오는 데 걸린 왕복 시간 | 질문을 보내고 답장을 받기까지의 시간 |
queue |
아직 처리되지 않아 순서를 기다리는 요청의 줄 | 식당 앞 대기줄 |
batch 또는 batching |
여러 작업을 모아 한꺼번에 처리하는 방식 | 택배를 한 상자에 모아 보내기 |
cache |
다시 쓸 데이터를 더 가까운 곳에 보관하는 공간 | 자주 쓰는 물건을 책상 위에 두기 |
cache miss |
cache에서 데이터를 찾지 못해 더 먼 곳까지 가는 상황 | 책상에 물건이 없어 창고까지 찾으러 가기 |
locality |
자주 쓰거나 함께 쓰는 데이터를 가까이 두는 성질 | 같이 쓰는 도구를 한 서랍에 모아 두기 |
working set |
지금 작업에서 실제로 자주 사용하는 데이터의 범위 | 현재 책상 위에 펼쳐 놓고 쓰는 자료 |
fan-out |
요청 하나가 여러 하위 요청으로 퍼지는 구조 | 한 사람이 여러 사람에게 동시에 확인을 부탁하기 |
critical path |
전체 완료 시간을 결정하는 필수 작업의 흐름 | 가장 늦게 끝나면 전체 출발을 막는 준비 과정 |
SLA |
서비스가 지키겠다고 약속한 성능이나 가용성 기준 | 배송 예정 시간에 대한 약속 |
AI 문맥에서 자주 만나는 용어
| 영문 용어 | 쉬운 뜻 | 왜 중요한가 |
|---|---|---|
token |
모델이 글을 읽고 만드는 기본 단위 | context와 생성량이 커질수록 계산과 이동량도 늘어난다. |
context |
모델이 이번 요청에서 참고하는 입력 정보 전체 | 필요 이상으로 길면 처리 시간과 비용이 커진다. |
prefill |
입력 context를 먼저 읽고 계산하는 단계 | 긴 문서나 긴 대화에서는 첫 응답이 늦어지는 원인이 된다. |
TTFT |
Time to First Token, 첫 token이 나올 때까지의 시간 | 사용자가 AI가 반응하기 시작했다고 느끼는 시점이다. |
KV cache |
이전 token 계산 결과 일부를 재사용하도록 저장한 memory | 재계산을 줄이지만 memory 공간과 worker 배치의 영향을 받는다. |
HBM |
High Bandwidth Memory, accelerator가 대량의 데이터를 빠르게 읽도록 만든 memory | 모델 weight와 activation을 얼마나 빠르게 공급하는지에 영향을 준다. |
interconnect |
GPU, accelerator 또는 node를 잇는 연결망 | 여러 장비가 데이터를 주고받는 속도가 scale-out 성능을 제한할 수 있다. |
model weight |
학습으로 정해진 모델의 수많은 숫자 값 | inference 때 memory에서 읽어 계산 장치로 공급해야 한다. |
activation |
모델이 입력을 처리하면서 중간에 만들어 내는 값 | 계산 단계 사이에서 계속 생성되고 이동한다. |
성능을 측정하고 고칠 때 나오는 용어
| 영문 용어 | 쉬운 뜻 |
|---|---|
baseline |
변경 전 성능이다. 수정 뒤 얼마나 달라졌는지 비교하는 기준점이 된다. |
benchmark |
정해진 입력과 조건으로 성능을 재는 시험이다. |
microbenchmark |
함수나 연산처럼 아주 작은 부분만 떼어 재는 시험이다. |
trace |
요청 하나가 어떤 구간을 거쳤고 각 구간에서 얼마나 기다렸는지 남긴 기록이다. |
profile |
프로그램의 어느 코드가 시간이나 memory를 많이 쓰는지 분석한 결과다. |
serialization |
객체나 데이터를 network로 보내거나 저장할 수 있는 형태로 바꾸는 과정이다. |
regression |
변경 뒤 기능, 속도 또는 memory 사용량이 이전보다 나빠지는 현상이다. |
idempotency |
같은 작업을 여러 번 실행해도 결과가 한 번 실행했을 때와 같게 유지되는 성질이다. |
용어를 전부 외운 뒤 읽을 필요는 없다. 뒤에서 막히는 단어가 나왔을 때 이 표로 돌아오면 된다.
요청 하나를 쪼개 보면 어디가 느린지 보인다
사용자가 AI 검색 버튼을 눌러 답을 받기까지 800 ms가 걸렸다고 해 보자. 이 숫자만으로는 무엇을 고쳐야 하는지 알 수 없다.
| 구간 | 예시 시간 | 먼저 확인할 질문 |
|---|---|---|
queue wait |
120 ms | 요청이 처리되기 전에 왜 기다렸는가? |
| DB·검색 | 180 ms | 반복 조회나 불필요하게 큰 결과가 있는가? |
prefill과 모델 생성 |
350 ms | context가 너무 길거나 batch 대기가 섞였는가? |
| tool·network 왕복 | 100 ms | 외부 호출 횟수와 물리적 거리를 줄일 수 있는가? |
| serialization·merge | 50 ms | 같은 데이터를 여러 번 변환하거나 복사하는가? |
| 합계 | 800 ms | 가장 큰 구간부터 검증했는가? |
여기서 문법 몇 줄을 줄여 1 ms를 아끼는 일은 우선순위가 낮다. queue wait 120 ms나 DB·검색 180 ms를 줄일 여지가 있는지 먼저 보는 편이 낫다. 다만 여러 구간을 병렬로 실행했다면 단순히 전부 더해서는 안 된다. 이때는 가장 늦은 branch와 마지막 merge가 critical path를 만든다.
처음 성능을 살필 때는 네 가지만 기억하면 된다.
- 단위를 먼저 맞춘다.
ns,µs,ms를 섞어서 비교하지 않는다. - 평균과 함께
p95,p99를 본다. - 전체 시간을
queue, 계산, memory, DB, network 구간으로 나눈다. - 가장 오래 기다리거나 가장 자주 반복되는 경계부터 측정한다.
Latency Numbers는 왜 아직도 의미가 있을까
Jeff Dean의 2007년 발표에 등장한 수치는 오늘날 하드웨어의 성능표가 아니다. 실제로 2007판과 2009판 사이에서도 mutex, 압축, 디스크 순차 읽기 값이 달라졌다. 현재 시스템의 SLA로 복사해서는 안 된다.
그럼에도 표가 계속 회자되는 이유는 연산 계층 사이의 자릿수 차이를 한눈에 보여 주기 때문이다.
| 작업 | 2007 발표의 근사치 | 여기서 얻을 감각 |
|---|---|---|
| L1 cache 접근 | 0.5 ns | CPU에 가까운 데이터는 매우 싸다. |
| Main memory 접근 | 100 ns | cache miss가 누적되면 계산량이 같아도 느려진다. |
| 메모리 1 MB 순차 읽기 | 250 µs | 첫 접근 시간과 지속 전송 속도는 다른 문제다. |
| 같은 데이터센터 왕복 | 500 µs | 함수 호출처럼 보여도 네트워크 경계를 넘으면 비용 층위가 달라진다. |
| Disk seek | 10 ms | 무작위 I/O는 작은 CPU 최적화를 압도할 수 있다. |
| 대륙 간 왕복 | 150 ms | 물리적 거리와 왕복 횟수는 코드 미세 최적화로 제거할 수 없다. |
절대값은 낡았지만 메시지는 선명하다. 어떤 층위를 한 번 더 건드리는지가 작은 연산 몇 개보다 중요할 수 있다.
2007에서 2009로, 실제 숫자는 이렇게 달라졌다
두 발표에서 같은 이름으로 비교할 수 있는 항목 가운데 값이 달라진 것은 세 가지다. 여기서 mutex는 여러 작업이 같은 자원을 동시에 건드리지 못하게 막는 lock, Zippy는 당시 Google에서 사용한 압축 도구, disk seek는 disk가 원하는 데이터 위치를 찾는 동작이다. Read 1 MB sequentially from network는 2007 표에는 있었지만 2009 표에서는 빠졌다.
| 항목 | 2007 | 2009 | 변화 | 개발자가 읽어야 할 뜻 |
|---|---|---|---|---|
| Mutex lock/unlock | 100 ns | 25 ns | 4배 빨라짐 | 동기화 비용도 고정 상수가 아니다. CPU·OS·구현에 따라 다시 재야 한다. |
| Zippy로 1 KB 압축 | 10 µs | 3 µs | 약 3.3배 빨라짐 | 압축 여부는 network 절감량과 CPU 비용을 함께 비교해야 한다. |
| Disk에서 1 MB 순차 읽기 | 30 ms | 20 ms | 1.5배 빨라짐 | 같은 disk라도 seek와 sequential bandwidth를 분리해서 봐야 한다. |
| Network에서 1 MB 순차 읽기 | 10 ms | 표에서 제외 | 직접 비교 불가 | 항목이 사라진 것을 성능 개선으로 해석하면 안 된다. |
L1 cache 0.5 ns, main memory 100 ns, 같은 데이터센터 왕복 500 µs, disk seek 10 ms 등은 두 발표에 같은 값으로 실렸다. 이것은 2년 동안 실제 장비가 하나도 변하지 않았다는 증거가 아니다. 이 표가 정밀 벤치마크보다 자릿수 감각을 전달하는 교육용 근사치였다는 신호에 가깝다.
시간이 지나며 숫자보다 ‘질문’이 더 크게 바뀌었다
| 시기 | 중심 관점 | 대표적으로 묻는 숫자 | 설계 판단 |
|---|---|---|---|
| 2007 | 한 연산의 비용과 자릿수 | cache·memory·disk·network latency | 구현 전에 대략 계산하고 microbenchmark로 보정한다. |
| 2009 | server→rack→cluster storage hierarchy | 계층별 latency·capacity·bandwidth | 데이터가 어느 경계를 넘는지가 시스템 구조를 결정한다. |
| 2012–2013 | 대규모 fan-out과 분포의 꼬리 | p95·p99·p99.9, slowest branch | 평균보다 tail을 보고 backup·deadline·partial result를 설계한다. |
| 2026 AI | accelerator와 serving 전체의 balance | HBM·on-chip memory·interconnect bandwidth, energy, batch wait, KV-cache locality | FLOPS 하나가 아니라 이동·대기·재사용을 함께 최적화한다. |
flowchart TD
A["2007<br/>연산별 자릿수"] --> B["2009<br/>서버·랙·클러스터 계층"]
B --> C["2012–2013<br/>분포·fan-out·tail"]
C --> D["2026 AI<br/>HBM·interconnect·batch·KV cache"]
A -. "추정" .-> E["직접 측정"]
D -. "여전히 같은 원칙" .-> E
flowchart TD
A["2007<br/>연산별 자릿수"] --> B["2009<br/>서버·랙·클러스터 계층"]
B --> C["2012–2013<br/>분포·fan-out·tail"]
C --> D["2026 AI<br/>HBM·interconnect·batch·KV cache"]
A -. "추정" .-> E["직접 측정"]
D -. "여전히 같은 원칙" .-> E
즉 Latency Numbers의 역사는 단순히 숫자가 작아진 역사가 아니다. 단일 연산 → 계층 → 분포와 의존성 → 전체 시스템의 균형으로 개발자가 봐야 할 범위가 넓어진 역사다.
자릿수 차이를 몸으로 느끼는 환산표
2007 값에서 L1 cache 접근 0.5 ns를 사람이 느낄 수 있는 1초로 늘리면 다음과 같다. 실제 최신 장비의 성능표가 아니라, 계층 사이의 간격을 이해하기 위한 비율이다.
| 원래 작업 | 2007 근사치 | L1을 1초로 환산하면 |
|---|---|---|
| L1 cache 접근 | 0.5 ns | 1초 |
| Main memory 접근 | 100 ns | 3분 20초 |
| 메모리 1 MB 순차 읽기 | 250 µs | 약 5.8일 |
| 같은 데이터센터 왕복 | 500 µs | 약 11.6일 |
| Disk seek | 10 ms | 약 231일 |
| 대륙 간 왕복 | 150 ms | 약 9.5년 |
이 환산에서 얻을 교훈은 “cache miss를 절대 내지 말라”가 아니다. 느린 경계를 넘는 일이 필요하다면 한 번에 묶고, 겹쳐 실행하고, 재사용하고, 왕복 횟수를 줄이라는 뜻이다.
2026 AI·Agent 시대에는 무엇이 달라졌나
고전 Latency Numbers가 한 연산과 한 번의 데이터 이동에 대한 감각을 줬다면, 2026년에는 그 감각을 긴 실행 경로 전체로 확장해야 한다.
| 고전적인 질문 | 2026 Agent 시대의 질문 | 바뀐 이유 |
|---|---|---|
| 이 연산은 몇 ns·µs·ms인가? | 한 task가 몇 turn·tool call·handoff를 거치는가? | 요청 하나가 반복되는 trajectory가 됐다. |
| 데이터가 cache에 있는가? | context·tool prefix·KV cache를 같은 worker에서 재사용하는가? | text context도 계산된 memory state가 됐다. |
| endpoint p99는 얼마인가? | task completion p95·p99와 성공률을 함께 만족하는가? | 빠르게 실패하거나 틀린 결과를 내는 것은 개선이 아니다. |
| 서버 한 대의 처리량은 얼마인가? | 목표 TTFT·output speed를 지키며 동시 agent session을 몇 개 처리하는가? | agent는 긴 sequence와 tool 대기를 번갈아 만든다. |
| 함수 profile에서 어디가 느린가? | model·tool·handoff·guardrail·retry 중 slowest span은 무엇인가? | 병목이 application과 model 경계를 계속 오간다. |
| memory 사용량은 얼마인가? | context 증가, cache retention과 session 수가 비용·capacity에 어떤 영향을 주는가? | 한 사용자의 state가 여러 turn과 worker에 걸쳐 살아남는다. |
이제는 ‘응답 시간’보다 ‘작업 완료 시간’을 본다
Chat UI에서 첫 token이 빨리 나오는 것은 중요하지만, Agent가 파일을 수정하고 test를 실행해 검증하기까지 2분이 걸린다면 TTFT만으로는 실제 속도를 설명할 수 없다. 반대로 첫 반응은 조금 늦더라도 불필요한 tool call과 revision을 줄여 전체 task를 빨리 끝내면 더 좋은 시스템일 수 있다.
그래서 Agent의 latency는 여러 층으로 본다.
| 층 | 대표 지표 | 답하는 질문 |
|---|---|---|
| 사용자 | task completion p50·p95·p99, timeout, success rate | 사용자는 유용한 결과를 언제 받았는가? |
| workflow | turn 수, tool call 수, retry·handoff 수, slowest span | 어떤 경로가 시간을 증폭했는가? |
| model | TTFT, inter-token latency, tokens/sec, input·output token | model 호출은 얼마나 빨리 시작하고 지속되는가? |
| context·cache | cached input token, prefix reuse, eviction, recompute | 같은 정보를 다시 읽고 계산하고 있지 않은가? |
| runtime | queue wait, active request, concurrency, saturation | model이 아니라 배정을 기다리는가? |
| 외부 경계 | DB·API RTT, payload bytes, rate limit | tool과 data source가 critical path를 만들고 있는가? |
| 품질·비용 | task success, token·tool 비용, 사람 개입 횟수 | 더 빠른 결과가 실제로 쓸 만하고 경제적인가? |
OpenTelemetry의 2026 GenAI observability 예시는 agent trace를 invoke_agent 아래의 model chat span과 execute_tool span으로 나누고, operation duration과 token usage를 함께 본다. OpenAI Agents SDK의 tracing 문서도 model generation, function tool, handoff와 guardrail을 각각 span으로 기록한다. 특정 제품을 써야 한다는 뜻이 아니라, Agent 성능을 최종 응답 숫자 하나가 아니라 실행 경로로 관찰하는 방식이 표준화되고 있다는 신호다.
context locality는 새로운 memory locality다
고전적인 locality는 CPU가 곧 쓸 데이터를 cache 가까이에 두는 문제였다. Agent에서는 system instruction, tool definition, conversation history와 반복되는 code context가 같은 역할을 한다. worker가 바뀌거나 KV cache가 사라지면 같은 prefix를 다시 계산해야 한다.
Markdown Search MCP에서 확인한 NVIDIA Dynamo 자료는 agent harness가 session id, priority, 예상 output length와 재사용 가능한 prefix 같은 힌트를 serving layer에 전달하는 방향을 설명한다. NVIDIA의 2026년 coding-agent session 예시는 main agent와 subagent가 많은 요청과 긴 context를 만들며 cached token을 반복 사용한다고 보고한다. 이는 vendor가 제시한 사례이므로 수치를 일반화할 수는 없지만, context 구조와 cache lifecycle이 latency·비용·capacity의 공동 변수라는 관점은 실무적으로 유용하다.
동시 Agent 수는 throughput만으로 결정되지 않는다
2026년 공개된 AA-AgentPerf는 목표 output speed와 p95 TTFT를 만족하면서 동시에 처리할 수 있는 agent 수를 측정한다. benchmark의 hardware 성능 주장은 독립 재현이 필요하지만, 측정 방식이 주는 교훈은 분명하다. 동시 요청 수를 높였다는 사실보다 사용자에게 약속한 속도를 유지한 동시 session 수가 중요하다.
이 관점은 일반 backend에도 같다. Google의 Prequal 연구는 CPU load 자체보다 예상 latency와 active requests-in-flight를 이용해 server를 선택한다. 자원 사용률 하나만 균등하게 만드는 것과 사용자의 대기 시간을 줄이는 것은 다른 목표다.
원리 1: 메모리는 하나가 아니다
개발 코드에서는 흔히 데이터를 “메모리에 있다”고 표현한다. 하지만 CPU register(연산 장치 내부의 아주 작은 저장 공간), L1·L2 cache(CPU에 가까운 고속 저장 공간), main memory(보통 RAM을 가리킨다), GPU HBM, 다른 GPU의 memory, SSD와 원격 저장소는 같은 장소가 아니다.
데이터가 계산 장치에서 멀어질수록 이동 경로와 기다릴 지점이 늘어난다. 좋은 설계는 먼 계층을 없애기보다 꼭 필요한 횟수만 오가게 만든다.
flowchart TD
A["연산 장치"] -->|"가까움·작음"| B["L1 / on-chip memory"]
B --> C["Main memory / HBM"]
C --> D["다른 GPU·다른 서버"]
D --> E["SSD·원격 저장소"]
E -->|"멀어짐·대기와 이동 증가"| F["외부 API·대륙 간 network"]
flowchart TD
A["연산 장치"] -->|"가까움·작음"| B["L1 / on-chip memory"]
B --> C["Main memory / HBM"]
C --> D["다른 GPU·다른 서버"]
D --> E["SSD·원격 저장소"]
E -->|"멀어짐·대기와 이동 증가"| F["외부 API·대륙 간 network"]
이 그림은 모든 요청이 왼쪽에서 오른쪽으로 순서대로 이동한다는 뜻이 아니다. 개발자가 데이터의 현재 위치와 다음 이동 경계를 확인하기 위한 거리 지도다.
성능 차이는 저장 공간의 이름보다 다음 세 가지 관계에서 나온다.
거리가 멀수록 대기와 이동 비용이 커진다
CPU가 필요한 데이터를 가까운 cache에서 찾으면 바로 계산할 수 있다. 찾지 못하면 더 먼 계층으로 내려간다. GPU에서도 계산 장치가 아무리 빨라도 필요한 tensor나 KV cache를 제때 공급하지 못하면 연산기는 기다린다.
연속 접근과 무작위 접근은 다르다
같은 1 MB를 읽어도 연속된 구간을 읽는 것과 흩어진 위치를 따라가는 것은 다르다. 연속 접근은 cache line(한 번에 가져오는 작은 데이터 묶음), prefetch(곧 쓸 데이터를 미리 읽는 동작)와 높은 bandwidth를 활용하기 쉽다. pointer chasing(주소를 따라 다음 데이터를 찾는 접근)과 random access(흩어진 위치를 읽는 접근)는 작은 데이터라도 반복적인 miss를 만들 수 있다.
데이터 구조가 곧 성능 구조다
객체를 예쁘게 나눈 설계가 실행 시에는 수많은 작은 allocation과 간접 참조를 만들 수 있다. 반대로 자주 함께 읽는 데이터를 가까이 배치하면 알고리즘을 바꾸지 않고도 locality가 좋아진다.
그래서 개발할 때는 “이 로직의 시간복잡도가 무엇인가?”와 함께 다음을 물어야 한다.
working set은 얼마나 큰가?
자주 쓰는 데이터가 cache에 머물 수 있는가?
접근은 연속적인가, 무작위인가?
같은 데이터를 몇 번 복사하는가?
CPU와 GPU, GPU와 GPU 사이를 몇 번 오가는가?
원리 2: latency와 bandwidth를 구분해야 한다
“메모리가 빠르다”, “네트워크가 빠르다”, “모델이 빠르다”는 표현만으로는 부족하다.
Latency는 요청하거나 전송을 시작한 뒤 첫 결과를 받기까지의 대기 시간이다.Bandwidth또는throughput은 일정 시간 동안 얼마나 많은 데이터를 처리할 수 있는가다.
고속도로 차선이 많아도 목적지가 멀면 첫 차가 도착하는 시간은 길 수 있다. 반대로 가까운 길도 차선이 하나뿐이면 많은 차량을 한꺼번에 보내기 어렵다.
AI 서비스에서는 이 차이가 더 분명하다.
| 지표 | 답하는 질문 |
|---|---|
| Time to First Token | 사용자가 첫 반응을 언제 보는가? |
| Inter-token latency | 생성되는 동안 체감 속도가 안정적인가? |
| Tokens/sec | 지속 생성 처리량은 얼마인가? |
| Batch wait | 처리 시작 전에 queue에서 얼마나 기다렸는가? |
| End-to-end p95·p99 | 느린 사용자까지 포함하면 얼마나 걸리는가? |
batch를 크게 만들면 데이터 이동과 계산을 여러 요청에 나눠 처리할 수 있어 throughput이 좋아질 수 있다. 그러나 batch가 모일 때까지 기다리면 개별 사용자의 latency는 나빠진다. 처리량 개선이 곧 사용자 경험 개선은 아니다.
원리 3: 계산보다 데이터 이동이 비쌀 수 있다
Jeff Dean은 2026년 YC 인터뷰에서 AI 시스템 개발자가 알아야 할 숫자로 accelerator 내부 memory bandwidth, 연산 에너지, chip 간 interconnect bandwidth, 연결 규모가 커질 때의 bandwidth 저하를 들었다.
이 관점의 핵심은 “GPU가 몇 FLOPS인가?”만 보는 데서 벗어나는 것이다. FLOPS는 1초에 수행할 수 있는 부동소수점 연산 횟수다. 실제 workload에서는 model weight, activation, KV cache와 intermediate result가 계속 이동한다. 계산 장치가 빨라도 데이터를 공급하지 못하면 전체 시스템은 빨라지지 않는다.
2026년 AI 시스템에서 고전적인 숫자표를 그대로 복사하는 대신, 다음 경로를 자신의 workload로 측정해야 한다.
| 경로·구간 | 함께 볼 지표 | 나쁠 때 드러나는 현상 | 검토할 선택 |
|---|---|---|---|
| Accelerator main memory → on-chip memory | bandwidth, cache hit, stall | 연산기는 놀고 memory를 기다림 | layout, fusion, tiling, working set 축소 |
| GPU → GPU / node → node | link별 bandwidth·latency | scale-out 효율 저하, collective 지연 | topology, partition, communication overlap |
| Queue → batch 실행 | batch wait, TTFT, tokens/sec | 처리량은 높지만 첫 응답이 느림 | dynamic batching, deadline, 우선순위 |
| Prefix·KV cache → worker | hit rate, eviction, recompute | 같은 context를 반복 계산 | session affinity, cache-aware routing |
| Agent → tool·DB·API | round-trip 수, payload bytes, p99 | 모델보다 외부 호출이 더 오래 걸림 | batching, projection, artifact reference, timeout |
Markdown Search MCP에서 찾은 NVIDIA의 NVbandwidth 자료도 같은 원리를 실측 도구로 보여 준다. 이 도구는 host-to-device, device-to-host, GPU-to-GPU와 multi-node 경로의 bandwidth와 latency를 따로 잰다. 중요한 점은 제품명이 아니라 전송 경로별로 직접 측정한다는 방법이다.
웹·백엔드 개발에서도 구조는 같다.
- DB에서 100개 row를 한 번에 가져올 일을 반복문 안에서 100회 조회한다.
- service 사이에서 같은 JSON을 여러 번 serialize하고 deserialize한다.
- 필요한 필드 몇 개 대신 큰 payload 전체를 전송한다.
- 같은 원격 데이터를 단계마다 다시 읽는다.
- AI agent가 tool output과 긴 대화 기록을 매 호출마다 다시 전달한다.
코드는 서로 달라도 모두 “계산이 아니라 이동과 왕복 횟수가 병목”이라는 같은 문제다.
원리 4: 평균이 아니라 꼬리가 사용자를 기다리게 한다
평균 latency가 좋다는 말은 느린 요청이 없다는 뜻이 아니다. Jeff Dean의 2012년 예시에서는 한 서버가 1초 이상 걸릴 확률이 1%일 때, 100개 서버의 결과를 모두 기다리는 요청이 적어도 하나의 느린 서버를 만날 확률은 약 63.4%다.
P(적어도 하나가 느림)
= 1 - P(모두 빠름)
= 1 - (1 - 0.01)^100
≈ 63.4%
개별 구성요소에서는 드물었던 문제가 fan-out 시스템에서는 흔한 사용자 경험이 된다.
이것은 microservice와 agent graph에 그대로 적용된다.
- 여러 API를 병렬 호출한 뒤 전부 기다리는 화면
- shard나 partition을 넓게 조회하는 검색
- 여러 agent가 후보를 만들고 가장 늦은 결과까지 기다리는 workflow
- evaluator가 모든 branch의 긴 결과를 다시 읽는 구조
병렬화의 단순 모델은 합이 아니라 가장 느린 branch에 가깝다.
T_parallel ≈ max(branch latency) + merge overhead
따라서 “병렬로 만들었으니 빠르다”가 아니라 branch 수, slowest branch, deadline, cancellation, partial result를 함께 설계해야 한다.
원리 5: 최적화는 한 층의 문제가 아니라 관계의 문제다
성능 문제는 한 부품에서 끝나지 않는다. 한 곳의 개선이 다른 곳으로 병목을 옮길 수 있다.
| 선택 | 좋아질 수 있는 것 | 나빠질 수 있는 것 |
|---|---|---|
| batch 확대 | throughput, 연산 효율 | queue wait, TTFT |
| cache 확대 | 재계산, 반복 I/O | memory pressure, invalidation 복잡도 |
| branch 병렬화 | 중앙값 완료 시간, 탐색 폭 | p99, 비용, rate limit |
| retry 추가 | 일시적 실패 복구율 | 장애 시 부하 증폭, 중복 side effect |
| context 확대 | 모델이 보는 정보량 | prefill 시간, KV cache, 관련성 희석 |
| payload 압축 | network bytes | CPU 사용량, 압축·해제 latency |
Markdown Search MCP에서 찾은 DynoSim 자료는 LLM serving의 backend, tensor parallelism, prefill/decode 분리, worker 수, scheduler, routing, KV cache와 autoscaling이 서로 영향을 준다고 설명한다. 한 설정의 국소 개선이 다른 병목을 만들 수 있어, 여러 후보를 먼저 simulation으로 거른 뒤 실제 hardware에서 검증하는 접근을 제안한다.
이것이 관계를 보는 개발이 중요한 이유다. 좋은 개발자는 cache, network, scheduler, model과 graph를 따로 외우는 데서 끝나지 않는다. 한 선택이 다음 층의 queue, memory와 tail latency를 어떻게 바꾸는지 연결해서 본다.
원리 6: AI Agent의 context도 결국 메모리와 데이터 이동 문제다
AI agent에서 context는 단순한 prompt 문자열이 아니다. system instruction, tool definition, conversation history, 검색 결과, 로그와 subagent 결과가 누적된다.
Markdown Search MCP의 NVIDIA Dynamo 관련 정리에서는 agent workload가 긴 prefix를 반복해 사용하기 때문에 KV-cache locality, cache retention, routing과 worker scheduling이 latency와 비용에 영향을 준다고 설명한다. 같은 session의 다음 요청이 이전 prefix를 재사용할 수 있어도 다른 worker로 흩어지거나 cache가 사라지면 다시 계산해야 한다.
그래서 context engineering은 글을 잘 쓰는 prompt 기법만이 아니다.
- 어떤 정보가 장기적으로 재사용되는가?
- 무엇이 이번 단계에서만 필요한가?
- tool output 전체를 남길 것인가, artifact reference만 남길 것인가?
- subagent가 종료된 뒤 어떤 context를 버릴 수 있는가?
- 같은 session을 cache가 있는 worker에 배치할 수 있는가?
- context가 커질 때 품질 향상이 latency와 비용 증가를 정당화하는가?
agent에게 정보를 많이 주는 것과 필요한 정보를 가까이 두는 것은 다르다. 전자는 context를 무작정 키우고, 후자는 목적에 맞는 정보만 검색하고 재사용한다.
원리 7: 측정하지 않은 최적화는 아직 가설이다
성능 개선은 다음 순환으로 다뤄야 한다.
flowchart TD
A["Baseline<br/>latency·memory·quality"] --> B["병목 가설"]
B --> C["한 가지 변경"]
C --> D["같은 조건에서 재측정"]
D --> E["넓은 입력<br/>p95·p99·회귀 확인"]
E --> F{"목표와 품질을<br/>함께 만족?"}
F -->|"예"| G["변경 유지·기준선 갱신"]
F -->|"아니오"| H["되돌리기·가설 수정"]
H --> B
flowchart TD
A["Baseline<br/>latency·memory·quality"] --> B["병목 가설"]
B --> C["한 가지 변경"]
C --> D["같은 조건에서 재측정"]
D --> E["넓은 입력<br/>p95·p99·회귀 확인"]
E --> F{"목표와 품질을<br/>함께 만족?"}
F -->|"예"| G["변경 유지·기준선 갱신"]
F -->|"아니오"| H["되돌리기·가설 수정"]
H --> B
2026년 공개된 SWE-Pro preprint도 이 문제를 흥미롭게 보여 준다. 이 연구는 실제 repository의 성능 최적화를 평가할 때 실행 시간 하나만 보지 않고 peak memory와 시간 가중 memory 사용량을 여러 입력과 noisy measurement 조건에서 함께 측정한다. 논문의 개별 성능 수치는 후속 재현이 필요하지만, 평가 설계가 주는 메시지는 분명하다.
짧은 함수 하나의 microbenchmark가 좋아졌다고 전체 시스템이 개선됐다고 말할 수 없다. 실제 입력, memory, 분산, 기능 정확성과 회귀까지 확인해야 한다.
AI가 코드를 고쳐 준 경우에는 이 원칙이 더 중요하다. 코드가 그럴듯한 것과 빠르고 안전한 것은 별개의 판단이다.
AI가 코드를 써 주는 시대, 개발자는 시스템을 인수하는 사람이다
관리자의 관점은 AI를 감시한다는 뜻이 아니다. 생성된 코드를 실제 서비스에 넣어도 되는지 기준과 증거를 가지고 판단한다는 뜻이다.
AI coding assistant는 함수, API와 test를 빠르게 만들 수 있다. 그러나 실제 workload, SLA, 운영 예산, 장애가 났을 때의 책임까지 저절로 알지는 못한다. 요청에 이런 조건이 빠져 있으면 AI는 눈앞의 기능을 완성하면서도 N+1 query, 큰 payload, 제한 없는 concurrency와 retry, 과도한 context 같은 구조를 함께 만들 수 있다.
그래서 AI 시대의 개발자는 모든 코드를 손으로 쓰는 사람보다 시스템의 인수 기준을 정하는 사람에 가깝다. 관리자의 마음으로 본다는 것은 줄마다 간섭하는 micro-management가 아니다. 무엇을 맡기고, 어디까지 허용하며, 어떤 증거가 있어야 승인할지를 먼저 정하는 일이다.
| 검수 관점 | AI가 만든 결과에 물어볼 질문 | 확인할 증거 |
|---|---|---|
| 기능과 invariant | 정상 입력뿐 아니라 꼭 지켜야 할 규칙과 edge case도 통과하는가? | unit·integration test, eval 결과 |
| architecture와 data flow | DB·API·model·tool 경계를 몇 번 넘고 같은 데이터를 반복해서 옮기지 않는가? | architecture map, dependency diff, trace |
| latency와 scale | 개발 환경에서 한 번 빠른 것이 아니라 실제 부하에서도 p95·p99가 유지되는가? | load test, queue time, p50·p95·p99 |
| memory와 비용 | cache, working set, context와 payload가 커지면서 다른 병목을 만들지 않는가? | profile, peak memory, token·network bytes, 비용 추정 |
| failure behavior | timeout, retry, cancellation과 partial failure가 생기면 안전하게 끝나는가? | fault test, idempotency 확인, fallback 결과 |
| 운영 가능성 | 문제가 생겼을 때 원인을 찾고 이전 버전으로 돌아갈 수 있는가? | metric·log·trace, alert, rollback 절차 |
코드 생성 전에 인수 조건부터 준다
AI에게 “이 기능을 만들어 줘”라고만 하면 구현 방식의 중요한 빈칸을 AI가 추측하게 된다. 아래처럼 인수 조건을 함께 주면 생성 속도를 살리면서도 설계 판단을 놓치지 않을 수 있다.
기능 요구: 사용자가 얻어야 할 결과와 반드시 지킬 invariant
데이터 경계: 사용 가능한 DB·API·model·tool과 금지할 새 dependency
성능 예산: 예상 workload, latency p95·p99, memory와 비용 상한
실패 정책: timeout, retry, idempotency, cancellation, fallback
검증 방법: test, benchmark, trace와 비교할 baseline
배포 조건: 관측할 metric, alert와 rollback 방법
이 항목은 거대한 설계 문서를 쓰자는 이야기가 아니다. 작은 변경이라면 몇 줄이면 된다. 중요한 점은 AI가 코드를 만든 뒤 감으로 평가하지 않고, 만들기 전에 합격선을 정해 두는 것이다.
빠르게 생성할수록 feedback loop는 더 짧아야 한다
AI 덕분에 한 시간에 시도할 수 있는 변경 수가 늘었다. 좋은 설계와 나쁜 설계가 퍼지는 속도도 함께 빨라졌다. 그러므로 generate → test → measure → review → deploy를 하나의 짧은 loop로 만들어야 한다.
Latency Numbers의 관점은 이 loop에서 유용한 질문을 준다. “코드가 동작하는가?” 다음에 “데이터는 어디로 움직이는가?”, “무엇을 기다리는가?”, “branch가 늘면 tail은 어떻게 변하는가?”, “같은 workload에서 baseline보다 실제로 좋아졌는가?”를 묻게 한다.
AI가 구현을 맡을수록 개발자의 가치가 사라지는 것이 아니다. 타이핑의 비중은 줄어들 수 있지만, 목표와 제약을 세우고 시스템의 관계를 읽으며 결과를 인수하는 책임은 더 선명해진다.
그래서 개발자라면 어디까지 알아야 할까
모든 개발자가 GPU kernel이나 network protocol을 직접 최적화할 필요는 없다. 대신 자신의 코드가 넘는 경계와 그 경계에서 확인할 지표는 알아야 한다.
| 역할·상황 | 최소한 알아야 할 범위 | 다음 단계가 필요한 신호 |
|---|---|---|
| 모든 개발자 | ns·µs·ms의 자릿수, end-to-end latency, p50·p95·p99, queue와 service time | 사용자가 느리다고 하지만 원인을 한 구간으로 설명하지 못한다. |
| Frontend·mobile | network waterfall, request 수, payload, main thread, rendering과 cache | API는 빠른데 화면 완료가 느리거나 interaction이 끊긴다. |
| Backend·data | DB round trip, N+1, serialization, connection pool, retry, concurrency와 saturation | 부하가 조금만 늘어도 queue·timeout·p99가 급증한다. |
| AI application·Agent | TTFT, tokens/sec, turn·tool·retry 수, context token, cached token, task success와 cost | model을 바꿔도 전체 task latency와 비용이 개선되지 않는다. |
| Inference·platform | HBM·on-chip bandwidth, KV cache, batching, scheduler, GPU topology와 interconnect | GPU 사용률은 높은데 SLO를 만족하는 동시 session 수가 낮다. |
경계는 직급이 아니라 문제에 따라 이동한다. 평소에는 application trace만으로 충분할 수 있다. 그러나 profile에서 memory stall이 보이거나 GPU 간 통신이 critical path라면 한 층 아래로 내려가야 한다. 반대로 hardware 수치를 많이 알아도 사용자의 task completion과 품질을 측정하지 않으면 한 층 위의 문제를 놓친다.
2026년 개발자의 공통 대시보드
처음부터 수십 개 metric을 만들 필요는 없다. 다음 일곱 가지를 같은 trace와 dashboard에서 연결할 수 있으면 출발점으로 충분하다.
- 사용자의
end-to-end p50·p95·p99와 task success queue wait와 실제 execution time- slowest DB·API·tool span과 payload bytes
- model별 TTFT, tokens/sec와 input·output·cached token
- turn, tool call, retry, handoff와 subagent 수
- concurrency, saturation, timeout과 cancellation
- 한 task의 비용과 사람 개입 횟수
이 목록의 목적은 monitoring을 화려하게 만드는 것이 아니다. “느리다”는 말을 model 탓, network 탓, agent 탓으로 추측하지 않고, 어느 span과 어떤 반복이 critical path를 만들었는지 증거로 설명하기 위해서다.
사람들이 흔히 하는 실수
작은 연산부터 최적화한다
문법, 반복문과 함수 호출을 줄이지만 실제 시간은 DB, network, disk, queue나 model API에서 소비된다. 먼저 trace와 profile로 기다리는 곳을 찾아야 한다.
평균만 본다
평균이 빠르면 완료했다고 생각한다. 사용자가 경험하는 p95·p99와 timeout 비율이 숨겨진다.
병렬화하면 무조건 빠르다고 생각한다
branch가 늘면 contention, rate limit, merge와 tail을 만날 가능성도 커진다. 모든 결과가 정말 필요한지 먼저 확인해야 한다.
cache를 공짜라고 생각한다
cache는 memory를 사용하고 invalidation과 routing 제약을 만든다. hit rate뿐 아니라 memory pressure, stale data와 miss penalty를 함께 봐야 한다.
retry를 신뢰성으로 착각한다
제한 없는 retry는 장애 때 부하를 증폭한다. timeout, backoff, jitter, 최대 횟수, idempotency가 한 묶음이어야 한다.
benchmark 숫자 하나를 진실로 받아들인다
다른 hardware, driver, topology, workload와 warm-up 조건의 숫자를 그대로 가져온다. 숫자에는 환경, 단위, percentile과 측정 조건이 붙어야 한다.
AI Agent에 node와 context를 계속 추가한다
복잡성이 품질이라고 생각한다. 그러나 model call, KV cache, tool round trip, fan-out과 실패 지점만 늘어날 수 있다. 실패 trace가 요구하는 구조만 추가해야 한다.
개발할 때 내가 먼저 물어볼 질문
설계 전
- 데이터는 지금 어디에 있고 어디로 이동해야 하는가?
- network·DB·disk·model·tool 경계를 몇 번 넘는가?
- 전체 critical path에 꼭 필요한 단계는 무엇인가?
- 구현 전에 자릿수 수준의 예상 시간을 계산할 수 있는가?
구현 중
- 반복문 안에 DB·API·model 호출이 숨어 있지 않은가?
- 같은 데이터를 반복해서 복사·직렬화·전송하지 않는가?
- working set과 context가 필요 이상으로 크지 않은가?
- 병렬 branch에 concurrency limit, deadline과 cancellation이 있는가?
- retry되는 작업이 idempotent한가?
운영 전
- queue time과 execution time을 분리해서 보는가?
- p50뿐 아니라 p95·p99와 timeout을 수집하는가?
- payload bytes, context token, cache hit와 retry를 기록하는가?
- throughput이 좋아졌을 때 TTFT와 p99가 악화되지 않았는가?
- 한 변경 전후를 같은 workload와 환경에서 비교했는가?
AI Agent라면 추가로
- node를 추가한 이유가 실제 실패 trace로 설명되는가?
- evaluator의 합격 기준과 revision budget이 있는가?
- tool output을 prompt에 복사하지 않고 artifact로 보존할 수 있는가?
- 모든 branch를 기다릴 필요가 있는가?
- 품질, token, latency, 비용과 사람 개입을 같은 eval에서 비교하는가?
결국 ‘찐 개발자’가 보는 것
초보자는 코드가 실행되는지만 본다. 조금 익숙해지면 알고리즘과 framework를 본다. 더 깊이 들어간 개발자는 그 아래의 관계를 본다.
코드
↓
데이터 구조와 접근 패턴
↓
메모리 계층과 데이터 이동
↓
queue·scheduler·network
↓
critical path와 tail latency
↓
사용자가 실제로 경험하는 속도와 안정성
물론 모든 개발자가 GPU interconnect의 세부 숫자까지 알아야 하는 것은 아니다. 중요한 것은 자신의 시스템에서 비용의 층위가 바뀌는 경계를 아는 것이다.
- 프론트엔드 개발자는 main thread, network waterfall, bundle과 cache의 관계를 본다.
- 백엔드 개발자는 DB round trip, N+1, serialization, queue와 p99의 관계를 본다.
- 데이터 개발자는 sequential scan, random I/O, partition과 data locality의 관계를 본다.
- AI 개발자는 prefill, KV cache, batching, tool call, context와 evaluator의 관계를 본다.
Latency Numbers가 주는 가장 큰 교훈은 “더 빠른 코드를 작성하라”가 아니다.
무엇을 계산하는지만 보지 말고, 무엇을 옮기고 무엇을 기다리는지 보라. 그리고 추측을 측정으로 바꿔라.
참고 자료
| 구분 | 자료 | 이 글에서 사용한 관점 |
|---|---|---|
| 1차 발표 | Jeff Dean 2007 발표 | 고전 latency 표와 back-of-the-envelope 계산 |
| 1차 발표 | Jeff Dean 2012 latency 발표 | fan-out과 tail amplification |
| 원 논문 | The Tail at Scale | tail-tolerant system |
| 공식 운영 가이드 | Google SRE: Monitoring Distributed Systems | latency·traffic·errors·saturation의 연결 |
| 공식 운영 가이드 | Google SRE: Service Level Objectives | 평균 대신 distribution과 workload별 SLO |
| Google Research | Load is not what you should balance: Prequal | active request와 예상 latency 기반 routing |
| 1차 인터뷰 | Jeff Dean: The 1% Rule for Building in AI | AI판 balance numbers, data movement, microbenchmark loop |
| 사용자 제공 영상 | YC 스타트업 스쿨 talks, 정리했습니다 | 후속 원자료를 찾기 위한 챕터 지도 |
| 공식 설계 글 | Anthropic: Building Effective Agents | agent 복잡성과 latency·cost·quality trade-off |
| 공개 표준·예시 | OpenTelemetry: GenAI Observability | model·tool span과 duration·token 관측 |
| 공식 SDK 문서 | OpenAI Agents SDK Tracing | generation·tool·handoff·guardrail trace |
| 공식 기술 글 | NVIDIA NVbandwidth | memory·GPU interconnect 경로별 실측 |
| 공식 기술 글 | NVIDIA Dynamo agentic inference | 반복 context, KV cache locality, routing |
| 공식 기술 글 | NVIDIA: Agentic Systems Extreme Co-Design | coding-agent context·cache·token dynamics 사례 |
| Benchmark 해설 | NVIDIA: AA-AgentPerf | TTFT·output speed SLO를 지키는 concurrent agents |
| 공식 기술 글 | DynoSim | serving 설정의 상호작용과 simulate-then-verify |
| 연구 preprint | SWE-Pro | runtime·memory·noise-aware performance evaluation |
| 내부 연구 노트 | Latency Numbers 설계 가이드 | 수치 버전, Graph Engineering 적용, 검증 한계 |
| 내부 연구 노트 | 단일 Agent Loop에서 Graph로 | graph·fan-out·eval을 추가하는 기준 |
출처 주의: NVIDIA 자료는 공식 기술 설명이면서 제품 공급자의 관점을 담고 있다. 특정 제품의 성능 수치는 이 글의 일반 원리 근거로 사용하지 않았고, Agent session 사례와 benchmark는 측정 관점만 참고했다. OpenTelemetry의 GenAI semantic convention은 2026년에도 active development 상태다. SWE-Pro는 2026-06 공개 preprint이며, 개별 수치보다 평가 설계의 시사점을 사용했다.
'관심있는 주제 > 탐구 노트' 카테고리의 다른 글
| LangGraph를 쓰며 생긴 의문: Graph Engineering은 워크플로우 엔진과 무엇이 다른가 (0) | 2026.08.12 |
|---|---|
| pgGraph 완전 가이드: PostgreSQL 데이터를 CSR 그래프로 만들고 검색·탐색하는 법 (0) | 2026.08.06 |
| 일정을 못 잡는 개발자를 위한 WBS 실전 가이드 (1) | 2026.07.25 |
| 지식 자산화와 OKF: 개인 노트에서 기업 AI 지식 인프라까지 (0) | 2026.07.19 |
| Ilya Sutskever가 추천했다고 알려진 30 Papers로 보는 AI의 큰 그림 (0) | 2026.07.12 |
