StudyDad Loop 제품을 만들며 배운 운영과 설계를 기록합니다.

FamBlend를 중심으로 실제 구현, 운영 메모, GitHub 포트폴리오를 연결해 쌓아가는 StudyDad의 작업 기록입니다.

성장과 기술/시스템 설계

데이터베이스를 쓰지 않기로 한 아키텍처 결정

박세식 2026. 7. 9. 12:00

운영 콘솔 아키텍처 시리즈 4/9

운영 도구를 만들 때 가장 먼저 데이터베이스를 떠올리는 경우가 많다. 목록이 있고, 상태가 있고, 조회 화면이 있으면 자연스럽게 RDB 테이블을 설계하게 된다.

하지만 모든 운영 콘솔에 데이터베이스가 필요한 것은 아니다. 어떤 경우에는 데이터베이스를 추가하지 않는 것이 더 단순하고 안전한 결정이 될 수 있다.

문제 상황

신청 관리 콘솔의 데이터 원천은 이미 외부에 있었다. 외부 파트너는 폼 도구로 신청했고, 운영자는 스프레드시트에서 데이터를 검수하고 상태를 관리했다. 스프레드시트가 사실상 Source of Truth였다.

콘솔은 이 데이터를 더 보기 좋게 보여주고, 공개 가능한 일부 데이터를 외부에 노출하면 됐다. 데이터 규모는 크지 않았고, 변경도 특정 시점에 몰렸다. 초당 수십 번씩 쓰기가 발생하는 시스템이 아니었다.

이 조건에서 RDB를 새로 두면 다음 책임이 생긴다.

  • 스키마 설계
  • 데이터 동기화
  • 백업과 복구
  • 권한 관리
  • 장애 대응
  • 원천 데이터와 복제 데이터의 정합성 관리

오히려 시스템이 복잡해질 수 있었다.

선택지

첫 번째 선택지는 RDB를 새로 만드는 것이었다. 데이터 조회와 필터링은 편해지지만, 원천이 이미 스프레드시트인 상황에서는 복제 저장소가 하나 더 생긴다.

두 번째 선택지는 스프레드시트를 실시간으로 직접 조회하는 것이었다. 하지만 브라우저가 직접 조회하기에는 권한과 응답 속도 문제가 있고, 공개용 데이터와 내부용 데이터를 분리하기도 어렵다.

세 번째 선택지는 스프레드시트 데이터를 주기적으로 JSON으로 변환해 객체 저장소에 저장하는 것이었다. 콘솔은 이 JSON을 읽고, 객체 저장소는 스냅샷과 감사 로그 역할도 한다.

세 번째 방식을 선택했다.

최종 결정

RDB를 두지 않고, S3 같은 객체 저장소에 JSON 스냅샷을 저장한다.

핵심은 객체 저장소를 원천 데이터베이스처럼 쓰지 않는 것이다. 원천은 스프레드시트이고, 객체 저장소는 콘솔이 빠르고 안전하게 읽기 위한 캐시와 스냅샷이다.

구현 구조

저장 구조는 단순하게 나눴다.

console-data-bucket/
├── latest/data.json
├── monthly/data-YYYY-MM.json
├── public/calendar-YYYY-MM.json
└── audit/YYYY-MM/YYYY-MM-DD/sync-HHMMSS.json

latest/data.json은 첫 화면이나 최신 상태 조회에 사용한다. 사용자는 대부분 최신 데이터를 보고 싶어 하기 때문에 고정된 키가 있으면 클라이언트와 API가 단순해진다.

monthly/data-YYYY-MM.json은 월별 조회를 위한 스냅샷이다. 월 단위로 데이터를 다시 볼 수 있고, 과거 화면을 재현하기 쉽다.

public/calendar-YYYY-MM.json은 공개 가능한 정보만 담은 사본이다. 내부용 데이터에서 민감한 필드를 제거한 뒤 별도 파일로 저장한다. 공개 화면은 이 파일만 읽는다.

audit/.../sync-HHMMSS.json은 감사 목적의 append-only 백업이다. 동기화가 잘못됐을 때 이전 데이터를 확인하거나 되돌릴 수 있다.

얻은 것

가장 큰 장점은 단순함이다. RDB 인스턴스도 없고, 마이그레이션도 없고, 커넥션 풀도 없다. 데이터가 작고 읽기 패턴이 단순하다면 JSON 파일 하나를 읽는 것으로 충분하다.

캐시와도 잘 맞는다. 월별 데이터는 자주 바뀌지 않으므로 CDN이나 API 계층에서 캐시하기 좋다. 공개용 데이터는 민감한 필드를 제거한 파일만 노출하면 되므로 보안 경계도 명확하다.

감사 로그를 만들기도 쉽다. 동기화할 때마다 timestamp가 붙은 파일을 남기면 된다. 별도 이력 테이블을 만들지 않아도 어느 시점에 어떤 데이터가 올라갔는지 확인할 수 있다.

포기한 것

복잡한 검색과 조인은 어렵다. 여러 조건으로 빠르게 필터링하거나, 관계형 데이터를 조인해야 한다면 RDB가 더 적합하다.

동시 쓰기 제어도 약하다. 여러 주체가 동시에 같은 데이터를 수정하는 시스템이라면 JSON 파일 저장 방식은 맞지 않는다. 이 구조는 쓰기 주체가 제한적이고, 동기화 시점이 명확할 때 유효하다.

데이터 크기가 커지면 한 파일을 계속 읽는 방식이 부담이 된다. 이 경우 월별, 상태별, 공개용 등으로 파일을 더 나누거나 결국 데이터베이스로 이전해야 한다.

다시 설계한다면

처음부터 JSON schema 검증을 더 엄격하게 넣겠다. 파일 기반 저장소는 스키마가 느슨해지기 쉽다. 동기화 함수에서 필수 필드, 타입, 공개 가능 여부를 검증하면 장애를 줄일 수 있다.

또한 공개용 파일을 만들 때 제거한 필드 목록을 테스트로 고정하겠다. 공개 데이터와 내부 데이터가 같은 원천에서 나오기 때문에, 실수로 민감한 필드가 섞이지 않도록 자동 검사가 필요하다.

정리

데이터베이스를 쓰지 않는 것도 아키텍처 결정이다.

데이터 원천이 이미 외부에 있고, 데이터 규모가 작고, 변경 빈도가 낮고, 읽기 패턴이 단순하다면 RDB보다 객체 저장소의 JSON 스냅샷이 더 단순할 수 있다. 중요한 것은 객체 저장소를 원천 데이터베이스로 착각하지 않고, 캐시와 스냅샷이라는 역할을 명확히 하는 것이다.

함께 볼 GitHub 저장소

Next Step 이 글은 StudyDad 작업 루프의 한 조각입니다.

글에서 정리한 생각은 GitHub의 코드와 포트폴리오로 이어지고, 일부는 FamBlend 같은 제품 실험으로 확장됩니다.