광고 차단 프로그램이 감지되었습니다

이 사이트는 광고 수익을 통해 무료로 콘텐츠와 서비스를 제공하고 있습니다.

더 나은 서비스를 위해 광고 차단 프로그램을 비활성화 해주세요.

광고 차단 해제 방법 보기
Loading...

Django + MongoDB에 PostgreSQL 추가하기: 끝나지 않는 마이그레이션 전쟁과 해법

Django + MongoDB에 PostgreSQL 추가하기: 끝나지 않는 마이그레이션 전쟁과 해법에 대한 img

서론

  • [주제 소개]: 많은 Django 프로젝트가 개발 초기 단계의 유연성 때문에 MongoDB로 시작합니다. 하지만 서비스가 성장하면서 데이터 관계 분석, 트랜잭션 보장, 통계 기능 등 관계형 데이터베이스(RDBMS)의 강력한 기능이 필요해지는 순간이 찾아옵니다. 이때 가장 많이 고려되는 조합이 바로 기존 MongoDB 환경에 PostgreSQL을 추가하는 '멀티 데이터베이스' 구성입니다. 이 글은 이 복잡하고 어려운 여정을 안내하는 실전 가이드입니다.
  • [왜 작성하였는가?]: 단순히 공식 문서를 번역하는 수준을 넘어, 실제 운영 환경에서 겪게 될 수많은 오류와 함정들을 미리 짚어봅니다. 이 글을 통해 독자들은 '왜 이 오류가 발생하는가?'에 대한 근본적인 이해를 얻고, 수많은 디버깅 시간을 절약하며, 안정적으로 멀티 데이터베이스 환경을 구축하고 운영하는 노하우를 얻어갈 수 있습니다.


Django 멀티 DB: 핵심 개념 파헤치기

  • Database Router (데이터베이스 라우터): Django 프로젝트에 여러 데이터베이스가 있을 때, 특정 쿼리(읽기, 쓰기, 마이그레이션)를 어떤 데이터베이스로 보낼지 결정하는 '교통 경찰'입니다.
  • 왜 중요한가요?: 라우터가 없다면 Django는 어떤 앱의 데이터를 어디에 저장해야 할지 전혀 알 수 없습니다. 멀티 데이터베이스 운영의 성패를 좌우하는 가장 핵심적인 설정입니다.
  • DEFAULT_AUTO_FIELD (기본 자동 필드): 프로젝트 전체에서 모델의 기본 Primary Key를 어떤 타입으로 만들지 지정하는 전역 설정입니다.
  • 놓치기 쉬운 점: 이 설정은 프로젝트 전체에 영향을 미칩니다. MongoDB를 위해 ObjectIdAutoField로 설정된 경우, PostgreSQL에 마이그레이션을 시도할 때 PostgreSQL이 알지 못하는 objectId 타입을 만들려 하여 100% 오류가 발생합니다. 많은 개발자들이 이 '전역성'을 간과하여 디버깅의 늪에 빠집니다.
  • 마이그레이션 파일 (Migration Files): 모델의 구조를 데이터베이스에 반영하기 위한 '설계도' 또는 '지시서'입니다. makemigrations 명령어로 생성됩니다.
  • 실무 적용 시 고려사항: 마이그레이션 파일은 생성될 당시의 settings.py 설정을 기반으로 만들어집니다. 즉, 설정에 문제가 있는 상태에서 생성된 마이그레이션 파일은 그 문제가 '박제'되어 버립니다. 나중에 설정을 고쳐도, 이미 잘못 만들어진 설계도는 계속 문제를 일으킵니다.


Django 멀티 DB: 공식 가이드라인 & 권장 사항

  • [공식 소스]: 이 주제에 대한 가장 정확한 정보는 Django 공식 문서의 Multiple databases 섹션입니다. 문제가 발생했을 때 가장 먼저 참고해야 할 최종 권위의 출처입니다.
  • [주요 권장 사항]:
  • 안전 제일 원칙DatabaseRouter의 allow_relation 메소드를 반드시 구현하여, 서로 다른 종류의 데이터베이스(예: PostgreSQL과 MongoDB) 간에 실수로라도 관계(ForeignKey)가 맺어지는 것을 원천 차단해야 합니다. 이는 예기치 않은 오류와 데이터 불일치를 막는 가장 중요한 안전장치입니다.
  • 성능 및 효율성: 데이터베이스 간의 불필요한 JOIN은 성능 저하의 주범입니다. 서로 관계를 맺어야 하는 데이터(예: 사용자와 게시물)는 반드시 같은 데이터베이스 안에 두는 것이 원칙입니다.


