PyMongo에서의 MongoDB Replica Set에서의 FailOver 과정

지난 온라인 서버 제작자 모임에서 누군가가 질문을 하셔서 간단하게 정리합니다. MongoDB에서는 Master-Slave 와 Replica-Set 이라는 두 가지 방법을 제공하고 대부분 Replica-Set을 사용합니다. 그리고 이 경우 Primary가 죽을 경우, 자동적으로 새로운 Primary 가 선출되게 됩니다. 예를 들어 현재 저의 머신에는 다음과 같이 세 개의 mongodb instance를 실행시켜두었습니다.

 

charsyam 5657 1 0 Dec07 ? 00:03:23 /home/charsyam/mongo/mongod –dbpath /home/charsyam/data/mongodb/db1 –port 10001 –replSet charsyammongo/localhost:10002
charsyam 7016 6583 3 01:23 pts/11 00:00:46 /home/charsyam/mongo/mongod –dbpath /home/charsyam/data/mongodb/db2 –port 10002 –replSet charsyammongo/localhost:10001
charsyam 7399 6583 0 01:29 pts/11 00:00:03 /home/charsyam/mongo/mongod –dbpath /home/charsyam/data/mongodb/db3 –port 10003 –replSet charsyammongo/localhost:10001,localhost:10002

 

pymongo를 이용해서 connection을 만듭니다.

 

>>> from pymongo import Connection
>>> db = Connection(“localhost:10001″, replicaset=”charsyammongo”).test
>>> db.test.insert( {‘x’:1} )

ObjectId(‘4edf948ce50cd21aea000000′)
>>> db.test.find_one()

{u’x’: 1, u’_id’: ObjectId(‘4edcf0e4e50cd2389f000001’)}

>>> db.connection.host
localhost

>>> db.connection.port

10001

 

db.connection.host 와 db.connection.port를 이용해서 지금 어디에 연결되어 있는지를 확인할 수 있습니다.

localhost:10001 에 연결되어 있다고 가정하고 해당 instance를 한번 종료시켜 보겠습니다.

 

kill -9 5657

 

그리고 다시 db.test.find_one()를 하게 되면 다음과 같은 에러가 발생합니다.

 

Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
File “pymongo/collection.py”, line 518, in find_one
for result in self.find(spec_or_id, *args, **kwargs).limit(-1):
File “pymongo/cursor.py”, line 699, in next
if len(self.__data) or self._refresh():
File “pymongo/cursor.py”, line 662, in _refresh
self.__uuid_subtype))
File “pymongo/cursor.py”, line 612, in __send_message
**kwargs)
File “pymongo/connection.py”, line 868, in _send_message_with_response
sock = self.__socket()
File “pymongo/connection.py”, line 680, in __socket
sock, from_pool = self.__pool.get_socket(host, port)
File “pymongo/connection.py”, line 165, in get_socket
self.sock = (pid, self.connect(host, port))
File “pymongo/connection.py”, line 127, in connect
s.connect((host, port))
File “<string>”, line 1, in connect

 

상황에 따라서 다음과 같은 오류가 나기도 합니다.

>>> db.test.find_one()

Trackback (most recent call last):

pymongo.errors.AutoReconnect: …

 

그리고 다시 시도하면 오퍼레이션 도중에 자동으로 접속을 하게 됩니다. Connect 부분에서 call stack을 찍어보면 다음과 같습니다. 참고문서를 보면 AutoReconnect는 이전 primary에 접속할 수 없을 경우에 발생한다고 합니다.

 

(Pdb) w

<stdin>(1)<module>()

/home/charsyam/repo/charsyam/pymongo/pymongo/collection.py(518)find_one()

-> for result in self.find(spec_or_id, *args, **kwargs).limit(-1):

/home/charsyam/repo/charsyam/pymongo/pymongo/cursor.py(699)next()

-> if len(self.__data) or self._refresh():

/home/charsyam/repo/charsyam/pymongo/pymongo/cursor.py(662)_refresh()

-> self.__uuid_subtype))

/home/charsyam/repo/charsyam/pymongo/pymongo/cursor.py(612)__send_message()

-> **kwargs)

/home/charsyam/repo/charsyam/pymongo/pymongo/connection.py(871)_send_message_with_response()

-> sock = self.__socket()

/home/charsyam/repo/charsyam/pymongo/pymongo/connection.py(671)__socket()

-> host, port = self.__find_node()

/home/charsyam/repo/charsyam/pymongo/pymongo/connection.py(641)__find_node()

-> node = self.__try_node(candidate)

/home/charsyam/repo/charsyam/pymongo/pymongo/connection.py(580)__try_node()

-> response = self.admin.command(“ismaster”)

/home/charsyam/repo/charsyam/pymongo/pymongo/database.py(344)command()

-> _uuid_subtype = uuid_subtype)

/home/charsyam/repo/charsyam/pymongo/pymongo/collection.py(518)find_one()

-> for result in self.find(spec_or_id, *args, **kwargs).limit(-1):

/home/charsyam/repo/charsyam/pymongo/pymongo/cursor.py(699)next()

-> if len(self.__data) or self._refresh():

/home/charsyam/repo/charsyam/pymongo/pymongo/cursor.py(662)_refresh()

-> self.__uuid_subtype))

/home/charsyam/repo/charsyam/pymongo/pymongo/cursor.py(612)__send_message()

-> **kwargs)

/home/charsyam/repo/charsyam/pymongo/pymongo/connection.py(871)_send_message_with_response()

-> sock = self.__socket()

/home/charsyam/repo/charsyam/pymongo/pymongo/connection.py(674)__socket()

-> sock, from_pool = self.__pool.get_socket(host, port)

/home/charsyam/repo/charsyam/pymongo/pymongo/connection.py(168)get_socket()

-> self.sock = (pid, self.connect(host, port))

> /home/charsyam/repo/charsyam/pymongo/pymongo/connection.py(138)connect()

-> if self.use_ssl:

 

참고문헌: http://api.mongodb.org/python/current/examples/replica_set.html