인프런 커뮤니티 질문&답변

alpharegulus님의 프로필 이미지

작성한 질문수

mongoDB 기초부터 실무까지(feat. Node.js)

mongoDB의 참조무결성 제약

작성

·

633

0

안녕하세요, 좋은 강의를 촬영해주셔서 감사히 잘 듣고 있습니다.
 
다름이 아니라, 강의를 듣고 난 이후 실제 어플리케이션 API 서버를 작성하다가 궁금한 점이 생겨서 질문 드리게 되었습니다.
 
일반적인 SQL DB를 이용했을 경우에는 스키마에 참조무결성을 지정하고 cascade 등 관련 제약을 지정하면 dbms 단에서 이들이 구현되는 것에 비해서, MongoDB를 이용해서 ODM인 mongoose로 스키마를 형성하는 경우 참조 무결성 제약을 만드는 게 매우 어렵다는 것을 느끼게 되었습니다.
 
데이터베이스 모델링 자체를 NoSQL 스럽게 진행하여 최대한 nested document 혹은 subdocument를 이용해서 one-document ACID를 구현하고자 하는 철학은 잘 이해되고 그렇게 최대한 진행하였는데요..
 
개체 자체의 본질적인 속성으로 인하여 collection 간의 ref로만으로 처리할 수밖에 없을 경우에는 이를 활용하였는데, 참조무결성을 구현하기 위해서는 여러 번의 쿼리가 필요한 것을 알게 되었습니다. 여기에서 질문이 좀 있게 되었습니다.

#1. 참조무결성 구현을 위하여 multi-document 간의 ACID를 지키기 위해서 transaction을 사용할 수밖에 없었는데, isolation 수준은 document level에서 진행되는 것일까요? 아니면 collection 자체에 쓰기금지까지 지정이 되는 것일까요?
 
#2. 몽고db 자체가 schemaless이기에 참조 무결성을 위한 지원이 없다는 것은 이해가 되는데, 그럼 실무에서 참조 무결성 제약이 필요한 경우에는 모두 ODM과 같은 tool을 이용하여 server단에서 구현하는 것이 최선일지요? 혹시 다른 더 좋은 방법이 있을지요?

#3. 저는 mongoose와 관련된 라이브러리 중 만족스러운 오픈소스 ref > id validator가 없어서 직접 구현해서 사용하고 있는데 혹시 좋은 tool이 있을지 궁금합니다.
(심지어 custom validator나 middleware을 이용해 구현할 때에는 순환참조의 문제가 발생할 수밖에 없는 듯하여 RESTful API 혹은 graphQL resolver 단계에서 구현하고 있습니다. 이렇게밖에 할 수 없는지 궁금합니다.)
 
다시 한 번 좋은 강의 촬영해주신 것에 매우 감사드립니다. 오늘도 좋은 하루 되셨으면 좋겠습니다. 감사드립니다.

답변 1

0

김시훈님의 프로필 이미지
김시훈
지식공유자

alpharegulus님 안녕하세요

좋은 질문입니다.

 

Mongo 같은 NoSQL 디비에서는 엄격한 스키마가 지원되지 않을뿐더러 참조무결성 또한 지원하지 않아요. 관계형처럼 엄격하진 않지만 백엔드에서 잡아주죠.

Mongoose로 생성한 스키마로도 사실 완전한 데이터 일관성을 보장할 수 없지요. MongoDB Compass 혹은 다른 클라이언트로 들어와서 다른 형태로 데이터를 수정할 수 있겠죠. 그리고 같은 백엔드에서 Schema를 업데이트하고 배포하면 새로운 데이터는 변경되는 스키마에 맞게 수정되겠지만 과거 데이터는 기존 스키마로 그대로 유지되어서 일관성이 깨지게 되죠.

NoSQL에서의 디비란 복잡한 데이터 구조를 저장, 수정, 탐색을 빠르게 할 수 있도록 해주는 역할이에요. 데이터 일관성(스키마), 참조무결성 등 이런 부분들은 백엔드의 역할로 넘어가고요.

