리플레이 디스크를 GA4 3년치로 다시 쟀다
리플레이 용량 실측 편은 “리플레이 1개 평균 213KB, 디스크 여유 66GB — 걱정할 단계 아님”으로 끝났다. 개발자 몇 명이 쓰는 테스트 트래픽 얘기였다. 운영 트래픽이 들어오면 어떻게 될까. 레거시 앱의 GA4에서 3년치 세션을 뽑아 다시 쟀더니, 처음 감으로 잡아 둔 알람 기준이 세 번 뒤집혔다.
(사내 인프라 특성상 서비스 이름·서버 주소는 일반화했다.)
정해야 할 값은 셋
레거시 웹앱의 프런트를 React로 바꾸면서 Sentry Session Replay를 켜기로 했다. self-hosted라 디스크가 곧 쿼터다. 정해야 할 값은 셋이었다.
- 리플레이 샘플링:
replaysOnErrorSampleRate(에러가 난 세션만 녹화),replaysSessionSampleRate(아무 세션이나 무작위 녹화) - 90일 보관할 때 디스크 크기
- 디스크 알람을 울릴 기준
처음 초안에는 “5GB 넘으면 알람” 정도로 적어 뒀다. 근거는 없었다.
근거는 레거시 앱의 GA4에서 가져오기로 했다. 프런트만 바꾸는 것이니 새 React 앱은 같은 사용자와 같은 트래픽을 그대로 물려받는다. 레거시의 세션 수가 React 배포 첫날의 가장 정확한 예측치다. 리플레이는 세션 단위로 녹화되니 이용자 수가 아니라 세션 수를 본다.
3년치 세션 — 평시는 잔잔하고, 신고철은 3.8배
| 연도 | 총 세션 | 일평균 |
|---|---|---|
| 2023 | 약 335만 | 약 9,190 |
| 2024 | 약 367만 | 약 10,020 |
| 2025 | 약 332만 | 약 9,100 |
| 2026 (8월 중순까지) | 약 176만 | 약 7,800 |
평시는 하루 9,000~10,000세션으로 3년 내내 비슷했다. 트래픽이 늘어 디스크가 서서히 차오를 걱정은 없다는 뜻이다.
문제는 세무 신고철이다. 2025년 가장 붐빈 달은 1,043,569세션, 하루 약 34,800으로 연평균의 약 3.8배였다. 한산한 달은 하루 2,830 정도이고, 마감일 당일에는 그 달 평균의 1.5~2배(하루 5~7만)도 가능하다. “평균의 두 배쯤 잡아 두면 되겠지”라는 어림으로는 놓치는 크기다.
GA4에서 하나 헤맨 점이 있다. 탐색(Explore) 화면은 데이터 보존 기간(기본 2개월, 최대 14개월) 때문에 작년 신고철을 보여 주지 못한다. 몇 년 전 수치는 보고서 → 획득 → 트래픽 획득에서 봐야 한다. 탐색에서 안 보인다고 “데이터가 없다”고 결론 내리면 안 된다.
리플레이 한 개는 얼마인가
테스트 서버에서 세 번 쟀다(재는 방법은 실측 편에 있다).
| 날짜 | 개수 | 총량 | 1개 평균 |
|---|---|---|---|
| 7월 27일 | 51 | 10.9MB | 약 213KB |
| 8월 13일 | 349 | 59MB | 약 177KB |
| 9월 8일 | 658 | 147MB | 약 229KB |
세션이 길수록 커진다. 처음에 가정한 250KB가 타당했다. 다만 에러 세션 하나에 에러가 평균 2.4건 붙어 있어서, 세션당으로 보면 리플레이 229KB에 에러 43KB를 더한 272KB가 더 정확하다.
계산식은 이렇다. 전제는 에러 세션만 녹화(onError 1.0, session 0)하고, 에러율은 GA에 없으니 5%로 가정했다.
하루 저장량 = 하루 세션 수 × 에러율 × 샘플링율 × 리플레이 1개 크기
첫 번째 — “5GB 알람”
8월 중순 첫 계산(리플레이 250KB 가정)부터 초안이 무너졌다.
- 평시: 하루 1만 세션 × 5% × 250KB ≈ 하루 125MB
- 가장 붐빈 달: 하루 34,800 × 5% × 250KB ≈ 하루 435MB → 그 한 달만 약 13GB
한 달 치만으로 13GB가 쌓이는데 5GB에서 알람이 울리면 경보가 아니라 소음이다. 기준을 25~30GB로 올렸다. 이때 계산한 최악의 90일은 약 20GB였다.
두 번째 — 최악은 20GB가 아니라 27GB
20GB는 90일 동안 신고철이 한 번 들어온다고 가정한 값이었다. 그런데 세무 일정은 1~2월 연말정산, 1월 부가세, 3월 법인세로 몰려 있다. 1~3월이라는 90일 창 하나에 성수기가 두 번 들어온다.
9월에 실측 단가로 다시 계산했다(평시 하루 9,100세션, 229KB 기준).
| 90일 동안 리플레이가 차지하는 공간 | 에러율 5% |
|---|---|
| 평시 | 약 9.4GB |
| 성수기 한 번 | 약 18.2GB |
| 성수기 두 번 겹침 | 약 27GB |
에러율이 10%면 전부 두 배다. 그리고 신고철에는 부하 때문에 타임아웃·5xx가 늘어 에러율 자체가 같이 오를 가능성이 크다. 세션이 3.8배인데 에러율까지 곱해지니, 고정 5%는 낙관적이다. 그래서 디스크 크기는 에러율 10%로 잡고, 5%를 운영 목표로 두자고 정리했다. 너무 작게 잡은 대가(신고철에 디스크가 가득 참)가 너무 크게 잡은 대가(디스크가 남음)보다 훨씬 크다.
세 번째 — “얼마 썼나”가 아니라 “얼마 남았나”
리플레이만 보다가 서버 전체를 다시 계산해 보니, 알람 기준 자체가 틀린 방식이었다. Sentry는 리플레이 말고도 OS, 컨테이너 이미지, Kafka, 에러, 트레이스가 디스크를 쓴다.
| 서버 전체 (GB) | 평시 | 성수기 한 번 | 성수기 두 번 |
|---|---|---|---|
| OS·이미지·Kafka | 29.8 | 32.7 | 36.7 |
| 리플레이 90일 | 9.4 | 18.2 | 27.0 |
| 에러 90일 | 1.2 | 2.4 | 3.6 |
| 합계 (트레이싱 끔) | 40.4 | 53.3 | 67.3 |
| 합계 (트레이싱 켬) | 43.9 | 59.8 | 77.3 |
평시에도 40GB를 쓴다. “25~30GB 넘으면 알람”이면 첫날부터 계속 울린다. 기준을 쓴 양이 아니라 남은 양으로 바꿨다. 남은 공간 30GB에서 경고, 15GB에서 위험.
그리고 이 표가 더 큰 사실을 보여 줬다. 지금 서버는 98GB 디스크에 여유가 63GB다. 성수기 두 번이 겹치면 67~77GB가 필요하다. 지금 서버로는 운영 트래픽을 못 버틴다. 지금 넉넉해 보이는 건 아직 운영 트래픽이 안 들어와서일 뿐이다. 새 서버 디스크는 최악에 여유 30%를 더한 150GB를 권고했다.
아직 모르는 것
- 에러율. 5%는 가정이다. 실측하려면 분모인 세션(릴리즈 헬스) 데이터가 필요한데, React 앱 프로젝트의 세션 데이터가 8월 21일 이후 끊겨 있다. 원인을 찾기 전에는 실측할 수 없다.
- 웹과 모바일이 섞였을 가능성. 이 GA4 속성에는 모바일 앱 채널로 보이는 항목도 있다. 리플레이는 웹 대상이니 웹 세션만 걸러야 정확하다. 다만 섞였다면 숫자가 실제보다 크게 잡힌 쪽이라, 사이징에는 여유를 두는 방향의 오차다.
마치며
이 숫자를 가지고 무엇을 받고, 언제 지우고, 어떻게 지켜볼지 정한 이야기는 보존 정책 편에 이어서 적었다.
진짜로 배운 것
- 시즌이 있는 서비스는 평균이 아니라 최악의 보관 기간 창으로 잰다. 보관이 90일이면 성수기 짐은 석 달 동안 남는다. 그 창에 성수기가 몇 번 들어오는지까지 센다.
- 알람은 “얼마 썼나”가 아니라 “얼마 남았나”로 건다. 시스템이 원래 쓰는 고정비가 있으면 사용량 기준은 첫날부터 소음이 된다.
- 근거에 결함이 있으면, 그 결함이 어느 방향으로 틀리게 하는지를 같이 적는다. 웹·모바일이 섞인 GA4 숫자는 불완전했지만 크게 잡히는 쪽이라, 5GB 기준을 뒤집기에는 충분했다.
- 가정은 가정이라고 남겨 둔다. 에러율 5%는 실측으로 바꿀 자리다. 그 자리가 비어 있다는 걸(세션 데이터 끊김) 찾은 것도 이번 조사의 결과다.