MongoDB Replication(2) - replication 구성

Sibeet·2022년 7월 6일
0

MongoDB

목록 보기
2/2

Replication 구성

참고 : https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set/

instance 분리

방화벽 체크 IP 체크 등은 이중화에 당연한 요소니까 설정했다고 치고 스킵.
그 외 localhost 루프백으로 하면 로컬에서만 붙을 수 있다..스킵.
여기서 살짝 드는 의문

  • 그럼 필요한 건 IP, Port 뿐인가?
  • Hostname으로도 접속 가능한가?

    default binding and bind to other IP addresses, use the net.bindIp configuration file setting or the --bind_ip command-line option to specify a list of hostnames or IP addresses.

Mongod 프로세스에서 hostname을 binding하면 hostname으로 만들어 줄 수 있음.
예를 들어,

mongod --bind_ip localhost,My-Example-Associated-Hostname

와 같은 식으로 바인드하면 mongosh에서 hostname으로 붙을 수 있는 셈.

mongosh --host My-Example-Associated-Hostname

mongosh --host 198.51.100.1

IP로 접속해도 되고, hostname으로도 가능하단 뜻이 된다.
--port 옵션도 마찬가지로 존재하니, 해당 옵션을 이용해서 한 장비에서 두개를 띄울 수 있겠다.

그래서 요렇게 구성.

alias pstart='nohup mongod --dbpath /home/mongo/lib --logpath /home/mongo/log/mongo.log --port 48900 --bind_ip localhost,pri_host 1>/dev/null 2>&1 &'
alias sstart='nohup mongod --dbpath /home/mongo/lib2 --logpath /home/mongo/log2/mongo.log --port 49000 --bind_ip localhost,sec_host 1>/dev/null 2>&1 &'

alias pstop='mongod --dbpath /home/mongo/lib --shutdown'
alias sstop='mongod --dbpath /home/mongo/lib2 --shutdown'

alias pmongo='ps -ef | grep mongo'

사실은 쉘로 했지만...일일히 쓰기 귀찮으니 일단은 alias로.

dbpath와 logpath를 분리하고 port, bind_ip를 분리하면 두 개의 DB를 일단 띄울 수 있다.

Configuration file

이걸 인스턴스 분리하고 보게 될 줄이야...
conf 파일로 상기의 설정을 모두 구성할 수 있다고 한다. 이게 무슨 뻘짓.
--conf 혹은 -f 설정으로 config 파일을 찾게 할 수 있다.
뭐 좋다. 훨씬 간단하게 할 수 있겠지.

Example:

processManagement:
   fork: true
net:
   bindIp: localhost
   port: 48900
storage:
   dbPath: /home/mongo/lib
systemLog:
   destination: file
   path: "/home/mongo/log/mongod.log"
   logAppend: true
storage:
   journal:
      enabled: true

일단은 conf파일을 하나씩 만들어 주고, 해당 방법으로 기동하게 변경했다.

alias pstart='mongod --config /home/mongo/conf/mongod.conf_pri'
alias sstart='mongod --config /home/mongo/conf/mongod.conf_sec'

이렇게 된 김에, mongosh도 alias를 만들어 주고.

alias pmongo='mongosh --host localhost --port 48900'
alias smongo='mongosh --host localhost --port 49000'

이제 replication set만 설정하면 구성 끝.

replication set

튜토리얼 대로 넘버링.

각 멤버를 replica set 세팅하여 기동한다.

Replica set에 필요한 프로퍼티는 replSetName이다.
예시:

replication:
   replSetName: "rs0"
net:
   bindIp: localhost,primary_host

해당 프로퍼티를 양쪽에 설정하고 띄우면 되는데,
들어가서 설정을 안해서인지 이런 메시지가 계속해서 로그에 남는다.

{"t":{"$date":"2022-07-06T16:27:53.384+09:00"},"s":"I",  "c":"-",        "id":4939300, "ctx":"monitoring-keys-for-HMAC","msg":"Failed to refresh key cache","attr":{"error":"NotYetInitialized: Cannot use non-local read concern until replica set is finished initializing.","nextWakeupMillis":11200}}

뭐...그 외에도 이것저것 뜨는데 일단 설정을 해 보자.

mongosh로 접속해서 member create

해당 명령은 rs.initiate()를 통해 구성한다.

