6년? 8년? 전에 tokumx mongoDB 부터 사용했었는데,  mongodb java driver 소스를 몇 번 봤었습니다.

(그 당시에는 지금처럼 mongodb가 안정화? 되지 않은 부분도 많았습니다. db커넥션 유지관련 버그 등..)

 

mongodb java driver 소스 중에 인상 깊고, 이후  다른 시스템들의 pk설계할때 많이 참고한 부분이  objectId  부분입니다.(인스타그램의 id체계 참고와 함께)

 

지금도 가끔 필요한 경우 소스를 다시 보는데, 메모 목적으로 내용을 복사해둡니다.(기억력이 예전같지 않아요 ...;)

 


참고 링크:  https://www.mongodb.com/docs/manual/reference/bson-types/

 

ObjectIds are small, likely unique, fast to generate, and ordered. ObjectId values are 12 bytes in length, consisting of:

  • A 4-byte timestamp, representing the ObjectId's creation, measured in seconds since the Unix epoch.
  • A 5-byte random value generated once per process. This random value is unique to the machine and process.
  • A 3-byte incrementing counter, initialized to a random value.

For timestamp and counter values, the most significant bytes appear first in the byte sequence (big-endian). This is unlike other BSON values, where the least significant bytes appear first (little-endian).

If an integer value is used to create an ObjectId, the integer replaces the timestamp.

In MongoDB, each document stored in a collection requires a unique _id field that acts as a primary key. If an inserted document omits the _id field, the MongoDB driver automatically generates an ObjectId for the _id field.

2020년경에 tokumx-> mongo 3.4 -> mongo 4.2로 DB서버 버전업시 어플리케이션 수정을 위해 정리했던 내용입니다.

 - java드라이버의 호환성내용입니다.

 - API는 4.0.4버전을 사용했고, admin은 하위버전의 DB까지 지원해야해서 3.4.3버전을 사용했습니다.

 


당시 조건을 간단히 정리하자면 아래와 같습니다.

  1. 분당 1만건/100Mb 이상의 좀 큰 사이즈의 트래픽이 저장요청 API 어플리케이션으로 몽고DB에 저장됨
  2. mongoDB는 10여개 이상의 셋트(replica형태로)로 aws ec2에 설치해서 사용 중
    1. mongoDB가 자체 개선되기전부터 특정 기능(tokumx의 압축, 파티션 등)을 사용했어야해서 tokumx, mongo 3.4가 혼재되어 있었음
    2. 여러 이슈로 mongo 4.2로 버전업 필요한 상황
  3. 저장 API는 1개의 소스-> 1개의 DB만 커넥션
  4. admin시스템은 1개의 소스->N개의 DB커넥션

 

참고

 - https://docs.mongodb.com/drivers/java/sync/current/compatibility/

 

구)

 
 
 
  1. 인덱스 없을시 explain 결과
repl_set:PRIMARY> db.test_multikey_index.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "test_db.test_multikey_index"
        }
]
 
 
repl_set:PRIMARY> db.test_multikey_index.find({topic:'server-3'}).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test_db.test_multikey_index",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "topic" : {
                                "$eq" : "server-3"
                        }
                },
                "queryHash" : "28760B72",
                "planCacheKey" : "28760B72",
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "topic" : {
                                        "$eq" : "server-3"
                                }
                        },
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.2.8",
                "gitVersion" : "43d25964249164d76d5e04dd6cf38f6111e21f5f"
        },
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1596622293, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1596622293, 1)
}
 
 
 
 
 
 
  1. 인덱스 존재시 explain결과
repl_set:PRIMARY> db.test_multikey_index.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "test_db.test_multikey_index"
        },
        {
                "v" : 2,
                "key" : {
                        "topic" : 1
                },
                "name" : "topic_1",
                "ns" : "test_db.test_multikey_index"
        }
]
 
 
 
repl_set:PRIMARY> db.test_multikey_index.find({topic:'server-3'}).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test_db.test_multikey_index",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "topic" : {
                                "$eq" : "server-3"
                        }
                },
                "queryHash" : "28760B72",
                "planCacheKey" : "9C0A2855",
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "topic" : 1
                                },
                                "indexName" : "topic_1",
                                "isMultiKey" : true,
                                "multiKeyPaths" : {
                                        "topic" : [
                                                "topic"
                                        ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "topic" : [
                                                "[\"server-3\", \"server-3\"]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [ ]
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.2.8",
                "gitVersion" : "43d25964249164d76d5e04dd6cf38f6111e21f5f"
        },
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1596622053, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1596622053, 1)
}
 
 
 
  1. 참고 - 테스트용 프로그램
