들어가며
지난 글에서 웹콘텐츠 창작자들을 위한 포트폴리오 서비스 LAITEU의 기획 배경과 전체적인 기술 스택에 대해 소개했습니다. 이번에는 "왜 MongoDB를 선택했는지", 그리고 "실제로 어떻게 데이터를 설계했는지"에 대해 이야기해보려 합니다.
MongoDB, 무엇이 다른가?
MongoDB를 설명하기 전에, 기존의 관계형 데이터베이스(RDBMS)와의 차이점부터 간단히 짚어보겠습니다.
예를 들어 웹툰 작가의 작품을 저장한다고 생각해봅시다. 관계형 데이터베이스에서는 다음과 같은 테이블 구조가 필요할 것입니다:
- 작품 테이블 (제목, 설명 등)
- 작품 이미지 테이블 (이미지 URL, 순서 등)
- 작품 태그 테이블 (태그 정보)
- 작업 과정 테이블 (스케치, 선화, 채색 등의 단계별 정보)
그런데 일러스트 작가의 경우는 어떨까요? 작업 과정이 다르고, 필요한 정보도 다릅니다. 웹소설 작가는 또 다르겠죠. 이렇게 다양한 형태의 데이터를 관계형 데이터베이스에서 관리하려면, 새로운 요구사항이 생길 때마다 테이블 구조를 수정해야 합니다.
반면 MongoDB는 자유로운 형태의 데이터 저장이 가능합니다. JSON과 비슷한 형태로 데이터를 저장하기 때문에, 작가의 유형에 따라 다른 구조의 데이터를 유연하게 저장할 수 있습니다.
데이터 모델 설계: 실제 사례를 통해 알아보기
LAITEU의 핵심 데이터는 크게 세 가지입니다: 작가(Artist), 작품(Artwork), 작품 이미지(ArtworkImage). 각각이 어떤 구조로 되어있는지, 실제 예시와 함께 살펴보겠습니다.
1. 작가(Artist) 데이터 구조
{
"artistId": "a12345",
"firebaseUid": "firebase123", // 로그인에 사용되는 ID
"artistName": "김라이트",
"profileImage": "profile-url",
"introduction": "안녕하세요, 웹툰 작가입니다",
"employmentStatus": "LOOKING_FOR_JOB", // 구직 상태
"favoriteFolders": [ // 북마크 폴더
{
"folderName": "참고작품",
"artworkIds": ["artwork1", "artwork2"]
}
],
"folioId": "kimlight-1234", // 공개 포트폴리오 URL
"artistType": "WEBTOON" // 작가 유형
}
이렇게 설계한 이유는 다음과 같습니다:
- 북마크 폴더를 작가 정보 안에 포함
- 북마크는 작가별로 관리되며, 다른 정보와 독립적으로 자주 조회/수정됨
- 별도 컬렉션으로 분리하면 조회 시 추가 쿼리가 필요
- folioId 필드 추가
- 외부 공유용 URL을 위한 식별자
- 작가의 실명이나 개인정보 노출 없이 포트폴리오 공유 가능
2. 작품(Artwork) 데이터 구조
{
"artworkId": "artwork123",
"artistId": "a12345",
"title": "나의 첫 웹툰",
"artworkImageIds": ["img1", "img2", "img3"], // 이미지 목록
"artworkTags": ["스케치", "채색", "완성본"], // 작업 단계
"artworkStatus": "PUBLIC", // 공개 상태
"publicId": "abc123", // 공유용 ID
"age": "ALL", // 연령 제한
"duration": "2주" // 작업 기간
}
특이한 점들을 살펴보면:
- 이미지는 ID로만 참조
- 대용량 이미지 정보는 별도 컬렉션에서 관리
- 작품 정보 조회 시 불필요한 이미지 데이터 로딩 방지
- 공개 상태 관리
- PUBLIC: 전체 공개
- PRIVATE: 비공개
- LINK_ONLY: 링크로만 공개
- DELETED: 삭제됨
3. 작품 이미지(ArtworkImage) 데이터 구조
{
"imageId": "img1",
"previewImageUri": "thumbnail-url", // 썸네일 이미지
"imageUri": "original-url", // 원본 이미지
"tagsScores": { // AI가 분석한 이미지 태그
"캐릭터": 0.95,
"귀여움": 0.82
},
"description": "메인 캐릭터 표정 시트",
"updatedAt": "2024-01-01T12:00:00Z"
}
이미지 데이터를 별도로 관리하는 이유:
- 이미지 URL과 메타데이터의 독립적인 관리 가능
- AI 태그 분석 결과를 효율적으로 저장
- 썸네일과 원본 이미지의 분리된 관리
실제 구현 과정에서 마주친 도전과제들
1. 작품 목록 조회 성능 문제
처음에는 단순히 다음과 같이 구현했습니다:
// 초기 구현 - 성능 문제 발생
List<Artwork> artworks = artworkRepository.findByArtistId(artistId);
for (Artwork artwork : artworks) {
for (String imageId : artwork.getArtworkImageIds()) {
// 각 이미지마다 개별 조회 발생!
ArtworkImage image = imageRepository.findById(imageId);
// ...
}
}
이 방식의 문제점:
- 작품 수가 많을수록 데이터베이스 조회가 기하급수적으로 증가
- 페이지 로딩 시간 증가
개선된 방식:
// 개선된 구현
// 1. 필요한 이미지 ID 모두 수집
List<Artwork> artworks = artworkRepository.findByArtistId(artistId);
Set<String> allImageIds = artworks.stream()
.flatMap(a -> a.getArtworkImageIds().stream())
.collect(Collectors.toSet());
// 2. 한 번에 모든 이미지 조회
Map<String, ArtworkImage> imageMap = imageRepository
.findAllById(allImageIds)
.stream()
.collect(Collectors.toMap(
ArtworkImage::getImageId,
image -> image
));
2. 북마크 기능 구현의 어려움
북마크 기능은 다음과 같은 도전과제가 있었습니다:
- 폴더 생성/삭제/이동이 빈번하게 발생
- 여러 사용자가 동시에 같은 작품을 북마크
처음에는 북마크를 별도 컬렉션으로 관리하려 했으나, 다음과 같은 이유로 작가 데이터 내부에 포함시켰습니다:
- 조회 성능 향상
- 트랜잭션 처리 단순화
- 데이터 일관성 유지 용이
배운 점과 앞으로의 과제
MongoDB를 사용하면서 가장 크게 배운 점은 "데이터 접근 패턴에 따른 모델링의 중요성"입니다. 관계형 데이터베이스처럼 정규화에만 집중하는 것이 아니라, 실제로 데이터를 어떻게 사용할 것인지를 고려한 설계가 필요했습니다.
앞으로 해결해야 할 과제들:
- 검색 기능 강화
- 현재는 단순 태그 기반 검색만 지원
- Elasticsearch 도입으로 전문 검색 기능 추가 계획
- 대용량 데이터 처리
- 이미지가 많은 작품의 경우 로딩 시간 개선 필요
- 캐싱 시스템 도입 검토
- 데이터 백업과 복구
- 안정적인 백업 시스템 구축
- 장애 상황 대비 복구 전략 수립
마치며
데이터 모델링은 서비스의 성능과 확장성을 결정짓는 중요한 기반이 됩니다. LAITEU 프로젝트에서 MongoDB를 선택하고 데이터 모델을 설계하면서, 단순히 데이터를 저장하고 조회하는 것을 넘어 실제 사용자들의 사용 패턴과 요구사항을 깊이 이해하는 것이 얼마나 중요한지 배웠습니다.
특히 웹콘텐츠 창작자들의 다양한 작업 방식과 포트폴리오 구성을 지원하기 위해서는, 기술적인 효율성뿐만 아니라 실제 사용자들의 편의성도 함께 고려해야 했습니다. 이는 단순한 기술 선택의 문제가 아니라 서비스의 본질적인 가치를 구현하는 과정이었습니다.
다음 글에서는 이렇게 설계한 데이터 모델을 기반으로, 실제로 포트폴리오의 핵심 기능들을 어떻게 구현했는지 더 자세히 다루도록 하겠습니다.
'[프로젝트] > [백엔드] LAITEU' 카테고리의 다른 글
EC2에서 Multi-Version API 서버 구현하기 (1) | 2024.11.20 |
---|---|
작품 대표 이미지 저장 (1) | 2024.11.20 |
API 응답 형식 표준화: 즐겨찾기 서비스 개선 (0) | 2024.11.20 |
AWS 개발 환경 비용 최적화하기 (0) | 2024.11.20 |
[Spring] LAITEU 개발기 (1) - 백엔드 아키텍처 설계 (5) | 2024.11.20 |