test> rs.initiate( {
...    _id : "rs0",
...    members: [
...       { _id: 0, host: "localhost:48900" },
...       { _id: 1, host: "localhost:49000" }
...    ]
... })
{ ok: 1 }

...끝?
소름돋을 정도로 쉽다.

ok 메시지가 뜨고 각각의 instance로 접근해 보면 다음과 같이 구별된다.

rs0 [direct: primary] test>
rs0 [direct: secondary] test>

로그를 까보면 다음과 같은 메시지.

Primary:

{"t":{"$date":"2022-07-06T16:42:59.990+09:00"},"s":"I",  "c":"REPL",     "id":6015313, "ctx":"OplogApplier-0","msg":"Replication config state is Steady, starting reconfig"}
{"t":{"$date":"2022-07-06T16:42:59.990+09:00"},"s":"I",  "c":"REPL",     "id":6015317, "ctx":"OplogApplier-0","msg":"Setting new configuration state","attr":{"newState":"ConfigReconfiguring","oldState":"ConfigSteady"}}
{"t":{"$date":"2022-07-06T16:42:59.990+09:00"},"s":"I",  "c":"REPL",     "id":21353,   "ctx":"OplogApplier-0","msg":"replSetReconfig config object parses ok","attr":{"numMembers":2}}
{"t":{"$date":"2022-07-06T16:42:59.990+09:00"},"s":"I",  "c":"REPL",     "id":51814,   "ctx":"OplogApplier-0","msg":"Persisting new config to disk"}
{"t":{"$date":"2022-07-06T16:42:59.991+09:00"},"s":"I",  "c":"REPL",     "id":6015315, "ctx":"OplogApplier-0","msg":"Persisted new config to disk"}
{"t":{"$date":"2022-07-06T16:42:59.991+09:00"},"s":"I",  "c":"REPL",     "id":6015317, "ctx":"OplogApplier-0","msg":"Setting new configuration state","attr":{"newState":"ConfigSteady","oldState":"ConfigReconfiguring"}}
{"t":{"$date":"2022-07-06T16:42:59.992+09:00"},"s":"I",  "c":"REPL",     "id":21392,   "ctx":"OplogApplier-0","msg":"New replica set config in use","attr":{"config":{"_id":"rs0","version":1,"term":1,"members":[{"_id":0,"host":"localhost:48900","arbiterOnly":false,"buildIndexes":true,"hidden":false,"priority":1,"tags":{},"secondaryDelaySecs":0,"votes":1},{"_id":1,"host":"localhost:49000","arbiterOnly":false,"buildIndexes":true,"hidden":false,"priority":1,"tags":{},"secondaryDelaySecs":0,"votes":1}],"protocolVersion":1,"writeConcernMajorityJournalDefault":true,"settings":{"chainingAllowed":true,"heartbeatIntervalMillis":2000,"heartbeatTimeoutSecs":10,"electionTimeoutMillis":10000,"catchUpTimeoutMillis":-1,"catchUpTakeoverDelayMillis":30000,"getLastErrorModes":{},"getLastErrorDefaults":{"w":1,"wtimeout":0},"replicaSetId":{"$oid":"62c53cf859b9e8bba8443eca"}}}}}
{"t":{"$date":"2022-07-06T16:42:59.992+09:00"},"s":"I",  "c":"REPL",     "id":21393,   "ctx":"OplogApplier-0","msg":"Found self in config","attr":{"hostAndPort":"localhost:48900"}}
{"t":{"$date":"2022-07-06T16:42:59.992+09:00"},"s":"I",  "c":"REPL",     "id":6015310, "ctx":"OplogApplier-0","msg":"Starting to transition to primary."}

Secondary:

