본문 바로가기

Database/MongoDB

MongoDB의 Failover

Conclusion

MongoDB는 데이터베이스 수준의 Failover를 제공하여 과반수 이상의 서버에 문제가 발생하지 않는 한 가용성이 유지된다. 

Application에서 MongoDB의 Failover가 발생하더라도 문제가 없도록 Connection String과 Option을 구성하고 Failover 시 발생할 수 있는 에러를 처리하는 로직을 작성해야한다. 

이를 검증하기 위해 Failover Test를 진행하며 Application에서 MongoDB에 연결하여 부하를 준 상황에서 rs.stepDown(), db.shutdownServer(), kill -9 MONGODB_PID 를 통해 테스트할 수 있다. 

Failover

우리가 MongoDB를 사용할 때, 보통 Replica Set의 형태로 사용한다. 또한, 보통의 Replica Set은 PSS( Primary - Secondary - Secondary )의 구성으로 사용한다. Replica Set에서 Primary 멤버가 모종의 이유로 Down 되거나 연결되지 않는 경우, Election을 통해 남은 Secondary 멤버 중에서 새로운 Primary를 선출한다. 새로 선출된 Primary는 Application의 Write나 Read Operation을 처리하게 되고 이를 통해 Replica Set을 구성하고 있는 멤버의 과반수 이상이 동시에 Down되지 않는 이상 Database의 가용성이 보장된다. 

 

Replica Set을 구성하고 있는 멤버 중 하나의 멤버( Primary 일수도, Secondary or Arbiter 일수도 있다. ) 가 Down되는 경우, MongoDB가 Down된 Primary를 대신하여 새로운  Primary를 선출하거나 Down된 Secondary가 처리하고 잇던 Read Operation을 다른 Secondary 멤버가 처리할 수 있도록 조치해주는 것을 Failover 라고 한다.

 

하지만 MongoDB 수준에서 Failover가 된다고 해서, Application 에서 문제가 발생하지 않는다는 것을 보장할 수 없다. Application에서 잘못된 설정을 사용하고 있는 경우, MongoDB가 Failover 되었을 때 Application에서 문제가 발생할 수 있다. 

Application Check List 

Connection String을 잘못 작성한 경우

Application에서는 MongoDB에 Connection String을 사용해 접속한다. MongoDB에서 사용할 수 있는 Connection String 형식은 SRV Connection FormatStandard Connection String Format이 있다. 

https://www.mongodb.com/docs/manual/reference/connection-string/

 

Connection Strings — MongoDB Manual

Docs Home → MongoDB Manual ➤ Use the Select your language drop-down menu in the upper-right to set the language of the following examples.You can use connection strings to define connections between MongoDB instances and the following destinations:You

www.mongodb.com

 

Standrad Connection String Format을 사용하는 경우에는 다음과 같은 형식으로 Connection String을 구성한다. 

mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]

 

이 때, 다음과 같은 항목을 체크해야한다. 

1. Replica Set을 구성하고 있는 모든 서버의 IP 또는 hostname을 넣어야한다. 

2. Connection String의 옵션 중 replicaSet 옵션에 Replica Set의 이름을 넣어야한다. 

 

해당 항목들을 체크하지 않고 사용하는 경우, MongoDB의 Failover시 Application에서 연결할 수 있는 MongoDB를 찾지 못해 장애가 발생할 수 있다. 

PSH ( Primary - Secondary - Hidden ) 구성에서 ReadPreference 가 Secondary 인 경우 

Replica Set을 PSS 구성이 아닌 PSH( Primary - Secondary - Hidden ) 구성으로 사용하는 경우도 있다. 이는 Replica Set의 마지막 Secondary 멤버를 백업 또는 분석용 쿼리의 용도로 사용하기 위해 MongoDB의 config 중 hidden : true 로 사용하는 경우를 말한다. hidden : true로 설정하면, Application에서 DirectConnection 옵션을 사용해 MongoDB에 접속하지 않는 한 일반 Application에서는 해당 MongoDB에 Operation을 수행할 수 없다. 

