지난 1년간 몽고DB를 실무에서 처음 접하면서 여러 가지 작업을 했다. 뭔가 명확한 정보를 전달한다기보다는 경험과 트러블슈팅을 기록한다는 느낌으로 끄적여본다.
끄적 1, 몽고DB는 NoSQL이다.
몽고DB는 NoSQL이라고 불리는 제품 중에서 현재 가장 유명하고 범용적이다. 전통적인 RDB와 다르게 스키마 없이(Schema-Less) 사용하는 것이 가능하고 RDB의 단점 중 하나인 확장성(Scalability)을 적극적으로 지원한다. 여러 개의 노드로 구성된 클러스터에 데이터를 분산해서 저장하는 방식인 Sharded Cluster이 그것이다.
끄적 2, 몽고DB 관련 도구는 Compass를 추천한다.
터미널로 직접 접근해서 사용하는 것을 좋아하는 분들도 계시겠지만 나는 GUI 환경을 지원하는 도구를 사용하는 것을 좋아한다. 몽고DB GUI 도구도 선택지가 몇 가지 있다. IntelliJ Ulitmate 버전에서 지원하는 DB 플러그인이나 DataGrip에서 몽고DB를 지원한다. 개발 IDE에서 화면 전환 없이 사용할 수 있다는 장점이 있다. 다만 RDB와 비교했을 때 상대적으로 최근에 지원을 했기 때문에 아직 여러 가지로 개선되었으면 좋겠는 부분이 있다. NoSQL Booster라는 도구도 있는데 개인적으로 GUI가 맘에 들고 특히 유료 버전은 굉장히 강력한 기능을 제공한다. 하지만 대부분의 상황에서 가장 좋은 선택지는 Compass라고 생각한다. Compass는 몽고DB에서 공식적으로 개발 & 운영하고 있는 GUI 도구다. 우리가 DB 도구에 기대할 수 있는 대부분의 기능을 깔끔한 GUI와 함께 제공한다. 무료라는 점도 포인트지만, 개인적으로 내가 가장 좋아하는 부분은 꾸준히 업데이트가 되고 있다는 것이다. 게다가 요즘 추세에 맞게 AI 프롬프트 기능도 있다. SQL과 비교했을 때 몽고DB의 쿼리는 복잡해지면 상대적으로 장황해지고 어려운데(이건 아직 내가 익숙하지 않아서 그럴 가능성도 있지만...) 이럴 때 유용한 기능인 것 같다.
끄적 3, 몽고DB는 CDC를 지원한다.
CDC(Change Data Capture)라는 기술이 있다. 말 그대로 데이터의 변경을 감지하고 잡아내는 것인데 몽고DB는 MongoDB Kafka Connector로 CDC를 공식적으로 지원한다. 이 기술을 사용하면 몽고DB의 특정 컬렉션의 특정 도큐먼트에 무언가의 변경이 가해지면 이 정보를 카프카 토픽을 통해 produce, consume 할 수 있다. 신규 도큐먼트의 추가(Insert), 기존 도큐먼트의 변경(Update), 삭제(Delete) 뿐만 아니라 컬렉션의 삭제(Drop) 등의 이벤트가 발생하면 이 이벤트 정보를 카프카 토픽으로 흘려보내준다. 이런 특징을 활용해 실무에선 몽고DB의 데이터를 어딘가에 실시간으로 동기화할 때 주로 사용하곤 한다.
끄적 4, 몽고DB는 가능하면 JOIN해서 쓰지 말자
몽고DB도 컬렉션 간의 JOIN 연산이 가능하다. 하지만 가능하면 하지 않는 것이 좋고, 하지 않게 설계해서 사용하는 것이 좋다. 물론 조회하는 데이터의 크기가 작고 복잡하지 않다면 괜찮다. 하지만 RDB에서 여러 개의 테이블을 엮고 조건을 걸어서 조회하는, 흔히 말하는 한 방 쿼리를 쓰는 것은 지양해야 한다. 비교적 큰 데이터를 대상으로 컬렉션 N개를 JOIN해서 한 번에 조회하는 것보다 N번 호출해서 애플리케이션 레벨에서 엮는 것이 메모리 및 응답 속도 관점에서 훨씬 좋은 상황을 경험했다. 물론 이것은 조건에 따라서 다른 것이니 모든 상황에서 정답은 아니지만, 몽고DB가 JOIN에 약하다는 말이 괜히 있는 건 아닌 것 같다.
끄적 5, 몽고DB도 스키마 있이 사용하면 좋다.
이건 개인적인 의견인데 몽고DB를 스키마 있이 사용하는 것이 좋다고 생각한다. 몽고 DB는 내가 특정 도큐먼트에 어떤 키를 추가해도, 기존에 있던 키를 삭제하거나 키에 대한 값의 타입을 바꿔도 동작한다. 그런데 이 자유로움이 실무 운영 환경에선 굉장히 많은 버그와 생산성 저하의 원인이 된다. 정확히는 이런 컬렉션을 사용하는 쪽에서는 굉장히 골치가 아프다. 스키마가 없는 몽고DB는 컬렉션의 특정 도큐먼트를 보더라도 그 도큐먼트가 스키마라고 생각할 수 없다. 내가 본 도큐먼트의 키 구성과 다른 도큐먼트의 키 구성이 다를 수 있고, 심지어 키 개수와 타입마저 달라도 된다. 이런 컬렉션은 사용하는 입장에서 굉장히 까다롭다. 만일 이런 컬렉션의 도큐먼트를 담을 수 있는 클래스를 작성하려면 어떻게 해야 할까?
- 쿼리로 컬렉션의 모든 도큐먼트가 가진 키 목록을 조회한다.
- 조회한 키 목록을 필드로 하는 클래스를 만든다.
- 그리고 모든 필드는 Nullable 하게 설계한다, 모든 도큐먼트가 해당 키를 가지고 있지 않을 수 있기 때문에.
예를 들어 코틀린으로 클래스를 설계한다면 모든 프로퍼티가 Nullable 한 data class를 하나 만들게 될 것이다. 이 클래스가 주는 정보는 혼란스럽다. 모든 프로퍼티에 대해서 (있거나, 없거나)니깐 이 클래스는 "이 컬렉션에서 도큐먼트를 조회하면 이런 이름을 가진 프로퍼티가 있을 수도 있고 없을 수도 있습니다"라는 정보를 준다. 반면에 RDB는 테이블이 스키마 그 자체다. 테이블에 DESC 명령어 하나로 테이블 스펙을 확인할 수 있다. RDB 테이블의 데이터를 담을 클래스를 만들어보면 아주 명확하다. 클래스 자체가 DB 테이블 스펙이고 이것 만으로도 개발자에게 의미 있는 정보를 전달한다.
물론 외부에서 운영하는 컬렉션을 사용하는 입장이라면 여러 가지 이해관계와 복잡한 사정으로 사용하는 쪽에서 이런 것들을 잘 발라내야 할 수 있다. 하지만 직접 운영하는 컬렉션이라면 억지로 스키마를 유연하게 만들지 말자. 실제로 특정 도큐먼트에서만 사용하는 키를 스키마를 맞추기 위해 모든 도큐먼트에 일괄 추가하는 것이 거부감이 있을 수 있다는 것은 이해한다. 직접 몽고DB 클러스터와 컬렉션을 운영하지 않고 사용만 하는 입장이기에 할 수 있는 생각일 수 있다고 생각한다. 실제로 유연한 스키마는 몇몇 상황에서 굉장히 유용하고 RDB가 선택할 수 없는 단순하고 쉬운 방법으로 문제를 해결할 수 있다. 하지만 그래도 가능하다면 조금 더 컬렉션(테이블) 설계에 공을 들여 스키마가 없지만 있게 사용한다면 좋을 것 같다.
'Programming' 카테고리의 다른 글
코틀린 하나의 파일에 클래스 하나만 사용하기 vs 여러 개 사용하기 (0) | 2025.01.19 |
---|---|
한 편으로 끝내기 - 제네릭과 변성(공변성, 반공변성) (0) | 2024.10.13 |
[2023 ver.] 서버 개발자 mac 장비 설정 (0) | 2023.07.22 |
성능 테스트 (0) | 2022.06.01 |
[springdoc-openapi 전환기 01] Spring Boot 2.6.x 버전에서 springfox와의 충돌 관련 이슈 & 임시 해결책 (0) | 2022.03.20 |