거의 모든 noSql DB가 그러하듯이 MongoDB도 pre-allocation으로 데이터 저장처리를 한다.

insert만 있고, update/remove가 없는 경우 아무런 상관이 없는데,

반대의 경우엔 이 부분이 문제가 된다.


MongoDB가 document를 insert할 때 padding 사이즈가 그리 크지 않은데,

(collection의 padding factor 기준으로 지정하는 방식인 듯)

문제는 이렇게 사이즈가 잡힌 document가 삭제되었을 경우,

해당 공간을 재사용할 가능성이 크게 줄어들 수 있다는 것.


예를 들어 500바이트짜리 document를 넣으면서 공간을 600바이트 할당했을 경우,

그 document가 삭제되면 600바이트짜리 공간이 확보되는데,

새로 insert되는 document의 사이즈가 610바이트이면 그렇게 확보된 600바이트의 공간을 활용하지 못하므로,

새로 610바이트를 할당하게 되는 것이다.


실제 사용시 예를 들어, 

어떤 로그를 저장하는 컬렉션이 있고, 

로그를 항상 최근 90일치를 유지하는 daily queue같은 형태의 컬렉션이라고 하면,

90일이 될때까지는 insert만 일어나다가, 

91일째부터 하루치 데이터의 remove가 일어나고, insert가 이루어지게 된다.


이것이 계속 반복되다 보면 storageSize가 말도 안되게 늘어나는 현상을 목격할 수 있다. (내가 증인)


이걸 어떻게 하나 계속 검색해보다가, 

compact나 repairDatabase등을 기웃거려봤지만,

대용량의 경우 저건 언제 끝날지 모르는 커맨드이고,

해당 커맨드가 실행되는 동안 전체 DB에 block이 걸린다. (말도 안되는 downtime!)


그리하여 MongoDB에 사후 compaction은 없다는 결론을 내리게 되었다.


하지만 MongoDB에는 이걸 어떻게 커버하기 위해 사전에 처리할 수 있는 방법이 있는데,

MongoDB 2.2 부터 지원하는 usePowerOf2Sizes 두둥.


remove가 빈번하거나 document 사이즈가 변경되는 update가 자주 일어나는 collection에서 storage 재사용 확률을 높이는 방식인데,

document 할당시 2의 제곱의 사이즈로 할당하는 방식이다.

예를들어, 511바이트짜리 document가 들어오면 512바이트로 할당하지만,

513바이트짜리 document가 들어오면 1024바이트로 할당한다.


컬렉션에 해당 flag를 세팅하는 방법은 아래와 같다.

mongo> db.runCommand({collMod: 컬렉션_이름, usePowerOf2Sizes: true})


// 확인하는 법은 stats() 명령의 결과에 나오는 useFlags가 1이면 usePowerOf2Sizes 가 세팅된 상태.

// 0 이면 세팅 안된 상태.



얼핏 보기에 엄청난 공간의 손실이 있을 것으로 보이는데, 

위에서 말한 특정 기간동안의 로그를 항상 보존하는 daily queue같은 식의 컬렉션 같은 경우 storageSize 재사용률을 크게 높여준다.

(같은 방식이라도 로그포맷이 너무나 일정하여 padding factor가 한없이 1.00000에 가깝다면 별 의미가 없겠지)


아래는 직접 테스트해 본 결과.

MongoDB 버전은 2.4.5



compaction ratio = storageSize / size

fileSize = db.stats()에 있는 fileSize

0 - usePowerOf2Sizes 세팅 안함

1 - usePowerOf2Sizes 세팅함


최초 10일치 데이터 insert


 

 size

 storageSize 

 compaction ratio 

 fileSize 

 0

 71505504

 86310912

 1.207 

 469762048 

 1

 107784656

 123936768 

 1.150 

 1006632960 


동일한 데이터인데 사이즈 차이가 많이 난다.

2의 제곱으로 할당하니까 당연한 결과다..

하지만 remove/insert가 여러번 일어나면 느낌이 달라진다.


아래는 remove / insert를 20일치 수행한 결과다.



 

  size

 storageSize 

 compaction ratiod 

 fileSize 

  0

 90869664 

 243314688 

 2.678 

 1006632960 

  1 

 134251040 

 174735360 

 1.302 

 1006632960 


데이터 사이즈는 여전히 크지만 storageSize가 역전된 상태이다.

usePowerOf2Sizes가 설정되지 않은 컬렉션의 경우, 

remove되어 사용되지 않는 공간 중 재사용된 공간이 적어서 어쩔 수 없이 새로 할당되는 공간이 많아졌기 때문에 storageSize가 커진 것이다.



결론. remove 혹은 document size가 변하는 update가 많은 collection의 경우 usePowerOf2Sizes 를 true해놓고 쓰는 것이 장기적인 관점에선 좋다고 본다.





[참조]

http://docs.mongodb.org/manual/reference/command/collMod/#usePowerOf2Sizes

http://www.slideshare.net/mongodb/use-powerof2sizes-27300759


















Posted by bloodguy
,