본문 바로가기

Python/Frameworks.Libraries

Django ORM과 MSA(마이크로서비스 구조) 함께 이용하기, DB 하나를 여러 서버에서 사용하기.

머릿말

Django를 깊게 공부하게되면서, 과연 Django가 실제로 많이 쓰이는 Web Framework으로서 적절한 지 고민해보게 되었다. 결론은 생산성 자체는 좋지만, 서비스가 커짐에 따라 ( 즉 단순 개발용이 아니라 실 서비스급으로 성장해감에 따라 ) Django 의 장점이 다시금 단점이 되어가는 것은 아닌가 싶긴했다.

( ORM 이용하며 model 과 view의 호흡을 통한 빠른 개발과 생산성이 장점이었으나, 그것이 MSA 서비스를 구축하기엔 너무도 Model과의 연결성이 커서 자유롭지가 못함.)

 

간략한 기준은 이러했다.

  • MSA(Micro Service Architecture) 구조를 따르기 쉬운가?
  • 다른 Framework들과 연동하기 쉬운가?
  • 협업하기 쉬운가?

사실 다들 'MSA 구조를 따르기 쉬운가' 라는 내용에 대한 세부내용일 수도 있긴하지만, 개인적으로는 각자 독립적으로 개발할 수 있다는 점에서 MSA 구조를 상당히 좋아하고 제대로 구현해보고 싶은 구조이기도 했기 때문에 위와 같이 생각하였다.

참고로 이 글의 실습 및 예제는 같은 DB를 이용하는 다수의 서버를 동시에 띄워보기 입니다.

왜 Django ORM을 이용하면서 MSA 구조를 따르는 내용을 글까지 써?

"저기... 혹시 Django는 Monolithic을 위한 Framework인가요...?"

사실 MSA 는 하나의 아키텍쳐이므로 그에 맞게 설계하면 그만이지만, ORM 을 이용하는 Django의 특성상 그러기가 힘들다고 생각했다. 실제로 Google을 이용해 Stackoverflow나 Quora 등에서 서치를 해봐도 Django를 이용해 MSA 방식으로 서버를 구축하는 것에 대한 내용을 많이 찾아볼 수 없었다.

거의 없었다고 보면 된다

작성해본 stackoverflow 질문글 - How can I use one database with multiple django servers?

.

Django ORM 과 MSA를 병행하기 힘든 이유는 우선 Django Project는 자신이 사용할 DB Table을 자신의 프로젝트 안의 models.py 라는 파일 안에 model과 관련된 class 로서 정의하기 떄문이다.

  • 여러 Django 서버에서 같은 DB에 각각 같은 내용의 models.py를 이용하는 경우

    • 처음으로 migrate를 하는 서버 이외에는 migrate를 하면 한 DB를 이용할 경우 table already exists 와 같은 에러가 발생하게된다.

  • 여러 Django 서버에서 각각의 DB(여러개의 DB)에 각각 같은 내용의 models.py를 이용하는 경우

    • 애초에 다른 DB를 이용하기 때문에 에러는 안나지만, 각 DB가 따로따로 내용이 담기게 됨.. 말도 안되는 방법
  • 한 Django 서버에서 models.py를 이용해 Table을 만들고 다른 서버에서는 models.py를 작성하지 않고 이용하는 경우

    그럴꺼면 왜 Django 써...?

    • 애초에 어떠한 models.py가 없으면 그 서버는 Django의 장점인 ORM과 Model과 밀접하게 연관된 View들을 이용할 수가 없기 때문에 Django를 이용할 장점이 없어지는 셈

해결책 - 간단히

위의 목록들과 같은 다양한 난관들이 있기 때문에 Django ORM의 장점을 이용하면서 MSA 구조를 따르는 것은 쉽지 않았다. 하지만 드디어 떠오른 방안이 있었으니... 진작 알려주던가;;

  1. 각각의 Project에 models.py를 동일하게 정의한다.

  2. 각각의 Project가 동일한 DB를 이용하도록 settings.py 에서 세팅한다.

  3. 가장 먼저 migrate를 진행하는 프로젝트에서는
    python manage.py makemigrations python manage.py migrate 를 이용해 migrate 해준다.

  4. 이후 migrate를 진행하는 프로젝트에서는 migrate 에 --fake 인자를 주어 실행한다.

    왜..?

    ​ : makemigrations를 통해 변동사항을 적는 file은 생성하지만, migrate는 실제 첫 서버에서 진행했기 때문에, 진행한 척만 하는 것이다.

    python manage.py makemigrations python manage.py migrate --fake

해결책 - 자세히

위의 내용들을 자세히 따라해보며 알아보자.

프로젝트 시작

대충 이러한 구조로 프로젝트와 앱을 만들어보자

mkdir msa && cd msa

전체 서버 두개를 만들 것이고 그 프로젝트를 담아줄 msa라는 디렉토리를 만들자.

django-admin startproject djangomsa && django-admin startproject djangomsasub

