블로그 목록
Backend10분 읽기
TTS 서버 파이프라인 해부 — Google TTS → R2 캐시 → 브라우저 재생
같은 문장을 100번 읽어줘도 Google TTS 요금이 1회분만 나오게 하려면 어떻게 설계해야 할까? 이 글은 텍스트를 음성으로 바꾸는 서버 API의 내부를 코드와 함께 따라간다. 입력값을 SHA-256 해시로 묶어 중복을 막고, R2 대신 DB로 캐시를 조회해 응답을 50배 빠르게 만들며, await를 떼어내 업로드를 백그라운드로 넘기는 트릭까지 읽고 나면, 작은 오디오 요청 하나가 비용과 속도를 동시에 챙기는 구조가 손에 잡힌다.
TTSR2캐시Base64
목차(18개 항목)
- 전체 흐름 — 한눈에 보기
1단계: Hash 생성 — 왜 필요한가?
- 2단계: Google TTS 호출
3단계: R2에 있는지 확인 — DB 캐시 전략
4단계: Fire-and-Forget — await 없는 백그라운드 실행
- 5단계: 응답 반환 — Buffer에서 브라우저까지
- 남용 방지 — 2단계 Rate Limit
- 로컬 저장 vs 직접 업로드 — 재시도 전략
- 정리 — 전체 파이프라인
- 관련 글
- 참고 자료
Google TTS API를 호출하고, 결과를 R2에 캐싱하고, 브라우저에서 재생하는 서버 사이드 오디오 파이프라인을 코드 레벨에서 해부합니다. hash 기반 중복 방지, DB vs R2 캐시 조회 전략, fire-and-forget 패턴까지.
전체 흐름 — 한눈에 보기
1단계: Hash 생성 — 왜 필요한가?
hash가 없으면?
hash가 있으면?
중복 방지 효과
2단계: Google TTS 호출
3단계: R2에 있는지 확인 — DB 캐시 전략
방법 비교
실제 코드
왜 DB가 더 나은가?
4단계: Fire-and-Forget — await 없는 백그라운드 실행
이번 요청 vs 다음 요청
5단계: 응답 반환 — Buffer에서 브라우저까지
남용 방지 — 2단계 Rate Limit
TTS는 유료 API이므로 남용을 막아야 합니다.
로컬 저장 vs 직접 업로드 — 재시도 전략
현재 route.ts는 방법 A를 사용합니다. 실시간 API 응답이라 로컬 파일을 쓰기 어렵고, R2 업로드 실패율이 매우 낮기 때문입니다. 배치 처리(스크립트)에서는 방법 B가 더 안전합니다.
정리 — 전체 파이프라인
관련 글
- #19 Base64 & 바이너리 기초 — Google TTS가 왜
audioContent를 base64로 주는지,Buffer.from(base64)가 무엇을 하는지의 기반 지식 - #21 소리는 어떻게 숫자가 되는가 — PCM/MP3 — 이 글의 출력물인 MP3가 PCM 원본에서 어떻게 만들어지는지
- #22 PCM vs WAV — 컨테이너와 코덱 —
audioEncoding: MP3vsLINEAR16(WAV)선택의 의미를 컨테이너/코덱 관점에서 - #11 Cloud Recording 녹화 파일 저장 — S3 — 같은 "바이너리 생성 → 오브젝트 스토리지 업로드" 패턴을 녹화 도메인에서
- #34 TTFB 분해 — DNS/TCP/TLS — fire-and-forget로 응답을 앞당기는 것이 체감 지표(TTFB)에 어떻게 작용하는지
참고 자료
- Cloud Text-to-Speech REST: text.synthesize — 본문에서 호출한 엔드포인트의 요청 스키마(
SynthesizeSpeechRequest)와 응답 - Cloud Text-to-Speech: AudioConfig —
audioEncoding,speakingRate,sampleRateHertz필드 정의와 기본값 동작 - Cloud Text-to-Speech basics — MP3/LINEAR16 인코딩, 음성/언어 코드 등 개념 정리
- Cloudflare R2 — Presigned URLs / Public Buckets — R2 public URL로 redirect하는 캐시 전략의 공식 근거
- MDN: HTTP Cache-Control — 응답에 쓴
private, max-age=86400의 정확한 의미 - MDN: 307 Temporary Redirect — 상태 코드를 지정하지 않은
NextResponse.redirect(url)이 기본으로 보내는 응답(메서드 보존 임시 리다이렉트)