package com.biz.mongodb;
 
 
import com.mongodb.BasicDBObject;
import com.mongodb.Block;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import com.mongodb.connection.ClusterSettings;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
 
 
import java.util.*;
 
 
/**
* 멀티키 Index 테스트
*
* @author 엄승하
*/
@Slf4j
public class FindMultiKeyIndexSample {
 
 
   private static final String dbAddr = "192.168.56.1"; //로컬 vm에 mongodb 4.2를 설치함
   private static final String dbName = "test_db"; //db명
 
 
   private static String colNm = "test_multikey_index";
   private static String indexField = "topic"; //인덱스 필드
 
 
   private static final int testDataSize = 100_000; //테스트 데이터 생성 갯수
 
 
   private static MongoDatabase mongoDB;
 
 
   public static void main(String[] args) {
 
 
      List<ServerAddress> serverList = Arrays.asList(new ServerAddress(dbAddr, 27017));
      Block<ClusterSettings.Builder> clusterSettings = builder -> builder.hosts(serverList);
 
 
      MongoClient mongoClient = MongoClients.create(MongoClientSettings.builder().applyToClusterSettings(clusterSettings).build());
      mongoDB = mongoClient.getDatabase(dbName);
 
 
      //컬렉션 추가
      mongoDB.createCollection(colNm);
      mongoDB.getCollection(colNm).createIndex(new BasicDBObject(indexField, 1)); //인덱스 추가
 
 
      saveBulkData(colNm, testDataSize); //테스트 데이터 저장
 
 
      mongoClient.close(); //DB커넥션 반환
 
 
      System.out.println("\n\n === 프로그램 종료 ===");
   }
 
 
   /**
    * bulk로 데이터 저장
    *
    * @param colNm 저장할 컬렉션명
    * @param dataSize 저장할 데이터 갯수
    */
   public static void saveBulkData(String colNm, int dataSize) {
 
 
      Date now = new Date();
      List<Document> docs = new ArrayList<>(dataSize);
 
 
      List<String> case1 = new ArrayList<>();
      case1.add("server-1");
      case1.add("server-2");
 
 
      List<String> case2 = new ArrayList<>();
      case2.add("server-2");
      case2.add("server-3");
 
 
      for (int i = 1; i <= dataSize; i++) {
 
 
         Document doc = new Document();
         doc.append("i", i);
         doc.append("uuid", UUID.randomUUID().toString());
         if (i % 2 == 0) { // 2가지의 경우로 데이터 저장
            doc.append("topic", case1);
         } else {
            doc.append("topic", case2);
         }
 
 
         doc.append("doc_make_date", now);
         docs.add(doc);
      }
 
 
      mongoDB.getCollection(colNm).insertMany(docs); //N개 insert
 
 
      //Thread.sleep(10); //부하분산 목적
   }
}
 
  1. 목적
    1. mongodb Zstandard(이하 zstd)압축 알고리즘 효과 및 압축옵션 적용시 find 성능에 문제가 없는지 확인
  2. 환경
    1. mongodb 4.2 서버
    2. java 드라이버 4.0.4
  3. 방법
    1. 압축 옵션 적용/미 적용시 압축율과 find 성능 확인
  4. 테스트 결과
    1. 용량 절약에 효과가 있으며 find 성능 문제 없음
    2. 상세 내용은 하단 참고
 

 
[필요사항]
  1. 테스트용 java 프로그램(하단 참고)
 
mongodb 드라이버 maven dependency
<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver-core</artifactId>
    <version>4.0.4</version>   
</dependency>
 
 
테스트용 java 소스
package com.biz.mongodb;


import com.mongodb.BasicDBObject;
import com.mongodb.Block;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Indexes;
import com.mongodb.connection.ClusterSettings;
import org.bson.Document;


import java.util.*;


/**
* 몽고DB 서버의 압축 효율 테스트
*  - DB서버의 압축 옵션을 적용/ 미 적용 후 bulk 데이터 저장 후 find 성능 확인
*
* @author 엄승하
*/
public class MongodbNotCompressTest {


