티스토리 뷰

SW 개발

MongoDB, 기본 개념 및 사용법 정리

지단로보트 2021. 4. 27. 22:29

개요

  • MongoDB는 수년간 대표적인 NoSQL 제품으로 자리 잡았다. 특히, 전통적인 RDBMS 대비 우월한 샤드 및 스케일 아웃 능력으로 대량 트래픽, 대량 데이터가 발생하는 모던 웹 시대에 걸맞는 저장소로 널리 쓰이고 있다.

설치 및 운영

  • MongoDB를 개발 및 테스트 목적으로 활용한다면 로컬 내 가상머신이나 AWS EC2와 같은 클라우드 환경에 직접 설치하는 것으로 충분하다. 설치 방법은 본 블로그의 이 글을 참고한다.
  • 실제 운영 목적이라면 이야기가 달라진다. MongoDB는 관리 측면에서 굉장한 전문성과 노력이 필요하다. 제작사가 직접 제공하는 MongoDB Atlas 유료 클라우드 서비스 이용을 추천한다. 데이터 증가에 따른 스케일 아웃 같은 까다롭고 어려운 관리 이슈를 대부분 자동으로 수행해주며, 매우 편리한 브라우저 기반의 관리 UI를 제공한다. 특히 2019년 6월부터 MongoDB Atlas Full-Text Search 서비스를 개시하였는데, MongoDB 생태계에서, 복잡한 백엔드 아키텍쳐에 대한 고민 없이 순수히 풀텍스트 검색 자체에 집중할 수 있어 강력히 추천한다. [관련 링크]

클라이언트 접속

  • MongoDB에 접속하는 가장 간단한 방법은 로컬 또는 원격 쉘에서 mongo 명령어를 실행하는 것이다. Windows 10에서 MongoDB Shell을 설치하고 실행하는 방법은 아래와 같다.
# MongoDB Shell 설치
$ choco install mongodb-shell -y

# mongosh로 원격지 데이터베이스 연결
$ mongosh "{uri}" --username "{username}" --password '{password}'
  • 평소에는 UI 기반 클라이언트가 확실히 쉘보다 편리하다. MongoDB Compass 또는 NoSQLBooster를 추천한다. [설치 링크]

데이터베이스

  • 데이터베이스는 MongoDB에서 가장 큰 데이터 단위이다. 하나의 MongoDB 노드(또는 클러스터)는 복수개의 데이터베이스로 구성된다.
### 현재 존재하는 데이터베이스 목록을 출력한다.
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

### 현재 사용 중인 데이터베이스를 출력한다.
> db
test

### 사용할 데이터베이스를 선택한다.
### 존재하지 않는 데이터베이스일 경우 새로 생성한다.
> use config
  • use 데이터베이스명 명령으로 사용할(접근할) 데이터베이스를 선택할 수 있다. 재미있는 점은, 현재 존재하지 않는 데이터베이스를 선택할 수 있다는 것이다.(즉, 별도의 데이터베이스 생성 명령 없이 암묵적으로 새 데이터베이스를 생성하는 것이다.) 해당 데이터베이스는 show dbs 명령으로 나타나지 않다가, 도큐먼트를 최초 생성하면 나타나게 된다.
### 현재 데이터베이스의 사용 현황을 bytes 단위로 조회한다.
> db.stats()
  • db.stats() 명령을 실행하면 현재 데이터베이스 사용 현황을 상세하게 확인할 수 있다.

컬렉션

### 현재 데이터베이스에 저장된 컬렉션 목록을 출력한다.
> show tables
> show collections
system.sessions
  • 데이터베이스는 복수개의 컬렉션의 집합으로 구성된다. show tables 또는 show collections 명령으로 현재 데이터베이스 저장된 컬렉션 목록을 확인할 수 있다.

도큐먼트