{"t":{"$date":"2022-07-06T16:42:59.989+09:00"},"s":"I",  "c":"REPL",     "id":2903000, "ctx":"conn2","msg":"Restarting heartbeats after learning of a new primary","attr":{"myPrimaryId":"none","senderAndPrimaryId":0,"senderTerm":1}}
{"t":{"$date":"2022-07-06T16:42:59.990+09:00"},"s":"I",  "c":"REPL",     "id":21215,   "ctx":"ReplCoord-0","msg":"Member is in new state","attr":{"hostAndPort":"localhost:48900","newState":"PRIMARY"}}
{"t":{"$date":"2022-07-06T16:42:59.992+09:00"},"s":"I",  "c":"REPL",     "id":21401,   "ctx":"conn2","msg":"Scheduling heartbeat to fetch a newer config","attr":{"configTerm":1,"configVersion":1,"senderHost":"localhost:48900"}}
{"t":{"$date":"2022-07-06T16:42:59.993+09:00"},"s":"I",  "c":"REPL",     "id":6015317, "ctx":"ReplCoord-2","msg":"Setting new configuration state","attr":{"newState":"ConfigHBReconfiguring","oldState":"ConfigSteady"}}
{"t":{"$date":"2022-07-06T16:42:59.994+09:00"},"s":"I",  "c":"REPL",     "id":6015317, "ctx":"ReplCoord-2","msg":"Setting new configuration state","attr":{"newState":"ConfigSteady","oldState":"ConfigHBReconfiguring"}}
{"t":{"$date":"2022-07-06T16:42:59.995+09:00"},"s":"I",  "c":"REPL",     "id":21392,   "ctx":"ReplCoord-2","msg":"New replica set config in use","attr":{"config":{"_id":"rs0","version":1,"term":1,"members":[{"_id":0,"host":"localhost:48900","arbiterOnly":false,"buildIndexes":true,"hidden":false,"priority":1,"tags":{},"secondaryDelaySecs":0,"votes":1},{"_id":1,"host":"localhost:49000","arbiterOnly":false,"buildIndexes":true,"hidden":false,"priority":1,"tags":{},"secondaryDelaySecs":0,"votes":1}],"protocolVersion":1,"writeConcernMajorityJournalDefault":true,"settings":{"chainingAllowed":true,"heartbeatIntervalMillis":2000,"heartbeatTimeoutSecs":10,"electionTimeoutMillis":10000,"catchUpTimeoutMillis":-1,"catchUpTakeoverDelayMillis":30000,"getLastErrorModes":{},"getLastErrorDefaults":{"w":1,"wtimeout":0},"replicaSetId":{"$oid":"62c53cf859b9e8bba8443eca"}}}}}

이것저것 살펴 보면 primary는 config 등 설정하고 secondary는 관련 프로세스를 올리고... 조금씩 작동이 다르긴 하지만 나름 성공적으로 커넥션이 이루어진 것 같다.
현재 레플리카 셋의 상태는 rs.conf 혹은 rs.status로 확인한다.

rs0 [direct: primary] test> rs.conf()
{
  _id: 'rs0',
  version: 1,
  term: 1,
  members: [
    {
      _id: 0,
      host: 'localhost:48900',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 1,
      host: 'localhost:49000',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    }
  ],
  protocolVersion: Long("1"),
  writeConcernMajorityJournalDefault: true,
  settings: {
    chainingAllowed: true,
    heartbeatIntervalMillis: 2000,
    heartbeatTimeoutSecs: 10,
    electionTimeoutMillis: 10000,
    catchUpTimeoutMillis: -1,
    catchUpTakeoverDelayMillis: 30000,
    getLastErrorModes: {},
    getLastErrorDefaults: { w: 1, wtimeout: 0 },
    replicaSetId: ObjectId("62c53cf859b9e8bba8443eca")
  }
}
rs0 [direct: primary] test> rs.status
[Function: status] AsyncFunction {
  apiVersions: [ 0, 0 ],
  returnsPromise: true,
  serverVersions: [ '0.0.0', '999.999.999' ],
  topologies: [ 'ReplSet', 'Sharded', 'LoadBalanced', 'Standalone' ],
  returnType: { type: 'unknown', attributes: {} },
  deprecated: false,
  platforms: [ 0, 1, 2 ],
  isDirectShellCommand: false,
  acceptsRawInput: false,
  shellCommandCompleter: undefined,
  help: [Function (anonymous)] Help
}

여기서 몇 가지 브레인스토밍

  • arbiterOnly : 이 프로퍼티를 바꾸면 arbiter 노드로 구성할 수 있겠지?
  • hidden : 조회되지 않는 히든 노드를 만들 수 있을까?
  • priority : 예상하기로는 fail-over시 priority를 정할 수 있을 것으로 보인다
  • buildIndexes : secondary node의 인덱스를 빌드하지 않고 운영할 수 있을까? read-only로도 사용하지 않는 DR 등의 용도라면 장점이 있을 수 있겠으나...fail-over시 난점이 생기는 것 아닌지?

다음 섹션
1. arbiter 노드 구성
2. 설정 프로퍼티 리서치
3. 기타 등등
4. OP log 리서치

0개의 댓글