스트리밍 응답의 진짜 비용은 UX 가 아니라 트랜잭션이다
글자가 흐르는 동안 커넥션도 함께 붙잡혀 있다.
목차
스트리밍을 붙이면 체감 속도가 좋아진다. 그건 맞다. 문제는 그 아래에서 일어난다.
커넥션이 응답 시간만큼 붙잡힌다
@Transactional
public void answer(Long chatId, String question) {
var history = repository.findHistory(chatId); // DB
llm.stream(question, history, chunk -> emit(chunk)); // 20초
repository.save(new Message(...)); // DB
}이 코드는 20초 동안 DB 커넥션을 쥐고 있다. 동시 사용자가 풀 크기를 넘는 순간 LLM 과 무관한 요청까지 전부 대기한다. 장애는 채팅이 아니라 로그인에서 먼저 보인다.
경계를 셋으로 나눈다
- 읽기 — 필요한 것을 읽고 트랜잭션을 닫는다
- 호출 — DB 없이 스트리밍한다
- 쓰기 — 다 받은 뒤 짧은 트랜잭션으로 저장한다
중간에 끊긴 응답을 어떻게 다룰지 정한다
사용자가 탭을 닫으면 2번 도중에 끝난다. 그때 저장하지 않으면 사용자는 "답을 봤는데 기록에 없다" 를 겪는다. 부분 응답을 저장하되 완결 여부를 표시하는 편이 낫다.
스트리밍은 화면의 문제가 아니라 트랜잭션 경계의 문제다.