   private static final String dbAddr = "192.168.56.1"; //로컬 vm에 mongodb 4.2를 설치함
   private static final String dbName = "compress_test_db"; //db명


   private static final int bulkSaveDataSize = 1_000_000; //bulk 데이터 저장 갯수
   private static final String dummyTest = "Zstandard is a real-time compression algorithm, providing high compression ratios. It offers a very wide range of compression / speed trade-off, while being backed by a very fast decoder";


   private static MongoDatabase mongoDB;


   public static void main(String[] args) {


      MongoClient mongoClient = getNewMongoClient(dbAddr);
      mongoDB = mongoClient.getDatabase(dbName);


      final String colNm = "no_compress";
      //final String colNm = "compress"; //압축 테스트때 사용하는 컬렉션명


      mongoDB.getCollection(colNm).createIndex(Indexes.ascending("uuid")); //인덱스 추가


      long startSave = System.currentTimeMillis();


      //100만건을 insert해봄
      saveBulkData(colNm, bulkSaveDataSize);


      long duSaveMills = System.currentTimeMillis() - startSave;
      System.out.println(String.format("테스트 데이터 저장 소요시간: '%s'", duSaveMills));


      //1건을 추가로 insert 후 find 속도 확인
      final String addedUuid = "last-uuid";


      Document addLastDoc = new Document();
      addLastDoc.append("i", bulkSaveDataSize + 1);
      addLastDoc.append("uuid", addedUuid);
      addLastDoc.append("dummy_text", dummyTest);
      addLastDoc.append("doc_make_date", new Date());
      mongoDB.getCollection(colNm).insertOne(addLastDoc);


      findByUuid(colNm, addedUuid); //find


      mongoClient.close();
   }


   /**
    * UUID로 데이터 찾기
    *
    * @param colNm 컬렉션명
    * @param uuid 찾을 UUID
    */
   public static void findByUuid(String colNm, String uuid) {


      long startFind = System.currentTimeMillis();
      MongoCursor<Document> cur = mongoDB.getCollection(colNm).find(new BasicDBObject("uuid", uuid)).iterator(); //find
      while (cur.hasNext()) {


         Document doc = cur.next();
         System.out.println("\nfind결과:" + doc);
      }


      long duFindMills = System.currentTimeMillis() - startFind;
      System.out.println(String.format("\nfind 소요시간: '%s'", duFindMills));
   }


   /**
    * bulk로 데이터 저장
    *
    * @param colNm 저장할 컬렉션명
    * @param dataSize 저장할 데이터 갯수
    */
   public static void saveBulkData(String colNm, int dataSize) {


      Date now = new Date();
      List<Document> docs = new ArrayList<>(dataSize);


      for (int i = 1; i <= dataSize; i++) {


         Document doc = new Document();
         doc.append("i", i);
         doc.append("uuid", UUID.randomUUID().toString());
         doc.append("dummy_text", dummyTest);
         doc.append("doc_make_date", now);


         docs.add(doc);
      }


      mongoDB.getCollection(colNm).insertMany(docs); //N개 insert


      //Thread.sleep(10); //부하분산 목적
   }


   public static MongoClient getNewMongoClient(String dbAddr) {


      List<ServerAddress> serverList = Arrays.asList(new ServerAddress(dbAddr, 27017));
      Block<ClusterSettings.Builder> clusterSettings = builder -> builder.hosts(serverList);


      //mongo와 실제 커넥션 생성(mongo client생성)
      return MongoClients.create(MongoClientSettings.builder().applyToClusterSettings(clusterSettings).build());
   }


}
 
[결과]
  1. 압축 옵션 미 적용시
    1. 파일 사이즈
       
    2. 소요시간
       
       
  2. 압축 zstd 적용시
    1. 파일 사이즈
       
    2. 소요시간
 
 

 

참고  
 
#OS튜닝
# nofile 및 nprc 갯수 튜닝
echo "*    soft nofile  64000" >> /etc/security/limits.conf
echo "*    hard nofile  64000" >> /etc/security/limits.conf
echo "*    soft nproc  64000" >> /etc/security/limits.conf
echo "*    hard nproc  64000" >> /etc/security/limits.conf
 
vim /etc/security/limits.d/20-nproc.conf 후에 64000으로 변경
 
Run the sysctl command below to apply the changed limits to the system:
sysctl -p
 
ulimit -a 명령어로 확인 가능
 
