리텐션이 안 나오는 제품을 뜯어보면, 의외로 “기능이 부족해서”가 아니라 “느리고 끊겨서”인 경우가 많습니다. 첫 사용에서 로딩이 길거나 화면이 멈추면 유저는 학습할 기회도 없이 나가요. 문제는 이게 감정의 영역이 아니라 퍼널 수치로 바로 찍힌다는 것. 온보딩 단계의 지연·프리징은 Activation을 깎고, 그 여파가 D1/D7 리텐션과 유료 전환까지 연쇄로 번집니다.
여기서 재미있는 포인트: 느려지는 이유가 서버(GPU)일 수도, 클라이언트(브라우저)일 수도 있다는 겁니다. 그런데 둘 다 공통 원인이 있어요. ‘일은 하고 있는데, 사용자에게는 멈춘 것처럼 보이는’ 오버헤드가 병목을 만든다는 점입니다. dev.to의 CUDA Graphs 딥다이브 글은 LLM 추론의 디코드(decode) 단계에서 GPU 연산 자체보다 CPU 커널 런치 오버헤드가 더 큰 병목이 될 수 있다고 짚습니다. 마이크로초 단위의 작은 커널을 수백 번 쏘는 동안 CPU가 런치·동기화·스케줄링에 시간을 태우고, 그 사이 GPU는 놀아버리는 구조죠.
CUDA Graphs는 이 “수백 번의 호출”을 한 번 캡처해 두고, 이후에는 단 한 번의 replay 호출로 재생합니다. 즉, CPU가 매 스텝마다 치르던 런치 비용을 상각해 latency를 줄이는 방식입니다(출처: dev_to, CUDA Graphs in LLM Inference: Deep Dive). 물론 대가도 있습니다. 그래프는 메모리 주소와 커널 호출 시퀀스를 ‘고정’해두기 때문에, 디코드처럼 입력 shape가 예측 가능한 구간에 특히 잘 맞고, 배치 사이즈별 그래프를 여러 개 잡으면 GPU 메모리를 더 먹습니다. 하지만 서빙에서 중요한 건 “1토큰 더 빠르게”가 아니라 “첫 응답이 끊기지 않게”라는 점에서, 이 선택은 UX에 직결됩니다.
프론트엔드도 똑같습니다. dev.to의 Web Workers 글이 말하듯, 자바스크립트 메인 스레드는 사실상 UI 스레드입니다. async/await는 ‘기다림’을 비동기로 만들 뿐, CSV 생성 같은 무거운 연산은 여전히 메인 스레드를 점유해서 스피너를 얼려버려요(출처: dev_to, The Secret Life of JavaScript: The Clone). Web Worker로 무거운 처리를 넘기면 UI는 계속 반응하고, 유저는 “앱이 살아있다”는 신호를 받습니다. Transferable Objects까지 쓰면 큰 데이터 복사 비용도 줄여 더 매끈해지죠.
이 두 이야기를 묶으면, 와 이거다 싶습니다. “서버에서 첫 토큰까지의 시간(TTFT)을 줄이고(CUDA Graphs), 클라이언트에서 화면 멈춤을 없애면(Web Workers), 체감 성능이 올라가고 퍼널 이탈이 내려간다.” 이건 기술 미덕이 아니라 그로스 레버입니다. 실험은 이렇게 잡을 수 있어요: (1) 온보딩 핵심 액션(첫 질문/첫 생성/첫 내보내기) 구간에 TTI, TTFT, long task(>50ms) 발생률을 트래킹 (2) CUDA Graphs 적용 전후로 p50/p95 응답 지연과 스트리밍 끊김률 비교 (3) Web Worker 적용 전후로 프리징 세션 비율과 온보딩 완료율 비교. 그리고 결과는 D1/D7, Activation rate, 결제 전환(CR)로 연결해 코호트로 봐야 합니다.
전망은 명확합니다. AI 기능이 기본값이 될수록 ‘모델 성능’은 점점 상향평준화되고, 승부는 “얼마나 끊김 없이 경험을 전달하느냐”로 갈립니다. 특히 LLM 제품은 응답이 길어질수록(=디코드가 길어질수록) 서버 오버헤드의 복리 효과가 커지고, 클라이언트는 렌더링·다운로드·내보내기 같은 부수 작업에서 쉽게 프리징이 나요. 결론: 속도 최적화는 비용 절감(낭비되는 GPU 사이클 제거) + UX 개선(프리징 제거) + 리텐션/수익화 개선(퍼널 누수 감소)까지 한 번에 거는 성장 베팅입니다. 빨리 테스트해봐야 돼요. 체감이 바뀌면 숫자가 따라옵니다.