djangomsadjangomsasub이라는 프로젝트를 만들어주자.

MSA 의 컨셉에 따라 djangomsa는 User를 관리하는 서버이고, djangomsasub은 Post를 관리하는 서버라고 예시를 들겠다.

cd djangomsa && django-admin startapp app

cd ../djangomsasub && django-admin startapp

각 프로젝트에 app이라는 django app을 만들어주자.

우선 djangomsa 프로젝트를 정의하고, djangomsasub은 복붙을 하시거나( settings.py는 복붙하면 안댐!) 수작업을 하셔서 서버 두개에서 같은 DB를 이용하는 방식으로 해보겠습니다.

프로젝트 설정

프로젝트의 urls.pyapp.urls를 포함시켜주고, app/url.py에서 views.index를 이용한다고 적어주세요 ( views.index는 나중에 정의하겠음)

이렇게 Student 라는 model을 정의해주시면, 다시 views.index를 정의해주겠습니다.

방금 만든 Student라는 모델을 이용하겠다는 것이죠.

djangomsa/app/templates/app/index.html을 만들어주겠습니다. ( 방금 index에서 전달받은 인자 이용할게요 )

그리고 setting.py에서 INSTALLED\_APPS 에app을 추가시고, DB설정을 해주세요, 저는 localhost의 mySQL을 이용하겠습니다.

그런 뒤에 djangomsasub도 동일하게 작업해주시고,

djangomsa 프로젝트를 python manage.py makemigrations && python manage.py migrate 해줍시다.

djangomsasub 프로젝트도 똑같이 python manage.py makemigrations && python manage.py migrate

에러가 뜰겁니다. 앞서 말씀드린대로 --fake 옵션을 줘야하기때문이죠. 아마 위와 같은 식의 에러가 날 겁니다.

당황하지 마시고 python manage.py migrate --fake를 진행해주세요.

그리고 난뒤 DB에 정보를 추가해봅시다.

python manage.py shell 을 이용해 python shell 창을 열어주시고 아래처럼 입력해주세요.

from app.models import Student
s=Student(name="Mr. Kim", age=19, hobby="Soccer")
s.save()
s=Student(name="Ms. Jeong", age=22, hobby="Cafe")
s.save()
s=Student(name="Mr. Park", age=19, hobby="Coding")
s.save()

그리고 djangomsa 프로젝트는 localhost의 8000번 포트를 이용해서 돌려줍니다

djangmsa 프로젝트는 localhost의 8001번 포트를 이용해줄게요.

이런식으로 서버가 두대이지만 동일한 DB의 데이터를 참조할 수가 있네요!

아쉬운 점

사실 꽤나 만족스러운 과정이긴하다. 하지만, 몇 가지 아쉬운 점은 존재한다

- django app의 이름이 같은 경우에만 가능하다.

Django ORM이 테이블을 생성할 때, 테이블 이름을 {{appName}}_{{modelsName}}과 같은 식으로 생성하기 떄문에, models.py 를 포함하는

그래서 전에도 django app을 한 app으로 구성하는 것에대한 외국 포스팅을 본 적도 있긴한데, 거기에 나의 뇌피셜을 추가하여 적어보자면, Django로 MSA를 구축하고 싶은 경우 models.py를 정의할 app은 하나의 app에 몰아 넣는 것은 어떨까 생각한다.

즉 기능별로 app을 만들고 그 기능에서 주가 되는 model을 각 앱의 models.py에 정의하는 것이 아니라, 작업이나 라우팅은 app별로 하되, models.py는 하나의 app에 몰아넣자는 것이다.

- models.py 한 번 바꾸면, 모든 MSA 에 참여되는 서버의 models.py를 바꾸어야한다.

대부분의 경우 critical하진 않지만, table already existno columns found 등의 에러는 서버 자체가 종료되는 critical issue이기 때문에 바로바로 모든 서버의 models.py를 바꿔주어야하는데,

요즘 CI/CD나 자동화와 관련된 내용을 몇 개 주어들은 게 있어서, 예를 들어 models.py 의 내용을 담고있는 url을 전달받으면, 그 url의 내용을 이용해 models.py를 동적으로 생성한다거나 뭐 그 외의 다양한 방법을 통해 models.py 를 자동화 하는 방법도 만들어보면 좋겠지만, 너무 복잡해져서 배보다 배꼽이 커질듯하긴하다.

마치며

간단한 예제지만, 프로그래밍을 시작하면서 처음으로 나름 신선한 생각이나, 인터넷 상에 널리 존재하지 않는 새로운 부분에 대한 정보를 적어본 것 같다. 정확하고 가장 모범적인 방법은 아닐 수 있지만, 'ORM을 이용하는 한 Django는 Micro Service 답게 작동할 수는 없는 걸까' 라는 생각에 대해 적어보았다.

 

 

혹시 더 좋은 방법이 떠오르신 분들은 댓글 남겨주세요~~