# repo 추가(red hat 계열) : 참고
vi /etc/yum.repos.d/mongodb-org-4.2.repo 이후 아래 입력
 
[mongodb-org-4.2]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.2/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc
 
# repo 추가(amazon ami 이미지의 경우) : 참고
vi /etc/yum.repos.d/mongodb-org-4.2.repo 이후 아래 입력
 
[mongodb-org-4.2]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/4.2/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc
 
# 설치
yum install -y mongodb-org
 
# 기본 설정 작업
#huge 설정
echo never > /sys/kernel/mm/transparent_hugepage/defrag
echo never > /sys/kernel/mm/transparent_hugepage/enabled
 
#재 부팅시 자동으로 시작(필요시)
systemctl enable mongod
 
#몽고 데이터 저장 디렉토리 생성 및 mongod계정의 소유로 변경(예)
mkdir -p /data/mongo/repl_0
chown -R mongod:mongod /data
 
 
#인증모드 적용 작업
#key 생성 -> 생성된 키는 모든 replica 멤버 몽고DB서버에 복사해야함
openssl rand -base64 755 > /data/mongo/mongo_repl.key
chown mongod.mongod /data/mongo/mongo_repl.key
chmod 400 /data/mongo/mongo_repl.key
 
#설정에 인증 활성화
vi /etc/mongod.conf 후 아래 내용 추가
security:
  keyFile: /data/mongo/mongo_repl.key
  authorization: enabled
 
 

#참고: 몽고DB authorization enable설정시 key파일 생성 방법

#Primary에서 key 파일 생성 (mongodb 간 접속을 위해서 필요)

#해당 key파일은 Secondary에 복사

 

sudo openssl rand -base64 756 > /data/mongo/mongo_repl.key

sudo chown mongod.mongod /data/mongo/mongo_repl.key

sudo chmod 400 /data/mongo/mongo_repl.key

 

# 아래 내용 복사하여 Secondary 에 동일하게 구성

cat /data/mongo/mongo_repl.key

 

 

#테스트(필요시 진행)

mongo 커맨드로 mongo접속 후

use admin

db.createUser({ user: "admin", pwd: "admin", roles: [ "root" ] })

db.auth("admin", "admin")

 

show dbs

 

#DB에 저장 및 find되는지 테스트

use test_db

db.test_col.insert({msg:"test insert message"})

db.test_col.find()

 
# 몽고 시작
#몽고 서비스 시작
systemctl start mongod
 
#몽고 프롬프트에 접속
mongo
 
 
#참고 : 몽고 삭제
systemctl stop mongod
 
#Remove any MongoDB packages that you had previously installed.
yum erase $(rpm -qa | grep mongodb-org)
 
#Remove MongoDB databases and log files.
rm -rf /var/log/mongodb
rm -rf /var/lib/mongo
 
#필요시
rm -rf /data
 
 
#참고 : 몽고 설정(/etc/mongod.conf)   
 
# mongod.conf
 
# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/
 
# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  logRotate: rename 
  path: /var/log/mongodb/mongod.log
  #quiet: true
 
 
# Where and how to store data.
storage:
  engine: wiredTiger
  directoryPerDB: true
  wiredTiger:
      engineConfig:
         journalCompressor: snappy
         #journalCompressor: zstd
         #cacheSizeGB: 0.5
      collectionConfig:
         blockCompressor: snappy
         #blockCompressor: zstd
      indexConfig:
         prefixCompression: true
 
  dbPath: /data/mongo/repl_0
  journal:
      enabled: true
 
 
# how the process runs
processManagement:
  fork: true  # fork and run in background
  pidFilePath: /var/run/mongodb/mongod.pid  # location of pidfile
  timeZoneInfo: /usr/share/zoneinfo
 
 
# network interfaces
net:
  port: 27017
  bindIp: 0.0.0.0  # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting.(AWS에서는 SG로 보안처리 하고 있어서 편의상 모두 허용하기도 함)
 
 
#security:
#  keyFile: /data/mongo/mongo_repl.key
#  authorization: enabled
 
#replication:
replication:
  replSetName: repl_set
 
 
#참고 : 몽고 replica 설정
primary가 될 서버에서 몽고 콘솔로 접속 : mongo
 
#Replica set 초기화
rs.initiate()
 
#Secondary 노드 추가
rs.add("secondary장비의 IP:27017")
 
