mongodb 3.2 wiredTiger 버전을 사용 중이고, 대용량 트래픽을 조금씩 받고 있는 mongodb가 있다.
하지만, mongodb의 replicaset 구축하고 나서, mariadb(mysql) 만큼 안정성이 높지 않은 것에 대해 최근 경악한 일이 있어서 공유한다.
mongodb가 slave가 RECOVERING 상태가 오래동안 두면, 자동으로 복구가 되길 바라지만 복구가 절대 되지 않는 경우가 있는 것 같다. 그러면 FAILED였으면 더 좋았을 뻔..
내가 겪은 내용 뿐 아니라 mongodb는 안전화될 때까지 주기적으로 손을 봐야하고, 안전화가 필요한 것으로 보여진다. (jira 참조)
Replication 상태를 확인해본다. Slave 한대가 Recovering 상태이고, 동기화가 안된지 꽤 오랜 시간이 걸렸다. slave 자입의 optimeDate가 오래되었다. 동기가 실패된지 꽤 오랜 시간이 되었음을 알린다.
$ mongo
MongoDB shell version: 3.2.0
connecting to: test
replset:RECOVERING> rs.status()
{
"set" : "replset",
"date" : ISODate("2016-10-21T01:40:13.146Z"),
"myState" : 3,
"term" : NumberLong(-1),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "1.1.1.1:27017",
"health" : 1,
"state" : 3,
"stateStr" : "RECOVERING",
"uptime" : 25473606,
"optime" : Timestamp(1457316114, 1871),
"optimeDate" : ISODate("2016-03-07T02:01:54Z"),
"maintenanceMode" : 328882,
"infoMessage" : "could not find member to sync from",
"configVersion" : 1,
"self" : true
},
{
"_id" : 1,
"name" : "2.2.2.2:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 3521143,
"optime" : Timestamp(1477013949, 1),
"optimeDate" : ISODate("2016-10-21T01:39:09Z"),
"lastHeartbeat" : ISODate("2016-10-21T01:40:12.320Z"),
"lastHeartbeatRecv" : ISODate("2016-10-21T01:40:12.999Z"),
"pingMs" : NumberLong(0),
"electionTime" : Timestamp(1451540357, 1),
"electionDate" : ISODate("2015-12-31T05:39:17Z"),
"configVersion" : 1
},
...
이제 제대로 동기화되게 해보자.
1.1.1.1 (slave)서버에 가서 몽고 셧다운을 한다.
$ mongod --shutdown
killing process with pid: 26867
$ ps -ef | grep mongo
(없음)
/etc/mongod.conf 에 정의된 db데이터-디렉토리를 백업해두고 새로 디렉토리를 생성한다.
$ mv db데이터-디렉토리 백업디렉토리
$ mkdir db데이터-디렉토리
$ /usr/local/mongodb/bin/mongod -f /etc/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 19670
child process started successfully, parent exiting
$ ps -ef | grep mongo
/usr/local/mongodb/bin/mongod -f /etc/mongod.conf
2.2.2.2(master) 서버에서 replication 상태를 보기 위해 rs.status() 를 실행한다. 1.1.1.1(slave) 서버의 상태가 STARTUP2로 변경되었다.
$ mongo
MongoDB shell version: 3.2.0
connecting to: test
replset:PRIMARY> rs.status()
{
"set" : "replset",
"date" : ISODate("2016-10-21T01:45:15.535Z"),
"myState" : 1,
"term" : NumberLong(-1),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "1.1.1.1:27017",
"health" : 1,
"state" : 5,
"stateStr" : "STARTUP2",
"uptime" : 28,
"optime" : Timestamp(0, 0),
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2016-10-21T01:45:15.081Z"),
"lastHeartbeatRecv" : ISODate("2016-10-21T01:45:14.171Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "syncing from: 172.17.58.238:27017",
"syncingTo" : "172.17.58.238:27017",
"configVersion" : 1
},
{
"_id" : 1,
"name" : "2.2.2.2:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 25474192,
"optime" : Timestamp(1477014306, 1),
"optimeDate" : ISODate("2016-10-21T01:45:06Z"),
"electionTime" : Timestamp(1451540357, 1),
"electionDate" : ISODate("2015-12-31T05:39:17Z"),
"configVersion" : 1,
"self" : true
},
...
처음 상태는 STARTUP2가 되고, 데이터 동기가 완료되면, SECONDARY로 상태가 변경된다.
데이터가 많을수록, IO(N/W) 시간이 느릴 수록 동기화 완료가 늦어진다. (이래서 SLAVE 장비가 좋아야 한단 것인가..)
동기화가 완료되면, 제대로 싱크되는지 확인할 수 있다.
replset:SECONDARY> db.printSlaveReplicationInfo()
source: ip:27017
syncedTo: Thu Jan 01 1970 09:00:00 GMT+0900 (KST)
1477015631 secs (410282.12 hrs) behind the primary
source: ip:27017
syncedTo: Fri Oct 21 2016 11:07:11 GMT+0900 (KST)
0 secs (0 hrs) behind the primary
또한, rs.status() 명령어를 실행하면 SECONDARY로 돌아온 것을 확인할 수 있다.
이 문제를 해결하기 위해 다양하게 접근 중이다. 문제 해결을 위해 다양한 해결 방식을 채택하면서 모니터링하면서 살펴봐야할 것 같다.
1. mongodb 업그레이드
mongodb 3.x는 여진히 진화 중이다. 여전히 버그가 많아서 게속 버전 업을 진행해야 한다.
2. oplog 크기
몽고DB 문서(https://docs.mongodb.com/manual/core/replica-set-oplog/#replica-set-oplog-sizing, https://docs.mongodb.com/manual/tutorial/troubleshoot-replica-sets/)에 따르면, oplog 디폴트 크기는 다음과 같다.
oplog size를 확인해본다.
$ mongo
MongoDB shell version: 3.2.0
connecting to: test
replset:PRIMARY> rs.printReplicationInfo()
configured oplog size: 10240MB
설정파일에서 oplog size를 설정할 수 있다. 나는 이미 10G로 내가 임의로 설정할 수 있다.
replication:
oplogSizeMB: 10240
replSetName: "replset"
3. /var/log/mongodb/mongod.log 파일에서 로그 분석
마지막으로 끊긴 시간을 기준으로 로그를 분석해 본다.
"optimeDate" : ISODate("2016-03-07T02:01:54Z"),
해당 일자 단위로 slave 로그를 보면, stale 상태로 된 것을 확인할 수 있다.
[ReplicationExecutor] syncing from: ip:27017
[rsBackgroundSync] we are too stale to use ip:27017 as a sync source
[ReplicationExecutor] could not find member to sync from
[rsBackgroundSync] too stale to catch up -- entering maintenance mode
[rsBackgroundSync] our last optime : (term: -1, timestamp: Mar 7 11:01:54:74f)
[rsBackgroundSync] oldest available is (term: -1, timestamp: Mar 7 11:09:19:21f)
[rsBackgroundSync] See http://dochub.mongodb.org/core/resyncingaverystalereplicasetmember
[ReplicationExecutor] going into maintenance mode with 524 other maintenance mode tasks in progress
로그가 가르키는 문서를 참조해 본다.
https://docs.mongodb.com/manual/tutorial/resync-replica-set-member/
stale 상태가 되면 데이터를 지우고 resync 작업을 진행하고 초기화 작업을 진행한다.
위에서 진행한 작업이 사실상 resync&init 작업이었다.
- Stop the member’s mongod instance. To ensure a clean shutdown, use the db.shutdownServer()method from the mongo shell or on Linux systems, the mongod --shutdown option.
- Delete all data and sub-directories from the member’s data directory. By removing the data dbPath, MongoDB will perform a complete resync. Consider making a backup first.
4. 다른 방법
성능이 좋은 장비를 써서 mongodb 쿼리가 빠르게 실행되도록 해야 한다.
찾아보니, 대용량 map reduce 가 상황에 따라서 blocking을 유발시킬 수 있다고 한다. 관련 내용을 찾아보고 있다.
http://blog.mlab.com/2013/03/replication-lag-the-facts-of-life/ 글에 따르면 slave가 recovering(stale) 상태에 빠지지 않는 여러 방법을 제안했다.
1. Make sure your secondary has enough horsepower
2. Consider adjusting your write concern
3. Plan for index builds
4. Take backups without blocking
5. Be sure capped collections have an _id field & a unique index
6. Check for replication errors
5. 툴을 이용한 모니터링
http://www.slideshare.net/revolutionistK/mongo-db-monitoring-mongodb-korea
상용 툴 : mongodb mms
https://www.mongodb.com/cloud
grafana쪽도 살펴봐야 할 것 깉다.
좀 더 모니터링해보고, 정확한 문제에 대한 해결 방법을 정리해야 할 것 같다. .
6. 다양한 공부
https://www.datadoghq.com/blog/monitoring-mongodb-performance-metrics-wiredtiger/
*****
나중에 해보니..
3.4로 업글하고,
replication의 oplogSizeMB을 작게 줄이니(10G->1G) 대용량 트래픽에도 replication이 끊어지지 않게 되었다.