replSet:SECONDARY> rs.config()
{
        "_id" : "replSet",
        "version" : 4,
        "term" : 126,
        "protocolVersion" : NumberLong(1),
        "writeConcernMajorityJournalDefault" : true,
        "members" : [
                {
                        "_id" : 0,
                        "host" : "hostname1",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 1,
                        "host" : "hostname2",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 2,
                        "host" : "hostname3",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : true, --> hidden true
                        "priority" : 0,
                        "tags" : {
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
        ]
}

 

위의 예시는 3번째 멤버를 hidden: true로 설정하는 경우이다. 

 

이때, Connection String의 Option 중 ReadPreference를 Secondary로 사용하는 경우에 문제가 발생할 수 있다. 

왜냐하면, MongoDB가 Failover가 되는 경우 하나의 멤버가 down되기 때문에, PH ( Primary - Hidden ) 구성이 된다. 이렇게 되면, Application에서 Read Operation을 수행할 Secondary 멤버를 찾을 수 없기 때문에 Read Operation을 수행할 수 없게 된다. 

따라서, Connection String에는 꼭 ReadPreference 옵션을 Secondary가 아닌 secondaryPreferred 로 사용해야한다. 

 

https://www.mongodb.com/docs/manual/core/read-preference/

 

Read Preference — MongoDB Manual

Docs Home → MongoDB Manual Read preference describes how MongoDB clients route read operations to the members of a replica set.By default, an application directs its read operations to the primary member in a replica set (i.e. read preference mode "prima

www.mongodb.com

Failover Test

서비스를 릴리즈하기 전에 MongoDB를 사용하는 Application에서 MongoDB의 Failover에 대한 대비를 했는지 확인하기 위해 Failover Test를 진행한다. 

Failover Test란 MongoDB 멤버의 장애 상황을 가정하고 일부러 MongoDB의 Failover를 발생시킨뒤 Application에서 문제가 없는지 확인하는 과정이다. 

 

테스트는 Application에서 MongoDB에 연결한 뒤 실제 어플리케이션 코드를 사용해 MongoDB에 Read, Write Operation를 수행하는 상황에서 진행해야하고, 부하의 정도는 실제 서비스의 부하 정도와 동일하면 좋지만 이는 힘들 수 있으므로 적은 수준의 부하에서 수행하는 경우도 있다.  

 

임의의 MongoDB Failover를 발생하는 방식은 다음 방식을 사용할 수 있다. 

1. rs.stepDown() 

2. db.shutdownServer() 

3. kill -9 MONGODB_PID

 

rs.stepDown()

기존의 Primary를 제외한 Secondary 중에서 새로운 Primary를 선출한다. 

rs.stepDown()은 곧바로 Primary를 Secondary로 강등하지 않는다.

1. 기존의 Secondary 중에서 Primary를 선출할 수 있는지 여부를 판단하고

2. Primary가 될 수 있는 Secondary가 있는 경우에 Rollback이 발생하지 않도록 Secondary의 복제지연을 secondaryCatchUpPeriodSeconds 만큼 기다린 후에 

3. Primary를 Secondary로 강등한 뒤 선출을 진행한다. 

이로 인해 안정적으로 Failover가 진행된다. 

https://www.mongodb.com/docs/manual/reference/method/rs.stepDown/

 

rs.stepDown() — MongoDB Manual

Docs Home → MongoDB Manual rs.stepDown(stepDownSecs, secondaryCatchUpPeriodSecs)Instructs the primary of the replica set to become a secondary. After the primary steps down, eligible secondaries will hold an election for primary.The method does not immed

www.mongodb.com

db.shutdownServer() 

db.shutdownServer는 떠있는 mongod 혹은 mongos 프로세스를 종료한다. 

해당 명령어로 종료하는 경우, stepdown을 진행한 뒤 stepdown에 성공한 경우 mongod 혹은 mongos가 종료된다.

force : true로 해당 명령을 수행하지 않으면, stepdown에 실패한 경우 mongod, mongos를 종료하지 않는다. 

 

또한, shutdownServer 명령은 stepdown 이후 mongod 혹은 mongos에서 수행중인 operation이 있으면 해당 operation이 종료될 때 까지 기다린다. 기다리는 동안에는 새로운 operation을 받아 처리하지 않는 quiesce period가 된다. 

 

db.shutdownServer()를 수행하는 경우 안정적으로 Failover 가 진행된다. 

https://www.mongodb.com/docs/manual/reference/method/db.shutdownServer/

 

db.shutdownServer() — MongoDB Manual

Docs Home → MongoDB Manual db.shutdownServer()Shuts down the current mongod or mongos process cleanly and safely. You must issue the db.shutdownServer() operation against the admin database.db.shutdownServer() has this syntax:db.shutdownServer({ force: ,

www.mongodb.com

kill -9 MONGODB_PID

이 방법은 MongoDB가 동작중인 서버가 갑자기 down되는 경우를 가정하며 기동중인 MongoDB를 곧바로 종료시킨다. 따라서 MongoDB에서 stepdown이 수행되지 않고, MongoDB가 처리중이 operation이 종료될 때 까지 기다리지도 않는다. 이 방법으로 MongoDB를 Failover 시키는 경우 Application에서 Timeout Error가 발생할 수 있다. 

Application에서는 이러한 Timeout Error를 처리하는 로직을 작성해야한다.