#Arbiter 노드 추가
rs.add("arbiter장비IP:37017",arbiterOnly:true)
 
 
# 잘 저장되는지 테스트
use testdb
db.test_collection.insert({'msg':'test message'})
db.test_collection.find()
 
 
#Secondary에서는 아래 명령 실행 후 조회해 보면 됨
db.slaveOk(true)
 
 
#참고: 계정 생성 방법
-- 유저 생성 및 권한 부여
use DB명 후;
db.createUser({ user: "유저ID입력    ", pwd: "암호입력", roles: [ "롤코드 입력" ] })
예) db.createUser({ user: "test-user", pwd: "pwd-1231", roles: [ "readWrite" ] })
 
 
 
 
-- 서버 접속 후 인증 방법
db.auth("<username>", "<password>" )
 
 
#root 권한으로 계정 생성 방법
use admin;
db.createUser({ user: "ID입력", pwd: "암호입력", roles: [ "root" ] })
 
 
#특정 DB만 엑세스 가능한 계정 생성 방법
use DB명 입력;
db.createUser({ user: "ID입력", pwd: "암호입력", roles: [ "readWrite" ] })
 
 
 
  1. MongoDB 드라이버를 maven pom.xml에 추가

<!-- MongoDB 드라이버를 maven pom.xml에 추가 -->

<dependency>

<groupId>org.mongodb</groupId>

<artifactId>mongodb-driver-sync</artifactId>

<version>4.0.4</version>

</dependency>

 

  1. MongoDB에 계정 생성 추가 방법

#root 권한으로 계정 생성

use admin;

db.createUser({ user: "ID입력", pwd: "암호입력", roles: [ "root" ] })

 

 

#특정 DB만 엑세스 가능한 계정 생성

use DB명 입력;

db.createUser({ user: "ID입력", pwd: "암호입력", roles: [ "readWrite" ] })

 

 

  1. java 샘플 소스

 

import com.mongodb.Block;

import com.mongodb.MongoClientSettings;

import com.mongodb.MongoCredential;

import com.mongodb.ServerAddress;

import com.mongodb.client.MongoClient;

import com.mongodb.client.MongoClients;

import com.mongodb.connection.ConnectionPoolSettings;

import org.bson.Document;

 

 

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.concurrent.TimeUnit;

 

 

/**

* 몽고DB java 4.0.4 드라이버 사용시 커넥션 소스 샘플

*  - 몽고DB 4.2에 데이터 저장하는 샘플소스

*  - DB서버는 인증모드와 replica모드가 적용되어 있음

*

* @author 엄승하

*/

public class MongoDBConnectWithAuth {

 

 

   public static void main(String[] args) {

 

 

      final String dbAddr = "DB서버주소";

 

 

      final String dbName = "DB명입력필요";

      final String user = "ID입력필요";

      final String pwd = "암호입력필요";

 

 

      final String colNm = "저장할 컬렉션명 입력 필요";

 

 

      //인증정보

      MongoCredential credential = MongoCredential.createCredential(user, dbName, pwd.toCharArray());

 

 

      //커넥션풀 설정

      Block<ConnectionPoolSettings.Builder> poolSetting = builder -> builder.maxWaitTime(4, TimeUnit.SECONDS).maxConnectionIdleTime(10000,

         TimeUnit.SECONDS).maxConnectionLifeTime(58, TimeUnit.SECONDS);

 

 

      //클러스터 또는 replica 설정

      List<ServerAddress> serverList = Arrays.asList(new ServerAddress(dbAddr, 27017));

      Block<com.mongodb.connection.ClusterSettings.Builder> clusterSettings = builder -> builder.hosts(serverList);

 

 

      //mongo와 실제 커넥션 생성(mongo client생성)

      MongoClient mongoClient = MongoClients.create(

         MongoClientSettings.builder().credential(credential).applyToConnectionPoolSettings(poolSetting).applyToClusterSettings(clusterSettings).build());

 

 

      int docsCnt = 10000;

      List<Document> docs = new ArrayList<>(docsCnt);

 

 

      for (int i = 1; i <= docsCnt; i++) {

         Document doc = new Document();

         doc.put("doc_id", i);

         doc.put("dt_ms", System.currentTimeMillis());

 

 

         docs.add(doc);

      }

 

 

      mongoClient.getDatabase(dbName).getCollection(colNm).insertMany(docs); //bulk insert

      mongoClient.close(); //자원 반환

   }

}

 

 

  1. 결과

    1. 아래와 같이 데이터가 정상적으로 저장됨을 확인 가능

 

 