Django 멀티 DB: 실무 적용 마스터 플랜

  • [주어진 기술 주제를 실제 환경에 적용하기 위한 구체적이고 실용적인 단계별 가이드입니다. 초보자도 쉽게 따라 할 수 있도록 자세한 설명과 예시를 포함합니다.]
  1. 첫 번째 단계: 환경 준비 및 Django 설정 추가
  • 무엇을 하는가?: Docker 환경에 PostgreSQL과 pgAdmin 서비스를 추가하고, Django가 이 새로운 데이터베이스를 인식하도록 설정합니다.
  • 어떻게 하는가?docker-compose.yml에 postgrespgadmin 서비스를 추가하고, psycopg2-binary를 설치한 뒤, settings.py의 DATABASES 사전에 'postgres' 항목을 추가합니다.
# settings.py
DATABASES = {
    'default': {
        # ... 기존 MongoDB 설정 유지 ...
    },
    # After: 새로운 PostgreSQL 설정 추가
    'postgres': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'homeserver_new',
        'USER': 'admin',
        'PASSWORD': 'admin123',
        'HOST': 'localhost', # 또는 Docker 서비스 이름
        'PORT': '5432',
    }
}
# 'default' DB 외에 'postgres'라는 별명을 가진 DB가 추가되었습니다.
  • 성공 점검docker ps 명령어로 postgres와 pgadmin 컨테이너가 정상 실행 중인지 확인하고, pgAdmin 웹페이지(http://localhost:8080) 접속에 성공합니다.
  • 실수 방지 팁: PostgreSQL 컨테이너의 포트(5432)가 로컬 PC의 다른 서비스와 충돌하지 않는지 확인하세요. 충돌 시 ports 설정에서 로컬 포트를 5433:5432 와 같이 변경해야 합니다.
  1. 두 번째 단계: ObjectId 마이그레이션 충돌 해결
  • 무엇을 하는가?: MongoDB의 ObjectId 타입과 PostgreSQL의 integer 타입 간의 충돌로 인해 발생하는 마이그레이션 오류를 해결합니다.
  • 어떻게 하는가?: PostgreSQL에 최초 마이그레이션을 실행할 때만 settings.py의 DEFAULT_AUTO_FIELD 설정을 임시로 주석 처리합니다.
# settings.py
# Before: 이 설정이 활성화되어 있으면 PostgreSQL 마이그레이션 시 오류 발생
DEFAULT_AUTO_FIELD = 'django_mongodb_backend.fields.ObjectIdAutoField'

# After (Temporarily):
# DEFAULT_AUTO_FIELD = 'django_mongodb_backend.fields.ObjectIdAutoField'

# 주석 처리 후, 컨테이너를 재시작하고 마이그레이션을 실행합니다.
# docker-compose down && docker-compose up -d --build
# docker-compose exec web python manage.py migrate --database=postgres
# 성공 후 반드시 주석을 다시 해제해야 합니다.
  • 성공 점검django.db.utils.ProgrammingError: type "objectid" does not exist 오류 없이 마이그레이션이 OK 메시지와 함께 진행됩니다.
  • 실수 방지 팁가장 많이 하는 실수는 파일을 수정하고 Docker 컨테이너를 재시작하지 않는 것입니다. docker-compose down과 up을 통해 변경된 설정이 컨테이너에 확실히 적용되었는지 확인해야 합니다.
  1. 세 번째 단계: 마이그레이션 의존성 오류 해결
  • 무엇을 하는가?: 일부 앱의 마이그레이션을 리셋하는 과정에서 꼬여버린 의존성 순서 문제를 해결합니다.
  • 어떻게 하는가?: 전체 마이그레이션을 한 번에 실행하는 대신, 의존성 순서에 따라 핵심 앱부터 하나씩 순차적으로 migrate를 실행합니다.
# Before: 이 명령어 실행 시 `relation "auth_user" does not exist` 오류 발생
python manage.py migrate --database=postgres

# After: 핵심 앱부터 순서대로 실행
python manage.py migrate contenttypes --database=postgres
python manage.py migrate auth --database=postgres
python manage.py migrate accounts --database=postgres
python manage.py migrate admin --database=postgres

# 그 후 나머지 전체 마이그레이션 실행
python manage.py migrate --database=postgres
  • 성공 점검django.db.utils.ProgrammingError: relation "..." does not exist 오류 없이 모든 마이그레이션이 성공적으로 완료됩니다.
  • 실수 방지 팁: 문제가 해결되지 않는다면 마이그레이션 기록이 완전히 꼬인 것일 수 있습니다. pgAdmin 등에서 django_migrations 테이블의 내용을 전부 삭제(DELETE FROM django_migrations;)하고 처음부터 다시 마이그레이션을 실행하는 것이 최후의 수단이 될 수 있습니다.


Django 멀티 DB: 생생한 성공 & 실패 사례 분석

  • [성공 사례] 독립적인 API 서버 구축으로 레거시 프로젝트에 활력 불어넣기
  • 배경: 오래된 Django 모놀리식 프로젝트에 고성능이 요구되는 실시간 라이선스 검증 기능을 추가해야 했다. 기존 코드베이스에 통합하기에는 복잡성과 위험 부담이 컸다.
  • 적용 전략: 새로운 기능을 기존 Django 프로젝트에 억지로 통합하는 대신, 별도의 FastAPI 프로젝트로 분리하여 '마이크로서비스'로 구축했다. 이 FastAPI 서버는 자체적으로 PostgreSQL 데이터베이스를 사용하여 라이선스 정보만 관리했다.
  • 핵심 결과: 기존 Django 프로젝트는 일절 수정 없이 안정적으로 유지되었고, 새로운 기능은 FastAPI의 비동기 성능을 활용해 빠르고 독립적으로 확장할 수 있었다. 두 서비스는 내부 API로 통신하며 완벽하게 분리 운영되었다.
  • 성공 요인 분석"모든 기능을 하나의 프로젝트에 담아야 한다"는 고정관념을 버린 것이 핵심이었다. 기능의 성격에 맞는 최적의 도구(API 서버 → FastAPI)를 선택하고, 아키텍처를 분리하여 각 서비스의 복잡도를 낮춘 것이 성공의 열쇠였다.
  • [실패 사례] 끝나지 않는 마이그레이션 전쟁: 작은 설정 하나가 불러온 재앙
  • 배경: 한 개발팀이 기존 Django/MongoDB 프로젝트에 관계형 분석 기능을 위해 PostgreSQL을 추가하기로 결정했다.
  • 실패 요인:
  1. 팀원들은 DEFAULT_AUTO_FIELD 설정이 전역적으로 영향을 미친다는 사실을 몰랐다.
  2. objectId 오류가 발생하자, 원인 파악 없이 구글링으로 찾은 migrations 폴더 삭제 등의 방법을 무분별하게 시도했다.
  3. 한 개발자가 수정한 settings.py가 Git에 제대로 반영되지 않았고, 다른 개발자는 Docker 컨테이너를 재시작하지 않아 변경사항이 적용되지 않은 채 계속 삽질을 반복했다.
  4. 결국 마이그레이션 의존성이 완전히 꼬여 relation does not exist 오류의 늪에 빠졌다.
  • 얻은 교훈근본 원인에 대한 이해 없는 임시방편은 더 큰 재앙을 부른다. 특히 설정 파일 변경 시에는, 변경 사항이 실제 실행 환경(Docker)에 어떻게 적용되는지에 대한 명확한 이해가 필수적이다. 문제 발생 시, 팀 전체가 현재 설정을 투명하게 공유하고 체계적으로 원인을 찾아 나서는 프로세스가 필요하다는 값비싼 교훈을 얻었다.


자주 묻는 질문(FAQ)

  • Q1. 그냥 Djongo 같은 라이브러리로 MongoDB만 계속 쓰면 안 되나요?
  • A1. 가능하지만, Djongo는 MongoDB를 관계형 DB인 '척'하게 만드는 '번역기'입니다. 복잡한 JOIN이나 트랜잭션 등 Django의 모든 ORM 기능을 완벽하게 지원하지 못하며, 예상치 못한 성능 문제나 오류를 만날 수 있습니다.
  • Q2. 사용자(auth) 앱은 기존 MongoDB에 두고, 새 앱만 PostgreSQL에 둘 수 없나요?
  • A2. 기술적으로는 가능하지만, 절대 권장하지 않습니다. 새 앱의 모델이 사용자와 관계(ForeignKey)를 맺을 수 없게 되어 Django의 장점을 모두 포기하게 됩니다. 관리자 페이지 연동도 매우 까다로워집니다.
  • Q3. 분명히 설정을 주석 처리했는데 왜 계속 objectId 오류가 발생하나요?
  • A3. 99% 확률로 Docker 컨테이너를 재시작하지 않았기 때문입니다. docker-compose down 후 docker-compose up -d --build로 컨테이너를 완전히 새로 시작하여 변경된 코드를 적용해야 합니다.
  • Q4. migrate와 migrate --database=postgres는 무슨 차이인가요?
  • A4. --database 플래그가 없으면 무조건 settings.py에 정의된 default 데이터베이스에 마이그레이션을 시도합니다. 따라서 다른 데이터베이스를 대상으로 할 때는 이 플래그가 필수입니다.
  • Q5. PostgreSQL이 MongoDB보다 무조건 더 좋은 데이터베이스인가요?
  • A5. 아닙니다. 데이터의 관계와 무결성이 중요하면 PostgreSQL, 유연하고 비정형적인 데이터를 빠르게 읽고 쓰는 것이 중요하면 MongoDB가 더 나은 선택일 수 있습니다. 목적에 맞는 도구를 사용하는 것이 중요합니다.
  • Q6. 기존 MongoDB의 사용자 데이터를 PostgreSQL로 옮기려면 어떻게 해야 하나요?
  • A6. Django의 **'관리자 명령어(Management Command)'**를 직접 만들어 옮기는 것이 가장 정석적인 방법입니다. MongoDB에서 데이터를 읽어와 PostgreSQL 모델 객체로 변환한 뒤, save(using='postgres')를 호출하여 저장하는 스크립트를 작성하면 됩니다.
  • Q7. 차라리 FastAPI로 새로 만드는 게 낫지 않을까요?
  • A7. 만약 만들려는 기능이 기존 Django 프로젝트와 완전히 독립된 API 서비스라면, FastAPI가 더 빠르고 좋은 선택일 수 있습니다. 하지만 기존 데이터와 긴밀한 연동이 필요하다면, Django 내에서 해결하는 것이 더 효율적입니다.


Django 멀티 DB: 실전 운영 팁 & 주의사항

  • [팁 1] 백업은 두 배로: 이제 mongodump와 pg_dump를 이용해 두 개의 데이터베이스를 각각 개별적으로 백업해야 합니다. 백업 스크립트와 복원 절차를 반드시 각각 테스트하고 문서화해두세요.
  • [팁 2] 모든 민감 정보는 환경 변수로: 데이터베이스 접속 정보(사용자, 비밀번호, 호스트)를 절대로 settings.py에 하드코딩하지 마세요. .env 파일과 python-decouple 같은 라이브러리를 사용해 모든 민감 정보를 환경 변수로 관리해야 합니다.
  • [팁 3] 데이터 마이그레이션 스크립트는 멱등성(Idempotent)을 고려하라: MongoDB에서 PostgreSQL로 데이터를 옮기는 스크립트를 작성할 때, 스크립트가 여러 번 실행되어도 데이터가 중복으로 쌓이지 않도록 '멱등성'을 고려하여 작성해야 합니다. (예: 실행 전 대상 테이블의 데이터를 모두 지우거나, 고유 키를 기준으로 이미 존재하는 데이터는 건너뛰는 로직 추가)
  • [팁 4] 아키텍처 선택의 순간: 새로운 기능을 추가하기 전에 항상 질문하세요. "이 기능은 기존 시스템과 긴밀하게 얽힌 부분인가, 아니면 독립적인 서비스로 분리할 수 있는가?" 이 질문에 따라 Django에 기능을 추가할지, 별도의 마이크로서비스로 구축할지 결정하는 습관은 프로젝트를 장기적으로 건강하게 유지하는 데 큰 도움이 됩니다.

 

목차
목차를 불러오는 중...

댓글

Loading...

댓글 로딩 중...

구글 검색