그래서 개발자 본인들이 책임지고 일관성을 유지해줘야 합니다. 스키마를 업데이트 했다면 스크립트를 돌려서 과거 데이터들도 업데이트 해줘야할거고요. 다른 외부 클라이언트가 데이터 수정을 못하도록 해야할거고요. 느슨한 일관성이라고 할 수도 있겠네요

 

그에 반면 관계형 디비에서는 참조무결성, 데이터 일관성까지 모두 디비가 담당을 하게 되버리죠. (프러덕션에서 데이터가 많이 축적된 테이블 구조를 수정한다면? 엄격한 일관성을 보장하는만큼 몇분에서 몇시간까지 디비 서버가 중단될 수도 있어요.)

 

그래서 사실 관계형 디비가 처음에 시작은 어렵지만(테이블 생성, foreign key 연결, cascade 설정, M:N관계를 위한 추가 테이블 등) 개발자한테는 훨씬 편한 데이터베이스에요. 다만 고객들이 불편함을 느낄 수 있겠죠.(스키마 변경 시 서버가 먹통이 되는 현상, 데이터가 많아지면 느려지는 현상들, 빠르게 스키마 개선을 못해서 개발 속도가 느려지는 현상)

 

몽고 같은 디비들은 초반에는 더 쉬워보이지만 프러덕션에서 신경써야할 부분들이 더 많아지죠. 그럼에도 불구하고 몽고 같은 디비가 많이 사용되는 이유는? 개발자가 조금 고생하더라도 유저경험을 살릴 수 있기 때문이에요.

 

만약 데이터 일관성, 참조무결성을 디비단에서 필수적으로 지원을 해야한다면 관계형 디비를 사용해야겠죠. 하지만 제 경험상 설계의 문제라고 봐요. 이커머스를 어떻게 몽고로 개발하냐라는 소리를 예전에 많이 들었는데 찾아보면 해외에서는 이커머스뿐만 아니라 다양한 대규모 서비스들을 몽고로 개발하고 있었어요. 저 또한 성공적으로 개발했었고요. 

 

그리고 몽고디비의 느슨한 혹은 점진적 일관성을 쉽게 관리할 수 있는 좋은 아키텍처가 있습니다. Event Driven Architecture(EDA)라고 보통 MSA개발할 때 많이 사용되요. 마이크로 서비스 간에 request/response형식으로 통신하는게 아니고 이벤트 생성/구독으로  비동기 통신을하게 됩니다. MSA로 전환을하게 되면 서비스마다 각자 독립된 디비를 사용하기 때문에 관계형 디비라고 하더라도 전체 서비스 관점에서 보면 엄격한 일관성, 참조 무결성이 불가능해져요. 그래서 eventual consistency 개념이 들어옵니다. EDA는 모놀리스에서도 충분이 사용 가능해요! 프론트엔드에서는 사실 EDA가 이미 대중화되어 있죠. global state management(mobx, redux, context, recoil)를 사용하는 아키텍처가 EDA와 매우 흡사합니다. EDA 사용 경험이 너무 좋아서 대중화를 원하는 사람 중 한명인데요. 보일러플레이트와 EDA를 정말 쉽게 빠르게 시작할 수 있도록 해주는 라이브러리를 하나 준비하고 있는데 궁금하시면 참고만 해보세요. 아직 업데이트 안된 부분들이 많아서 프러덕션에서 사용하기에는 무리가 있을거에요.(보일러플레이트와 특히 전반적으로 문서가 부족)

 

ref 관련해서는 워낙 유명한 기능이라 강의에서 소개했지만 전 GraphQL을 사용하고 있어서 ref를 사용하진 않아요. GraphQL에서 관계된 데이터는 어짜피 populate로 불러오지 않고 dataloader로 불러오고 있어서요.(사실상 populate랑 같은 기능).