몽고DB replica 재 설정방법 샘플
- primary에 커맨드 접속
- repl_set이라는 replica에 대해서 가중치를 포함하여 reconfig를 실행함
- 순단 발생하니 주의

-- config 재 정의
config = {
    "_id" : "repl_set",    
    "members" : [
            {
                    "_id" : 0,
                    "host" : "primary서버의 IP입력:27017",
                    "priority" : 3
            },
            {
                    "_id" : 1,
                    "host" : "secondary서버의 IP입력:27017",
                    "priority" : 2
            },
            {
                    "_id" : 2,
                    "host" : "arbiter서버의 IP입력:27017",                    
                    "arbiterOnly" : true
            }
    ]
}


-- re config 실행
rs.reconfig(config,  {force : true} );

-- 잘 저장되는지 테스트
use testdb
db.test_collection.insert({'msg':'test message'})
db.test_collection.find()



-- 참고: 최초 replica 설정일 경우 rs.initiate() 후 셋팅 필요

config = {
    "_id" : "repl_set",    
    "members" : [
            {
                    "_id" : 0,
                    "host" : "primary서버의 IP입력:27017",
                    "priority" : 3
            },
            {
                    "_id" : 1,
                    "host" : "secondary서버의 IP입력:27017",
                    "priority" : 2
            },
            {
                    "_id" : 2,
                    "host" : "arbiter서버의 IP입력:27017",                    
                    "arbiterOnly" : true
            }
    ]
}


rs.initiate(config);

* 기존 몽고 3.x 버전 설치문서를 기반으로 작성해서 몇 가지는 틀릴 수 있습니다.
참고로, 4.x에서는 기존 3.x에서 남아있던 소스를 많이 제거해서 성능적인 부분이 많이 개선되었으며, secondary에서 read 때 lock부분이 변경되어(복제 적용 중에 읽기가 허용됨) 대용량의 서비스에 더 좋아진 것 같습니다.

참고 

#OS튜닝
# nofile 및 nprc 갯수 튜닝
echo "*    soft nofile  64000" >> /etc/security/limits.conf
echo "*    hard nofile  64000" >> /etc/security/limits.conf
echo "*    soft nproc  64000" >> /etc/security/limits.conf
echo "*    hard nproc  64000" >> /etc/security/limits.conf

vim /etc/security/limits.d/20-nproc.conf 후에 64000으로 변경

Run the sysctl command below to apply the changed limits to the system:
sysctl -p

ulimit -a 명령어로 확인 가능


기타 
 - system service 의 resource limits들은 /etc/systemd/system.conf 여기에 설정해야 함

# repo 추가
vi /etc/yum.repos.d/mongodb-org-4.0.repo 이후 아래 입력

