참고 : https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set/
방화벽 체크 IP 체크 등은 이중화에 당연한 요소니까 설정했다고 치고 스킵.
그 외 localhost 루프백으로 하면 로컬에서만 붙을 수 있다..스킵.
여기서 살짝 드는 의문
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를 일단 띄울 수 있다.
이걸 인스턴스 분리하고 보게 될 줄이야...
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만 설정하면 구성 끝.
튜토리얼 대로 넘버링.
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}}
뭐...그 외에도 이것저것 뜨는데 일단 설정을 해 보자.
해당 명령은 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
}
여기서 몇 가지 브레인스토밍
다음 섹션
1. arbiter 노드 구성
2. 설정 프로퍼티 리서치
3. 기타 등등
4. OP log 리서치