콘텐츠로 이동

대량의 이미지를 파일시스템에 저장할 때

웹 서비스나 애플리케이션을 운영하다 보면 사용자 프로필, 게시글 첨부 등 대량의 이미지 파일을 처리해야 할 때가 옵니다. 이때 데이터를 어떻게 저장하고 관리할지에 대한 전략이 필요합니다.

1. DB vs FileSystem

일반적으로 이미지 바이너리 데이터 자체는 파일 시스템(또는 Object Storage)에 저장하고, 그 파일의 경로(Path)나 메타데이터만 데이터베이스에 저장하는 것이 정석입니다.

  • DB에 저장 시 문제점:
    • DB 용량이 불필요하게 커져 백업/복구 비용이 증가합니다.
    • DB 캐시 효율이 떨어지고 트랜잭션 처리에 부담을 줍니다.
    • 웹 서버에서 정적 파일(이미지)을 직접 서빙(Serving)하는 것이 DB를 거치는 것보다 훨씬 빠르고 효율적입니다.

2. 파일 시스템 저장 시 고려사항

2.1 디렉토리 구조화 (Partitioning)

한 디렉토리(폴더)에 너무 많은 파일이 존재하면 성능 저하가 발생합니다.

  • 문제점: ls 같은 목록 조회 명령어가 느려지고, 일부 파일 시스템(ext3 등)에서는 디렉토리 당 파일 수 제한이 있거나 성능이 급격히 떨어질 수 있습니다.
  • 해결책: 계층적 디렉토리 구조를 사용합니다.
    • 권장: 디렉토리 당 파일 수를 약 1,000 ~ 10,000개 미만으로 유지하는 것이 좋습니다.

2.2 파일명 생성 전략

파일명 충돌을 방지하고 보안을 위해 사용자가 업로드한 원본 파일명을 그대로 사용하는 것은 지양해야 합니다.

  • UUID 또는 해시값 사용: 파일을 유니크하게 식별할 수 있는 UUID나 파일 내용의 해시(MD5, SHA256 등)값을 파일명으로 사용합니다.
  • 경로 분산 (Path Hashing): 파일명의 앞 글자를 따서 디렉토리를 생성합니다.
    • 예: 파일명이 f6a5b123...jpg 라면
    • 저장 경로: /f/6/f6a5b123...jpg 또는 /f6/a5/f6a5b123...jpg
    • 이렇게 하면 수백만 개의 파일이 들어와도 첫 두 글자(256가지 조합)에 따라 디렉토리가 분산되므로 한 폴더에 파일이 몰리는 것을 방지할 수 있습니다.

2.3 보안 및 접근 제한

  • 웹 서버 설정: 업로드된 파일이 있는 디렉토리에서는 스크립트(PHP, JSP, ASP 등) 실행 권한을 막아야 합니다. (웹쉘 공격 방지)
  • 직접 접근 방지: 필요한 경우 이미지를 private 디렉토리에 두고 애플리케이션 레벨에서 권한을 체크한 뒤 스트리밍으로 제공하거나, Pre-signed URL 등을 활용해야 합니다.

3. 대안 및 확장 (Distributed Storage)

서비스 규모가 커져 단일 서버의 디스크 용량이나 I/O 처리가 한계에 다다르면 다음과 같은 분산 파일 시스템이나 오브젝트 스토리지를 고려해야 합니다.

  • Object Storage (S3, MinIO): 가장 현대적이고 추천되는 방식입니다. AWS S3, Google Cloud Storage 등을 사용하거나, 온프레미스에서는 MinIO 같은 S3 호환 스토리지를 구축합니다. API 기반으로 관리하기 쉽고 확장성이 뛰어납니다.
  • SeaweedFS: 수십억 개의 작은 파일(Small Files)을 효율적으로 저장하기 위해 설계된 오픈소스 분산 파일 시스템입니다. Facebook의 Haystack 논문 아이디어를 기반으로 하여 빠른 I/O를 제공합니다.
  • GlusterFS, Ceph: 범용적인 분산 파일 시스템으로 고가용성과 확장성을 제공합니다.

참고