Sentry Session Replay 용량 실측
TL;DR 자체 호스팅 Sentry의 Session Replay 데이터가 서버 디스크에서 얼마나 잡아먹는지 실측. 관련 DB 테이블(
replays_replayrecordingsegment,sentry_file)은 스키마만 있고 row가 0건 — 이 배포에서는 리플레이가 Django ORM을 안 거치고 파일시스템에 직접 저장된다. DB 쿼리는 시간 낭비였다. 폴더는 UUID 그대로 샤딩(체크섬 샤딩 아님)이라 UI의 리플레이 ID로 바로 잡을 수 있다. 리플레이 1개당 평균 약 213KB, 총 10.9MB / 66GB 여유 — 지금 페이스로는 걱정할 단계 아님.
배경
프론트팀에서 “에러마다 리플레이 영상이 남는데 얼마나 용량을 잡아먹는지” 물어봤다. 특정 프로젝트에 리플레이가 대략 50개 쌓여 있는 상황이었다. 답을 주려고 DB부터 뒤졌는데, 스키마는 있고 데이터가 없어서 잠깐 헷갈렸다. 결론은 “이 배포에서는 리플레이가 Django ORM을 안 거치고 파일시스템에 직접 저장된다”였다.
시도 1: DB 쿼리 — 스키마는 있는데 데이터가 없었다
리플레이 관련 테이블부터 찾아봤다.
docker compose exec postgres psql -U postgres -d postgres
(참고로 DB 이름이 sentry가 아니라 postgres였다. -l로 데이터베이스 목록을 먼저 확인해야 한다.)
관련 테이블은 이렇게 나왔다.
replays_replayrecordingsegmentsentry_filesentry_fileblob
각각 SELECT count(*) 걸어봤는데 세 테이블 모두 row가 0건이었다. 그런데 실제로 Sentry UI에서 리플레이는 정상적으로 재생됐다. 이 시점에 좀 헷갈렸다 — 재생이 되면 데이터는 어딘가 있어야 한다.
결론은 명확했다. 이 Sentry 배포는 리플레이 레코딩을 Django File ORM을 경유하지 않고 스토리지에 직접 쓰고 읽는 구조였다. sentry_file 테이블은 다른 종류의 파일(첨부, 아바타 등)용이지 리플레이 데이터를 여기서 트래킹하지 않는다.
DB 스키마가 있다고 실제로 그 경로로 데이터가 흐르는 건 아니다. “스키마 존재”와 “쓰기 경로”는 다른 층의 정보다.
이 층에서 뽑을 수 없다고 판단하고 파일시스템으로 넘어갔다.
시도 2: 파일시스템 직접 확인 — UUID 패턴을 찾기
Sentry 데이터 볼륨의 마운트 위치부터 확인했다.
docker volume inspect sentry-data --format '{{ .Mountpoint }}'
# /var/lib/docker/volumes/sentry-data/_data
이 안에 /files/ 폴더가 있고, 그 밑이 여러 레벨의 샤딩 폴더로 나뉜다. 그런데 여기에 함정이 하나 있었다.
리플레이 폴더는 UUID 패턴(/data/files/<샤드>/<서브샤드>/<UUID>/<세그먼트번호>), 일반 파일 폴더는 체크섬 샤딩 패턴(2자/4자/나머지).
처음에 /data/files/7a/e111/... 폴더를 발견했을 때 이게 리플레이인 줄 알았다. 그런데 file 명령으로 내용물을 확인해보니 1024x1024 PNG 이미지였다. 생성 날짜도 리플레이 테스트 훨씬 이전이었다. 조직/프로젝트 아바타로 추정되는 파일이었고, 이건 체크섬 샤딩(2자/4자) 규칙을 따르고 있어서 리플레이와는 완전히 다른 경로였다.
실제 리플레이 폴더는 UI에 표시되는 리플레이 ID를 그대로 폴더 이름으로 쓰고 있었다.
sudo find /var/lib/docker/volumes/sentry-data/_data/files -type d -iname "<리플레이ID>*"
sudo du -sb <나온 경로> # 리플레이 하나의 정확한 크기
UI의 리플레이 ID(예: 7a7fbf98...)를 그대로 find에 넣으면 폴더가 바로 잡힌다. 그 안에 세그먼트 번호로 파일이 몇 개 들어있고, 세션 길이(이벤트/브레드크럼 개수)에 비례해서 크기가 바뀐다.
폴더 이름 패턴이 스토리지 종류를 알려준다. UUID 형태면 리플레이/이벤트, 짧은 문자열의 계층 샤딩이면 체크섬 기반 일반 파일.
file명령으로 내용물까지 한 번 확인해두면 오판이 없다.
샘플 측정 결과
이번 배포에서는 리플레이가 전부 /data/files/90/ 밑에 몰려 있었다(다른 샤드는 없었음). 그래서 이 폴더 전체를 재면 됐다.
| 리플레이 | 세그먼트 수 | 크기 |
|---|---|---|
| 새로 만든 테스트 리플레이 | 4개 | ~49.5KB |
| 기존 리플레이 A | 19개 | ~93.1KB |
| 기존 리플레이 B | ? | ~156.1KB |
세션 길이(이벤트/브레드크럼 개수)에 비례해서 커진다.
전체 합계.
files/90 폴더 전체: 10,881,645 bytes
÷ 51개 (기존 50개 + 테스트 1개)
= 리플레이 1개당 평균 약 213KB
- 리플레이 총량: 약 10.9MB
- 서버 전체 디스크 여유: 66GB (98GB 중 28GB 사용)
- 결론: 지금 페이스로는 용량 걱정할 단계 전혀 아님
참고
- 환경: self-hosted Sentry (Docker Compose, Postgres + 파일 스토리지)
- 볼륨:
sentry-data,sentry-seaweedfs - 이 글의 결론은 배포 시점 기준. Sentry 버전이나 스토리지 백엔드 설정이 바뀌면 실제 쓰기 경로가 달라질 수 있음
- 선행 글: CSRF 6단계 · Slack 통합 · 권한 모델 · ingest 외부 노출