MongoDB의 Global Lock

Pinterest

글 : 이승용

MongoDB의 global lock은 용어에 풍겨 나오는 이미지에 의해 여러 개의 노드로 구성된 MongoDB 시스템에서 유일하게 사용되는 전체 락 이라고 생각할 수 있지만, 이는 전체 락 이기 보다는 MongoDB 시스템의 락 정보를 저장하고 있는 저장소이다. 저장하는 정보로는 현재 락 상태, 락 지속 여부, 현재 대기 중인 읽기 또는 쓰기 연산 수, 그리고 클라이언트 개수가 있다. [표 3]는 MongoDB의 serverStatus를 통해 취득할 수 있는 global lock의 항목을 보여준다.

[표 3] Global lock 항목

항목 내용
globalLock.totalTime Global lock이 생성된 시간으로 시스템이 기동되고 난부터 수행중인 시간을 의미하다.(단위 : microseconds)
globalLock.lockTime Lock 지속시간을 나타내는 것으로, 프로세스가 기동하고 난 다음부터 현 시점까지 lock이 걸려있던 시간의 합을 의미한다.(단위 : microseconds)
globalLock.ratio lockTime / totalTime 의 값
globalLock.currentQueue.total currentQueue.readers + currentQueue.writers 의 값
globalLock.currentQueue.readers 연산 중에서 lock이 걸린 읽기 연산의 개수
globalLock.currentQueue.writers 연산 중에서 lock이 결린 쓰기 연산의 개수
globalLock.activeClients.total activeClients.readers + activeClients.writers 의 값
globalLock.activeClients.readers 읽기 연산을 수행하고 있는 클라이언트의 개수
globalLock.activeClients.writers 쓰기 연산을 수행하고 있는 클라이언트의 개수

[표 3]의 값에서 주목하여야 할 값은 lockTime이다. lockTime은 MongoDB가 쓰기 락이 수행된 시간을 누적시킨 값으로, 값의 증가가 빨라지면 lockTime이 길어진다는 의미이다. 이 값이 길어지게 되는 원인은 여러 가지 발생할 수 있는데, 대부분 시스템 부하가 발생되어 lockTime이 길어진 것으로 보아야 한다. 한가지 분명한 사실은 쓰기 연산이 발생할 때마다 lockTime은 증가하며, 전체 시간 대비 lockTime이 증가하면 시스템 부하가 발생하였다고 예측할 수 있다.

[표 3]의 currentQueue는 MongoDB가 쓰기 락이 수행될 경우, 쓰기 락에 의해 대기 중인 연산을 의미한다. 명칭 큐로 설정되어 있어서 MongoDB가 큐에 연산을 넣고 해당 연산을 빼내어 처리한다고 판단할 수 있으나, 소스 코드상으로 볼 때, 연산을 요청한 클라이언트 리스트에서 해당 정보를 취득한다. 즉, 클라이언트가 요청할 때, 한 개의 쓰레드가 생성되는데, 이러한 쓰레드 리스트 중에서 현재 락이 걸린 연산들의 개수를 리턴 한다.

[표 3]의 activeClients는 연산을 요청한 클라이언트의 개수를 저장하는 것으로, 읽기 연산과 쓰기 연산을 요청한 클라이언트의 개수가 된다. 클라이언트의 한 개의 요청은 서버의 한 개의 쓰레드를 만들어 클라이언트의 요청이 할당된다. 서버에 쓰기 락이 활성화되지 않았다면, 서버가 생성한 쓰레드는 락이 걸리지 않는다. cuurentQueue와 activeClients는 모두 동일한 서버의 클라이언트 리스트에서 정보를 취득하지만, 임의의 클라이언트가 락이 걸려 있는지에 따라 데이터 값의 차이가 나타난다. 따라서, currentQueue의 값이 activeClients의 값 보다 클 수 없다.

MongoDB의 구성 요소인 mongos는 mongod와 달리 클라이언트의 역할을 담당하므로, lockTime, currentQueue, activeClients의 값이 나타나지 않는다. Global Lock은 서버 관점에서 클라이언트가 요청한 연산에 대한 락 상태를 보여주는 것이다. 따라서, [표 3]의 값은 mongod에서만 유효하다. 또한, [표 3]는 각각의 mongod에 따라 다른 값이 나타난다. MongoDB가 말하는 Global Lock은 한 개의 mongod 프로세스에서 발생하는 값을 의미한다. 만약 여러 개의 노드로 구성된 시스템에서의 Global Lock의 총합을 알고자 한다면, 각 mongod 프로세스에서 [표 3]의 globalLock 값을 취득한 뒤, 합쳐야 한다.

MongoDB는 메모리 데이터베이스의 성격을 가지고 있다. 따라서, 메모리에 데이터를 쓰는 시간 만큼의 쓰기 락이 주어진다. 이는 MongoDB의 일관성 정책이 NORMAL인 경우에 해당된다. 만약 일관성이 NORMAL이 아닌 SAFE라면 쓰기 락이 시간도 같이 올라간다.

쓰기 락은 slave에서도 사용된다. Slave에서의 쓰기 락은 Oplog의 동기화와 관련 있다. Master와의 Oplog 동기화가 발생되었다면, slave는 쓰기 락을 발생시키고 Oplog의 동기화가 완료되었을 경우에 쓰기 락을 해제한다. 만약, 읽기 성능을 위해 Slave_OK를 이용하여 slave에서 읽기 연산을 수행하는 경우라면, Oplog의 동기화 시간 동안 읽기 연산이 쓰기 락이 해제될 동안 대기 상태에 빠진다는 것을 의미한다.

앞서도 논의하였지만, 쓰기 락은 master에서 매우 빠르게 진행되기 때문에, 전체 적인 시스템 영향을 많이 준다고 보기 어렵다. 다만, 쓰기 락을 컬랙션 또는 DB 별로 나누어 관리하는 것이 NoSQL의 비정규화 락에 부합되는데, 이 부분이 2.0에서 구현되지 않은 것이 아쉽게 느껴진다. 하지만  MongoDB의 2.2 버전에서 이 부분이 수정되어 데이터베이스 별로 쓰기 락이 별도 존재한다. 이 부분을 더 세밀하게 나누어 데이터베이스가 아닌 컬랙션 별로 쓰기 락을 구현하는 것도 다음 버전에서 기대해 본다.

 

이전글 : MongoDB의 락 시스템

 


  • Facebook
  • Twitter
  • Delicious
  • LinkedIn
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS
  1. 아직 댓글이 없습니다.
  1. 엮인글들이 아직 없습니다.