개발자 면접에 30년 가까이 살아남은 질문이 있다. 브라우저 주소창에 주소를 치고 엔터를 누르면 그 다음에 무슨 일이 일어나느냐. 이 질문이 오래 간 이유는 답 하나가 시스템 전체를 관통하기 때문이다. 네트워크만 아는 사람은 거기까지 말하고 서버까지 아는 사람은 더 간다. 아는 만큼만 대답하게 되니까, 질문 하나로 그 사람이 어디까지 보는지가 드러난다.
AI에도 그런 질문이 하나 필요하다. 요즘 이런 말을 계속 듣는다. 이제 학습보다 추론이다, 추론이 메모리를 잡아먹는다, 그래서 메모리 슈퍼사이클이다. 그런데 막상 물어보면 추론이 뭘 어떻게 먹는다는 건지 짚어주는 데가 없다.
그래서 채팅창에 질문 하나를 치고 엔터를 누르는 순간부터 답이 돌아올 때까지를 끝까지 따라간다. 3초짜리 여정이다. 이걸 다 보고 나면 추론이 왜 중요한지가 아니라 추론의 어느 지점에서 뭐가 모자라는지를 알게 된다. 그게 결국 어디에 돈이 몰리는지와 같은 얘기다.
미리 하나만 말하면, 그 3초 동안 저쪽 GPU는 계산을 하느라 바쁜 게 아니다. 뭘 읽어 오느라 바쁘다. 여정 내내 계기판 넷을 들고 간다. 지난 시간, 쓴 전기, 읽은 가중치, GPU 동기화.
1. 집 밖으로, 바다 건너
엔터를 누르면 주소를 찾고 서로 확인하는 절차를 거친다. 여기까지는 인터넷을 쓸 때 늘 하는 일이다. 재밌는 건 여기부터인데, 질문이 곧장 미국까지 날아가는 게 아니다. 일단 제일 가까운 엣지에서 한 번 끊긴다. 서울이나 도쿄쯤. 그런데 거기서 답을 만들어 주지는 않는다. 엣지는 문지기지 주방이 아니다.
추론이 도는 GPU는 훨씬 멀리 있다. 그래서 오고 가는 것만으로 시간이 먹힌다. 실측으로 서울에서 미국 서부 오리건까지 왕복 137밀리초다. 중요한 건 이걸 줄일 방법이 사실상 없다는 것이다. 광케이블 안에서도 신호는 빛보다 빠를 수 없고, 태평양은 만 킬로미터다.
2. 데이터센터에 도착했는데, 어느 노드로 가지
데이터센터 도착은 끝이 아니라 시작이다. 이 안에 서버가 수만 대 있고, 내 요청은 그중 딱 한 대로 가야 한다. 그 한 대를 고르는 데만 관문이 셋이다. 로드밸런서가 어느 입구로 들일지 정하고, 라우터가 어느 모델 어느 리전으로 보낼지 정하고, 추론 스케줄러가 지금 여유가 있는 GPU 노드 하나를 배정한다.
배정이 끝나면 이상한 일이 시작된다. 그 GPU는 내 요청 하나만 붙들고 있지 않는다. 수십 개를 동시에 물고 있다. 그리고 한 스텝마다, 물고 있는 모든 요청에 토큰을 하나씩 붙여 준다. 내 답변 한 조각, 옆 사람 답변 한 조각, 그 옆 사람 한 조각. 한 번에.
아래 그림이 그 장면이다. 가로축이 시간이고 오른쪽이 나중이다. 가로 한 줄이 자리 하나, 칸 하나가 그 스텝에 그 자리에서 뽑힌 토큰 하나다. 한 줄 안에서 색이 갈리면 다른 요청이라는 뜻이다.
예전에는 물고 있는 요청이 전부 끝나야 다음 묶음을 받았다. 그러면 먼저 끝난 자리가 그냥 비어 있었다. 지금은 다르다. 한 스텝이 끝날 때마다 다 된 요청은 빼고, 기다리던 새 요청을 그 자리에 바로 넣는다. 격자에서 진한 세로선이 찍힌 자리가 그 교체 순간이다. 이걸 연속 배칭이라고 한다.
그래서 내 응답 속도가 옆자리 사정에 묶인다. 같은 배치에 몇 개가 들어 있느냐가 곧 HBM 대역폭을 몇으로 나누느냐이기 때문이다. 이 얘기는 7절에서 숫자로 다시 나온다.
그리고 하나 더 있다. 같은 대화는 되도록 같은 노드로 보낸다. 앞서 나눈 얘기를 그 GPU 메모리가 아직 들고 있으면 다시 계산하지 않아도 되기 때문이다. 그러니까 내 요청이 어느 노드로 가느냐에 따라 원가가 달라진다. 이 얘기는 뒤에서 가격표를 볼 때 다시 나온다.
3. GPU 한 장 안에는
우리가 GPU라고 부르는 건 통째로 한 장을 말하는데, 그 안에는 반도체가 두 종류 들어 있다. 계산하는 다이가 있고, 그 옆에 메모리가 층층이 쌓여서 붙어 있다. 이 메모리가 HBM이다.
최신 세대 기준으로 한 장에 HBM 288기가바이트가 여덟 스택으로 붙어 있고, 초당 20테라바이트 넘게 읽어 낸다. 직전 세대가 8테라바이트였으니 거의 세 배다. 그런데 이 글의 핵심은 그렇게 빨라도 모자란다는 것이다.
GPU끼리도 이어야 한다. NVLink로 잇고 장당 초당 1.8테라바이트다. 왜 이렇게까지 굵게 잇느냐면, 뒤에 나올 가중치가 한 장에 안 들어가서 여러 장에 쪼개 담아야 하고, 쪼개 담으면 레이어마다 서로 결과를 맞춰야 하기 때문이다.
4. 랙 밖으로 나가면, 구리가 광으로 바뀐다
요즘은 랙 하나를 통째로 한 도메인으로 묶는다. GPU 일흔두 장이 한 덩어리다. 도메인 안은 구리로 잇는다. 거리가 가까우니까. 그런데 도메인 밖으로 나가는 순간 달라진다. 멀어지면 구리로는 못 버틴다. 그래서 전기 신호를 빛으로 바꿔 보내고, 바꿔 주는 부품이 광 트랜시버다.
트랜시버는 GPU 한 장에 여섯 개꼴로 잡는다. 백만 장짜리 클러스터면 트랜시버가 먹는 전력만 180메가와트다. 하나만 기억하면 된다. 구리에서 광으로 바뀌는 경계가 어디냐. 이게 마지막에 다시 나온다.
5. 프리필 — 연산이 바쁘다
계산은 한 종류가 아니라 두 단계다. 먼저 입력을 통째로 읽는다. 이때 문장이 조각으로 잘리는데 그 조각 하나를 토큰이라 한다. 글자와 비슷하지만 같지는 않다. 흔한 단어는 통째로 한 토큰, 드문 단어는 여러 토큰으로 쪼개진다.
입력이 200토큰이면 200개를 한꺼번에 본다. 순서대로 볼 필요가 없다. 이미 다 와 있으니까. 한꺼번에 볼 수 있다는 건 연산부를 꽉 채울 수 있다는 뜻이고, 실제로 이 단계 이용률이 90퍼센트를 넘는다. 이 단계가 프리필이고, 첫 토큰이 나오기까지 걸리는 시간을 이게 정한다.
6. 디코드 — 토큰 하나의 한 바퀴
모델은 인공지능의 뇌라고들 하지만 열어보면 숫자가 적힌 거대한 표다. 칸이 수천억 개고, 이 숫자들을 가중치라고 한다. 가중치는 GPU 다이 위에 안 올라간다. 너무 크다. 그래서 HBM에 두고 계산할 때마다 읽어 온다. 그리고 한 덩어리가 아니라 레이어로 되어 있다. 공개된 모델로 보면 700억짜리가 80레이어, 4천억짜리가 126레이어다.
토큰 하나를 만드는 데 실제로 벌어지는 일은 이렇다.
- 각 GPU가 자기가 맡은 가중치 조각을 HBM에서 읽어 온다
- 곱한다
- NVLink로 옆 GPU들과 결과를 맞춘다
- 다음 레이어로 넘어간다
이걸 레이어마다 반복한다. 80번에서 126번. 그렇게 다 돌고 나면 나오는 게 토큰 하나다.
여기서 이상한 게 나온다. 숫자로 보면 확실하다.
제일 비싼 가속기를 사놓고 절반 넘게 놀리고 있는 것이다. 병목은 연산이 아니라 메모리 대역폭이다. 이 단계를 디코드라고 한다.
7. 그걸 500번, 그리고 쌓이는 KV 캐시
방금 그 한 바퀴가 토큰 하나였다. 답변이 500토큰이면 500번 돈다. 처음부터 똑같이.
그리고 여기 하나가 더 붙는다. 다음 토큰을 만들려면 앞의 맥락을 다 알고 있어야 하므로, 앞선 토큰들의 중간 계산 결과를 계속 들고 있어야 한다. 이걸 KV 캐시라고 한다. 700억 모델에서 토큰당 0.31메가바이트다. 별거 아닌 것 같지만 컨텍스트를 12만 8천 토큰까지 채우면 40기가바이트가 된다.
자리가 없으면 아래로 내려간다. 메모리가 한 층이 아니기 때문이다.
가중치를 처음 올릴 때도 마찬가지다. 스토리지에서 수백 기가바이트를 읽어 올려야 한다. 그래서 노드 하나가 모델 하나를 계속 붙들고 있다. 갈아 끼우는 게 너무 비싸서다. 2절에서 같은 대화를 같은 노드로 보낸다고 했던 것도 결국 같은 얘기다.
정리하면 메모리가 두 군데서 모자란다. 대역폭이 모자라고, 용량이 모자란다. 메모리가 많이 필요하다는 말은 정확히 이 두 가지다.
8. MoE의 반전
미뤄둔 얘기를 하자. 가중치를 매번 전부 읽느냐. 안 읽는다. 요즘 모델은 가중치를 전문가 여럿으로 나눠 놓고 토큰마다 필요한 전문가만 켠다. 이런 구조를 MoE, 전문가 혼합이라고 한다. 읽는 양은 확실히 준다. 여기까진 좋은 소식이다.
그런데 반전이 있다. HBM에는 여전히 전문가가 전부 올라가 있어야 한다. 어느 전문가가 걸릴지 미리 모르기 때문이다. 토큰을 받아봐야 안다. 읽는 양만 줄었지 용량 요구는 하나도 안 줄었다.
그리고 하나 더 있다. 전문가를 여러 GPU에 흩어 놓는 전문가 병렬을 쓰면 토큰을 담당 GPU로 보내야 한다. 앞의 결과 맞추기는 올리듀스라 모두가 같은 값을 나눠 갖는 얌전한 통신인데, 이건 올투올이다. 토큰마다 목적지가 다르다. 훨씬 고약한 패턴이다.
종합하면 연산은 줄었고, 용량은 그대로고, 통신은 늘었다. KV 캐시를 줄이는 쪽으로도 연구가 간다. 어텐션 구조를 바꿔 캐시를 압축하면 토큰당 0.31메가바이트가 0.07까지 내려간다. 그런데 이런 게 계속 나온다는 것 자체가 여기가 병목이라는 증거다. 안 급하면 아무도 안 고친다.
9. 프리필과 디코드를 갈라놓기
5절과 6절을 다시 보면 두 단계의 성격이 정반대였다. 프리필은 이용률 90퍼센트, 디코드는 20에서 40퍼센트. 성격이 반대인 일을 같은 노드에 시키면 어느 쪽도 제대로 돌지 않는다. 그래서 아예 분리하기도 한다. 프리필 전용 노드, 디코드 전용 노드로.
그러면 새 문제가 생긴다. 프리필이 만들어 둔 KV 캐시를 디코드 노드로 넘겨줘야 한다. 앞에서 봤듯 그게 수십 기가바이트다. 그걸 네트워크로 보내야 한다. 예전엔 없던 트래픽이 추론 안에서 새로 생긴 것이다.
10. 돌아오는 길, 그리고 영수증
답이 화면에 한 글자씩 찍히는 건 스트리밍 연출이 아니다. 진짜로 토큰이 하나씩 만들어지고 있는 것이다. 여정이 끝났으니 계기판을 보자.
| 정거장 | 지난 시간 | 쓴 전기 | 읽은 가중치 | GPU 동기화 |
|---|---|---|---|---|
| 0 훅 | 0.00 초 | 0 Wh | 0 GB | 0 회 |
| 1 바다 건너 | 0.07 초 | 0 Wh | 0 GB | 0 회 |
| 2 라우팅·큐 | 0.11 초 | 0 Wh | 0 GB | 0 회 |
| 3~4 GPU·랙 (관찰) | 0.11 초 | 0 Wh | 0 GB | 0 회 |
| 5 프리필 | 0.12 초 | 0.005 Wh | 40 GB | 160 회 |
| 6 첫 토큰 | 0.12 초 | 0.005 Wh | 41 GB | 320 회 |
| 7 500토큰 | 1.12 초 | 0.026 Wh | 665 GB | 80,160 회 |
| 10 영수증 | 1.19 초 | 0.026 Wh | 665 GB | 80,160 회 |
전기 칸은 짚고 넘어가야 한다. 이 숫자는 어디서 가져온 게 아니라 직접 계산한 것이다. 돌아다니는 추정치가 서로 수십 배씩 갈리기 때문에, 인용하는 대신 바닥부터 세웠다.
- 한 번에 읽는 가중치 40 GB ÷ 대역폭 20 TB/s = 한 pass 2 ms
- 그 2 ms 한 번이 배치 32개 요청에 각각 토큰 하나씩 → 토큰당 점유 0.0625 ms
- × GPU 1.5 kW × 500토큰 = 47 J
- × 서버 오버헤드 1.3 × 냉각 1.2 = 0.026 Wh
여기서 하나가 보인다. 시간이 읽는 양 ÷ 대역폭이다. 그러니까 전기가 대역폭에 직접 매여 있다. 대역폭이 모자라면 시간이 늘고, 시간이 늘면 전기를 더 먹는다.
다만 이건 바닥값이다. 실제로 재보면 이렇게 벌어진다.
그래서 이 영수증은 “최소한 이만큼”으로 읽어야 한다.
11. 가격표라는 증거
지금까지의 설명은 전부 추정이다. 확인할 방법이 하나 있다. 이 회사들이 API 가격표를 공개해 둔다. 입력 토큰과 출력 토큰의 값을 따로 매겨서.
| 입력 | 출력 | 캐시 읽기 | |
|---|---|---|---|
| A사 상위 | $5 | $25 | $0.50 |
| A사 중위 | $2 | $10 | $0.20 |
| B사 상위 | $5 | $30 | $0.50 |
두 가지가 눈에 띈다. 하나, 출력이 입력보다 다섯에서 여섯 배 비싸다. 입력은 프리필이라 한꺼번에 처리되고 출력은 디코드라 하나씩 만들어야 하기 때문이다. 5절과 6절의 차이 그대로다. 둘, 캐시를 읽으면 입력의 십분의 일이다. 2절에서 같은 대화를 같은 노드로 보낸다고 했던 것이 값으로 나타난 것이다.
그리고 이게 한 회사 사정이 아니다. 서로 다른 회사가 각자 매긴 값인데 다섯에서 여섯 배, 십분의 일이라는 비율이 겹친다. 장사 사정만으로 이렇게 겹치기는 어렵다. 물론 가격이 구조 하나로만 정해지지는 않는다. 그래도 앞에서 본 구조가 가격표에 비쳐 있다는 것 정도는 말할 수 있다.
12. 이 영수증에 곱하기
아까 그 영수증에 곱해보자. 지금 이 순간 같은 서비스를 쓰는 사용자 수, 하루 요청 수, 요청당 출력 토큰 수. 여기서 학습과 추론이 갈린다.
학습은 한 번 하면 끝난다. 끝나면 그 클러스터는 다음 모델까지 쉰다. 그런데 앞에서 본 건 다르다. 요청이 올 때마다 처음부터 다시 한다. 어제 했다고 오늘 건너뛸 수가 없다.
추론이 커진다는 말이 잘 안 와닿는 건 뭐가 커지는 건지를 안 알려주기 때문이다. 앞에서 본 게 그 답이다. 요청 하나에 이만큼 드는데, 그 요청이 매일 늘어난다.
그래서 모자란 게 가속기만이 아니다. 이 여정에서 막히는 데가 세 군데였다.
- 메모리 — 두 갈래다. 대역폭이 모자라서 제일 비싼 가속기를 절반 넘게 놀리고 있고, 용량이 모자라서 배치 크기가 깎인다. 그래서 수요가 HBM에서 끝나지 않는다. 밀려난 KV 캐시가 내려앉을 호스트 DRAM도, 그 아래 스토리지도 같이 따라 는다.
- 광통신 — 4절에서 기억해 달라고 한 그 경계다. 구리에서 빛으로 바뀌는 자리. GPU 한 장에 트랜시버 여섯 개꼴이니 가속기가 늘면 그 부품이 같은 배수로 는다.
- 인터커넥트 — 스케일업 도메인 안이 밖보다 서른여섯 배 굵다. 그러니까 도메인을 얼마나 크게 묶느냐가 성능을 정한다. 그런데 MoE는 올투올을 늘리고, 프리필과 디코드를 나누면 KV 전송이 또 생긴다. 이 축은 줄어들 이유가 없다.
가속기 얘기만 하기엔, 이 3초 안에 다른 게 너무 많았다.
가정과 한계
- 계기판 숫자는 대표값 가정에서 파생한 것이다. 활성 파라미터 400억·8비트, HBM 20 TB/s, 배치 32, GPU 1.5 kW, 입력 200·출력 500 토큰. 실제 서비스 모델의 파라미터·정밀도·배치는 공개되지 않으므로, 이 값들은 공개 모델과 공개 스펙에서 세운 추정이다.
- 레이어 80과 hidden 8192는 공개된 700억급 모델 기준이다. 실제 서비스 모델과 다를 수 있고, 동기화 횟수(레이어 × 2)는 텐서 병렬을 전제한 값이다.
- 프리필 시간은 유효 연산성능 2 PFLOP/s 를 가정해 계산했다. 세대·정밀도에 따라 크게 달라진다.
- 전력은 인용이 아니라 위 가정에서 세운 바닥값이다. 배치 미충족·유휴 전력·긴 추론·도구 사용은 빠져 있어 실제 서비스는 이보다 크다.
- 트랜시버 대 GPU 비율(여섯 개꼴)은 아키텍처마다 다르다. 단일 값이 아니라 대략의 자릿수로 읽어야 한다.