### system.sessions 컬렉션의 도큐먼트 목록을 출력한다.
> db.system.sessions.count()
> db.system.sessions.find()
{ "_id" : { "id" : UUID("8197a34f-310d-4132-b31e-3acf61058e3f"), "uid" : BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=") }, "lastUse" : ISODate("2019-08-20T15:49:29.589Z") }

### system.sessions 컬렉션의 도큐먼트 목록을 보기 예쁘게 출력한다.
> db.system.sessions.find().pretty()
{
        "_id" : {
                "id" : UUID("8197a34f-310d-4132-b31e-3acf61058e3f"),
                "uid" : BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=")
        },
        "lastUse" : ISODate("2019-08-20T15:49:29.589Z")
}

인덱스

  • 전통적인 RDBMS와 마찬가지로 MongoDB 또한 퍼포먼스를 위해 자주 조회되는 필드에 대한 적절한 인덱스 생성이 필수적이다. MongoDB는 기본적으로 PK 역할을 수행하는 _id 필드에 대해 자동으로 인덱스를 생성한다.
### someCollection 컬렉션에 생성되어 있는 인덱스 목록을 조회한다.
> db.someCollection.getIndexes()

### someCollection 컬렉션의 someField 필드에 대해 인덱스를 블록킹 방식으로 생성한다.
### 명령 실행 후 인덱스 생성이 완료될 때까지 해당 컬렉션에 대한 모든 CRUD는 블록킹 된다.
> db.someCollection.createIndex({someField:1})

### someCollection 필드에 대해 인덱스를 논블록킹 방식으로 생성한다.
### 명령 실행 후 인덱스 생성이 진행 중이더라도 해당 컬렉션에 대한 모든 CRUD가 가능하다.
> db.someCollection.createIndex({someField:1}, {background:1})

문자열 필드의 인덱스 설계 전략

  • String 타입의 필드 값에 대해 조건 조회를 할 경우, MongoDB$regex 오퍼레이터를 사용하여 정규식으로 해당 조건과 일치하는 도큐먼트를 조회한다. 최적의 조회 성능을 위해 아래 사항을 숙지해야 한다.
1. String 타입 필드에 인덱스가 생성되어 있지 않으면 대상 컬렉션에 풀스캔이 발생한다.
2. 인덱스가 생성되어 있을 경우, 일치 조건(eq = /keyword/)은 인덱스를 사용한다.
3. 인덱스가 생성되어 있을 경우, 접두어 조건(startsWith = /^keyword/) 또한 인덱스를 사용한다.
4. 인덱스가 생성되어 있더라도, 접미어 조건(startsWith = /keyword$/)은 인덱스를 사용하지 않는다.
5. 인덱스가 생성되어 있더라도, 포함 조건(contains = /.*keyword.*/)은 인덱스를 사용하지 않는다.
  • 접미어 조건(endsWith = /keyword$/)은 위에 정리했듯이 인덱스를 사용하지 않아 컬렉션에 풀스캔이 발생한다. 방법이 없는 것은 아니다. 접미어에도 인덱스를 사용하고 싶다면, 해당 필드의 문자 순서를 거꾸로 뒤집은 필드를 생성하고 인덱스를 생성하면 된다.
  • 풀텍스트 검색(FTS)을 원한다면 text 인덱스를 생성하면 된다. 유의할 점은 현재 공식적으로 영어권의 문자열만 FTS를 지원하기 때문에 CJK 계열의 한글 문자열의 경우 형태소 분석이 되지 않아 의도한대로 작동하지 않을 수 있다. 대안으로서의 방법은, 애플리케이션에서 자체적인 한글 형태소 분석기를 사용하여 해당 필드 값을 명사 단위로 쪼갠 후 중복을 제거한 배열 필드를 생성하고 인덱스를 생성하면 된다. (내 경우, 오픈 소스 한글 형태소 분석기인 KOMORAN을 사용했다. [관련 링크])
  • Percona MongoDB를 직접 설치하여 구축한 경우, text 인덱스 생성시 기본 언어로 ngram을 지원하여 CJK 계열의 FTS가 가능하다. [관련 링크]
  • 대부분의 회사가 운영 레벨에서 사용하는 서버리스 매니지드 형태의 MongoDB Atlas에서는 Atlas Search라고 불리우는 Apahce Lucene 기반의 독자적인 풀텍스트 검색을 지원한다. 한글 형태소 분석기로 Nori를 사용하여 한글 검색 또한 지원한다. [관련 링크1] [관련 링크2]

MongoDB Database Tools

  • MongoDB Database Toolsmongodump, mongorestore, bsondump, mongoimport, mongoexport, mongostat, mongotop, monofiles와 같은 공식 명령어를 제공하는 패키지이다. Windows 10, Amazon Linux 2, CentOS 7 등 대부분의 운영체제에서 설치가 가능하다.
  • Windows 10에서 MongoDB Database Tools를 설치하는 방법은 아래와 같다. (사전에 choco 패키지 관리자 설치가 요구된다. [관련 링크])
$ choco install mongodb-database-tools -y
  • Amazon Linux 2 또는 CentOS 7에서 MongoDB Database Tools를 설치하는 방법은 아래와 같다.
$ sudo nano /etc/yum.repos.d/mongodb-org-4.4.repo
[mongodb-org-4.4]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.4.asc

$ sudo yum install -y mongodb-org-tools

MongoDB 원격지간 직접 복사

  • mongodumpmongorestore 명령어를 이용하면 원격지 데이터베이스 간의 직접 복사가 가능하다.
$ mongodump --uri={source-uri} --username {source-username} --password '{source-password}' --gzip --archive | mongorestore --uri={destination-uri} --username {destination-username} --password '{destination-password}' --nsFrom="{source-db-name}.*" --nsTo="{destination-db-name}.*" --gzip --archive --numParallelCollections=1 --numInsertionWorkersPerCollection=1
  • 원격지간 직접 복사는 한 번에 대량의 바이너리 데이터가 고속으로 복사되므로, 충분한 크기의 물리 메모리가 확보되어야 한다. (명령어를 실행하는 경유지 역시 마찬가지로 물리 메모리가 확보되어야 한다.) 물리 메모리가 부족할 경우 실행시 OOM 오류가 발생한다.
  • --uri 옵션은 mongodb+srv//, mongodb:// 문자열 모두 입력이 가능하다. mongodb+srv// 문자열에 username, pasword가 포함된 경우에는 --username, --password 옵션을 생략할 수 있다.
  • --numParallelCollections 옵션은 한 번에 병렬로 복원할 컬렉션 개수를 지정할 수 있다. 너무 큰 대량의 데이터 전송시 운영체제의 ulimit 제한에 걸릴 수 있기 때문에 부하를 의도적으로 줄일 때 사용하면 유용하다. (기본값: 4)
  • --numInsertionWorkersPerCollection 옵션은 복원할 컬렉션당 병렬로 실행할 워커의 개수를 지정할 수 있다. 위 옵션과 동일한 의도로 사용할 수 있다. (기본값: 1)

참고 글

댓글
댓글쓰기 폼