[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc

# 설치
yum install -y mongodb-org

# 기본 설정 작업
#huge 설정
echo never > /sys/kernel/mm/transparent_hugepage/defrag
echo never > /sys/kernel/mm/transparent_hugepage/enabled

#재 부팅시 자동으로 시작(필요시)
chkconfig mongod on

#몽고 데이터 저장 디렉토리 생성 및 mongod계정의 소유로 변경(예)
mkdir -p /data/mongo/repl_0
chown -R mongod:mongod /data


# 몽고 시작
#몽고 서비스 시작
systemctl start mongod

#몽고 프롬프트에 접속
mongo


#참고 : 몽고 삭제
systemctl stop mongod

#Remove any MongoDB packages that you had previously installed.
yum erase $(rpm -qa | grep mongodb-org)

#Remove MongoDB databases and log files.
rm -rf /var/log/mongodb
rm -rf /var/lib/mongo

#필요시
rm -rf /data


#참고 : 몽고 설정(/etc/mongod.conf)
     특정파일의 config 파일을 이용하려면 mongod --config 파일경로 (이 명령어로는 root로 프로세스가 실행되니 필요시 init.d 등을 이용할수도 있음)
vi /etc/mongod.conf 후 아래샘플을 참고하여 수정해서 사용

systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log
  quiet: true

storage:
  dbPath: /data/mongo/repl_0
  journal:
    enabled: true
  #wiredTiger:
    #engineConfig:
      #cacheSizeGB: 0.5


net:
  port: 27017
  #bindIp: 127.0.0.1  # Listen to local interface only, comment to listen on all interfaces. (주석으로 막으면 모든 IP에서 접속 가능. AWS에서는 SG로 보안처리 하고 있어서 편의상 모두 허용하기도 함)


replication:
  replSetName: repl_set



#참고 : 몽고 replica 설정
primary가 될 서버에서 몽고 콘솔로 접속 : mongo

#Replica set 초기화
rs.initiate()

#Secondary 노드 추가
rs.add("secondary장비의 IP:27017")

#Arbiter 노드 추가
rs.add( { host: "arbiter장비IP:27017", arbiterOnly: true } )


# 잘 저장되는지 테스트
use testdb
db.test_collection.insert({'msg':'test message'})
db.test_collection.find()


#Secondary에서는 아래 명령 실행 후 조회해 보면 됨
db.slaveOk(true)



#참고 - 1개 장비에 여러개의 몽고데몬을 실행시켜야할 경우
1개의 몽고DB를 설치하면 아래에 service 파일이 생성됨
/etc/systemd/system/multi-user.target.wants

해당 디렉토리의 mongod.service 심볼릭링크가 가리키는 파일(/usr/lib/systemd/system/mongod.service) 이 하나의 데몬 파일

/usr/lib/systemd/system/mongod.service 파일을 복사하여 한개 더 생성(ex. cp /usr/lib/systemd/system/mongod.service /usr/lib/systemd/system/mongod2.service)
복사한 해당 파일의 내용을 적당히 수정

예)
[Unit]
Description=High-performance, schema-free document-oriented database
After=network.target

[Service]
User=mongod
Group=mongod
Environment="OPTIONS=--quiet -f /etc/mongod2.conf"
ExecStart=/usr/bin/mongod $OPTIONS run
ExecStartPre=/usr/bin/mkdir -p /var/run/mongodb2
ExecStartPre=/usr/bin/chown mongod:mongod /var/run/mongodb2
ExecStartPre=/usr/bin/chmod 0755 /var/run/mongodb2
PermissionsStartOnly=true
PIDFile=/var/run/mongodb2/mongod.pid
# file size
LimitFSIZE=infinity
# cpu time
LimitCPU=infinity
# virtual memory size
LimitAS=infinity
# open files
LimitNOFILE=64000
# processes/threads
LimitNPROC=64000
# total threads (user+kernel)
TasksMax=infinity
TasksAccounting=false
# Recommended limits for for mongod as specified in

[Install]
WantedBy=multi-user.target


설정들 데몬에 반영
systemctl daemon-reload


#참고 mongod.conf 1번

# mongod.conf

# for documentation of all options, see:

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log
  quiet: true

# Where and how to store data.
storage:
  dbPath: /data/mongo/repl_0
  journal:
    enabled: true
#  engine:
#  mmapv1:
  wiredTiger:
     engineConfig:
          cacheSizeGB: 0.4


# how the process runs
processManagement:
  fork: true  # fork and run in background
  pidFilePath: /var/run/mongodb/mongod.pid  # location of pidfile

# network interfaces
net:
  port: 27017
 # bindIp: 127.0.0.1  # Listen to local interface only, comment to listen on all interfaces.


#security:

#operationProfiling:

#replication:
replication:
  replSetName: repl_set

#sharding:

## Enterprise-Only Options

#auditLog:

#snmp:




#참고 mongod2.conf(1개 서버에 2개 프로세스 동시에 띄울때 사용할 목적)
# mongod.conf

# for documentation of all options, see:

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod2.log
#  quiet: true

# Where and how to store data.
storage:
  dbPath: /data/mongo/repl_1
  journal:
    enabled: true
#  engine:
#  mmapv1:
  wiredTiger:
     engineConfig:
          cacheSizeGB: 0.4


# how the process runs
processManagement:
  fork: true  # fork and run in background
  pidFilePath: /var/run/mongodb2/mongod.pid  # location of pidfile

# network interfaces
net:
  port: 27018
 # bindIp: 127.0.0.1  # Listen to local interface only, comment to listen on all interfaces.


#security:

#operationProfiling:

#replication:
replication:
  replSetName: repl_set

#sharding:

## Enterprise-Only Options

#auditLog:

#snmp:



+ Recent posts