MongoDB는 대표적인 NoSQL(비관계형) 데이터베이스로, JSON 형태의 유연한 문서(Document) 구조를 기반으로 데이터를 저장한다. 데이터는 BSON(Binary JSON) 형식의 문서로 저장되며, 컬렉션(Collection) 단위로 관리된다.
관계형 데이터베이스(RDBMS)처럼 고정된 스키마가 없어 구조 변경이 자유롭기 때문에 빠른 개발에 유리하다. 이러한 특성 덕분에 구조가 자주 변하거나 비정형 데이터가 많은 애플리케이션에 적합하다.
MongoDB의 장점
유연한 데이터 모델: 테이블과 스키마 없이 문서 구조를 자유롭게 정의할 수 있어 빠른 개발이 가능하다.
수평 확장성: Sharding 기능을 통해 대규모 데이터를 분산 저장할 수 있다.
JSON 기반의 쉬운 사용법: JSON 유사 문법으로 쿼리를 작성하기 때문에 진입 장벽이 낮다.
복제와 고가용성: Replica Set 기능으로 장애 복구와 무중단 서비스를 구현할 수 있다.
MongoDB의 단점
트랜잭션 제약: RDBMS만큼 복잡한 트랜잭션 처리에는 부담이 있다.
복잡한 조인에 약함: 다중 컬렉션 조인 처리에 약하다.
높은 메모리 의존성: 인덱스와 자주 접근하는 데이터(핫 데이터)를 메모리에 올려두는 구조라 메모리 부족 시 성능 저하가 발생한다.
MongoDB의 클러스터 구조
클러스터는 여러 서버(노드)를 하나의 논리적 데이터베이스로 구성해 데이터를 분산 저장하거나 복제하는 방식이다. 이를 통해 부하 분산, 데이터 복제, 장애 대응이 가능하다. 확장성과 안정성을 위한 데이터베이스 구조로 단일 서버 한계를 극복해야 하는 서비스에서 주로 사용된다.
MongoDB에서 구성 가능한 클러스터는 Replica Set과 Sharded Cluster 두 가지가 있다.
systemLog: # 로그 설정 verbosity:0 # 기본 로그 레벨 (0 = 최소 로그) destination: file # 로그를 파일로 출력 logAppend:true # 로그를 덧붙이는 방식으로 저장 path: /var/log/mongodb/mongod.log # 로그 파일 경로 logRotate: reopen # 로그 로테이션 시 SIGHUP 신호 처리storage: # 데이터 저장 경로 dbPath: /var/lib/mongo # 데이터 파일 저장 경로 directoryPerDB:true # DB별로 디렉토리 분리 저장 wiredTiger: engineConfig: cacheSizeGB:4 # WiredTiger 캐시 크기 설정 (서버 메모리에 맞게 조정)processManagement: # 프로세스 실행 방식 fork:true # 백그라운드 실행 pidFilePath: /var/run/mongodb/mongod.pid # PID 파일 경로 timeZoneInfo: /usr/share/zoneinfo # 타임존 정보 위치 (Linux 표준 경로)net: # 네트워크 설정 port:27017 # MongoDB 서비스 포트 bindIp:0.0.0.0 # 로컬 및 내부 IP에서만 접근 허용 (보안상 권장) unixDomainSocket: pathPrefix: /tmp/mongodb # 유닉스 도메인 소켓 경로security: # 보안 설정 keyFile: /etc/mongodb/mongod.key # 클러스터 인증용 키 파일 (Replica Set 필수) clusterAuthMode: keyFile # 키 파일 기반 인증 authorization: enabled # 사용자 인증 활성화 (role-based access control)operationProfiling: # 성능 모니터링 mode: slowOp # 느린 쿼리 기록 활성화 slowOpThresholdMs:1000 # 1초 이상 걸린 작업을 느린 쿼리로 간주replication: # 복제 설정 (Replica Set) replSetName:"game-rs00" # Replica Set 이름 oplogSizeMB:10240 # Oplog 크기 (10GB) – 쓰기 성능 및 복제 지연 최소화# 기타 (비활성화된 옵션 예시 – 필요시 활성화)# setParameter:# enableFlowControl:false# internalQueryMaxBlockingSortMemoryUsageBytes:1073741824 # $sort 연산이 메모리 기반으로 수행될 때, 최대 사용할 수 있는 메모리 크기 제한 (기본값 100MB)# sharding: # 샤딩이 필요할 경우 사용
운영 중 주요 설정 및 대응 사례
MongoDB Replica Set 구조(P-S-S) 운영 과정에서 여러 상황에 맞춰 대응해온 경험을 바탕으로 데이터베이스 운영 노하우를 쌓아가고 있다. 이번에는 운영 중 활용된 주요 설정과 대응 사례들을 정리해본다.
1. readPreference로 조회 분산
서비스 초기 일부 조회 요청이 특정 노드에 집중되며 응답 지연이 발생했다. 이를 완화하기 위해 MongoDB Replica Set에서 읽기 요청을 Secondary로 분산하는 설정을 적용했다.
# 이 옵션은 가능한 경우 Secondary에서 우선적으로 조회를 수행하며 Secondary가 사용 불가능할 경우에만 Primary에서 읽기를 수행한다.
2. 무중단 Primary 변경
운영중 노드를 점검하거나 스펙을 상향, 축소할 필요가 있을 때, Replica Set의 priority 설정을 활용해 Primary 역할을 무중단으로 전환했다.
Primary 전환 절차 (무중단 방식)
전환 대상 Secondary priority 상향
Replica Set이 자동으로 priority가 높은 Secondary를 Primary로 선출
기존 Primary 점검/작업 수행
작업 완료 후 우선순위 원복해 Primary 복귀
# 가중치 변경 방법 : Replica Set 설정 확인 후 진행 (rs.conf() 명령어로 확인 가능)
1) 현재 Replica Set 설정 가져오기mongosh> var cfg = rs.conf(); 2) 변경하려는 멤버(_id:1)의 priority 수정mongosh> cfg.members[1].priority = 3; 3) 변경된 설정으로 rs.reconfig() 적용mongosh> rs.reconfig(cfg); 4) mongo2 서버가 primary로 변경된것 확인 mongosh> rs.status() 5) mongo1 서버 스펙 변경
# 아래 작업은 스펙 변경 작업 후 원복하는 작업 6) 현재 Replica Set 설정 가져오기mongosh> var cfg = rs.conf();
MongoDB는 로그 레벨을 최소화하더라도 운영 중 발생하는 인증, 연결, 쿼리 실패, 복제 이벤트 등의 로그는 기본적으로 기록한다. 특히 Replica Set 환경이나 접속 빈도가 높은 서비스에서는 하루에 수백 MB 이상의 로그가 생성될 수 있어, 로그 파일이 적절히 관리되지 않으면 디스크 공간을 빠르게 소모하게 된다. 때문에 운영 환경에서는 MongoDB의 시스템 로그(mongod.log)를 주기적으로 순환하고, 오래된 로그는 압축하여 보관하거나 제거하는 정책이 필수적이다. logrotate를 활용해 하루 단위 회전, 30일 보관, gzip 압축 정책을 적용했다.
/etc/logrotate.d/mongodb {daily # 하루에 한 번 로그 회전rotate 30 # 최근 30일치 로그 보관compress # 오래된 로그는 gzip 압축delaycompress # 회전 다음날부터 압축 적용missingok # 로그 파일 없을 경우 무시notifempty # 파일이 비어있으면 회전하지 않음create 0640 mongod mongod # 새 로그 파일 생성 시 권한 및 소유자 지정sharedscriptspostrotate/bin/kill -SIGUSR1$(pgrep mongod) 2>> /var/log/mongodb/logrotate-error.logendscript}
4. oplog크기 설정
MongoDB의 oplog(Operation Log)는 Replica Set 환경에서 데이터 복제를 담당하는 핵심 구성 요소다. 서비스 오픈 직후 예상보다 많은 쿼리 요청이 발생하면서 oplog 가용 범위가 수 초 단위로 줄어드는 상황이 발생했다. 이 과정에서 Secondary 노드 한 대가 동기화 지연으로 Replica Set에서 제외됐고, oplog 누락으로 인해 자동 복귀하지 못하는 이슈가 발생했다.
이 문제는 다음과 같은 방법으로 해결했다.
# oplog 사이즈를 확대 # 해당 Secondary 노드를 초기화(데이터 파일 삭제)하여 복제 재등록 처리
이후 트래픽이 안정되면서 oplog 여유 구간이 크게 늘어났지만, 이미 설정된 oplog 크기를 줄이려면 다시 데이터를 초기화해야 했기에 축소는 포기할 수밖에 없었다.
결론적으로 oplog 크기는 늘릴 수는 있어도 줄이기는 어렵기 때문에, 초기에 충분한 여유를 두고 신중하게 설정하는 것이 운영 안정성을 확보하는 핵심이다.
마치며
MongoDB는 NoSQL 중에서도 높은 유연성과 확장성을 제공하며, 실시간성과 대규모 데이터를 동시에 요구하는 게임 서비스 환경에 적합한 데이터베이스다. 앞으로도 더욱 안정적이고 유연한 서비스 환경을 구축하기 위해 MongoDB의 기능을 지속적으로 탐색하고 개선해 나갈 예정이다.