DKU-StarLab / leveldb-study

LevelDB Analysis, Backgrounds, Practice and Tuning
https://sslab.dankook.ac.kr/leveldb-wiki/
35 stars 15 forks source link

About Read amplification of leveldb db_bench #15

Closed sss654654 closed 2 years ago

sss654654 commented 2 years ago

db_bench의 벤치마크와 옵션들을 건들이며 실험하던 도중 자습을 통해 '이렇게 구하는 것인가?'하고 짐작만 하고 구했던 RA(읽기증폭)가 실험 중 성능면에서 이상한 부분을 보여 계산하는 부분에서 제가 잘못 생각하고 있나 하여 조언을 받고자 이슈를 올리게 되었습니다.

leveldb의 db_bench의 결과에서 RA(읽기 증폭)을 구하기 위해서 작년도 rocksdb festival자료의 도움을 받았었습니다. 아래는 해당 자료의 일부분입니다.

image

또한 해당 실험에서 언급하는 Load된 data block들의 총 byte수를 구하기 위하여 저번 숙제중 하나였던 image 를 참고하여 실험을 진행하였습니다.

[Load] ./db_bench --benchmarks="fillrandom" --use_existing_db=0 —num=10000000

image

[A] ./db_bench --benchmarks="seekrandom,stats" --use_existing_db=1 —num=10000000 --cache_size=512000000 (cache크기를 비교한 여러 결과가 있으나 질문의 목적은 RA를 구하기 위한 것 이므로 한개의 실험 결과만 올리도록 하겠습니다.)

image

실제 read에 사용된 총 byte 수 / load된 data block의 총 byte 수 =>(10+217+445)/630(FileSize)

RA를 구하는 방법이 잘못되었다면 조언을 해주시면 감사할 것 같습니다.

또한 이 질문 외에도 별도로 db_bench.cc 소스코드상에서 옵션 중 하나인 use_existing_db에 대한 개념을 아직 이해를 못한 것 같습니다!! 이에 대해서 간단히 설명해주셨으면 합니다.

min-guk commented 2 years ago

image

우선 학생분들이 증폭에 대해서 많이들 여쭤봐서 개념적으로 먼저 설명을 드리겠습니다. 또한 위의 D-mooc 강의자료를 참고하시길 바랍니다.

1) WAF 쓰기증폭 LSM-tree는 유저가 입력 키를 잘 정리해서 저장하기 위해, 내부적으로 많은 작업을 진행합니다. 우선 WAL을 쓰고, Memtable에 키들을 모아놓다가, Flush를 하고, 나중에는 Compaction도 합니다. 따라서 유저가 요청한 키를 한번만 DB(디스크)에 쓰지 않고, WAL도 쓰고, Flush를 통해 L0에도 쓰고, Compaction을 통해 하위 레벨로 반복해서 쓰는 것이 WAF입니다. 즉, DB에서 유저가 쓰려고 했던 양보다 더 많은 양을 쓰는 것이고, 더 많은 양을 쓴다고 하여 쓰기증폭이라고 합니다.

2) RAF 읽기증폭 LevelDB는 여러 레벨에 걸쳐 키를 저장합니다. 또한 대부분의 레벨은 서로 key range가 겹칩니다. 그래서 우리가 하나의 키를 찾으려고 했을 때, LevelDB는 "memtable -> immutable memtable -> L0 -> L1 -> L2 ...." 이렇게 우리가 원하는 키를 찾을 때까지 하위 레벨로 내려갑니다. 유저는 단순히 하나의 키를 읽으라고 했는데 한번만 읽는 것이 아니라, 여러 레벨에 걸처 탐색과 읽기 작업을 진행하기 때문에 이를 읽기 증폭이라고 합니다.

3) SAF 공간증폭 LevelDB는 여러 레벨에 걸쳐 키를 저장합니다. 또한 대부분의 레벨은 서로 key range가 겹칠 뿐만 아니라, key또한 겹칩니다. 따라서 유저가 하나의 키에 대해 여러번 update를 진행했다면, out-of-place 방식으로 update를 진행하는 LSM-tree의 특성에 따라 쓸모없는 데이터가 하위레벨에는 존재하겠죠. Compaction을 통해서 가비지 콜렉션을 진행하지만, 그럼에도 불구하고 중복된 필요없는 데이터가 저장되어있으므로 공간증폭이 발생합니다. 결국 유저가 저장하려고 했던 데이터의 양보다, DB는 보다 많은 양의 데이터를 스토리지에 저장해야하고, 이를 공간증폭이라고 합니다.

min-guk commented 2 years ago

그리고 질문에 대한 답을 드리도록 하겠습니다.

leveldb db_bench에 나오는 read/write은 compaction stat입니다. 따라서 해당 레벨에서 compaction시, 얼마 만큼을 읽었고, 얼마 만큼을 썼는 지를 의미합니다. 따라서 학생분께서 기대하는 "readrandom benchmark에 의해 해당 레벨에서 얼마 만큼을 읽었는가"에 대한 정보가 아닙니다. 또한 LevelDB 소스코드를 수정하지 않고서, db_bench에서 제공하는 정보만으로는 SAF는 구할 수 있지만, WAF와 RAF를 구할 수 없습니다.

min-guk commented 2 years ago

use_existing_db는 우리가 이전에 사용하던 db를 계속해서 사용할 것이냐, 지우고 새로 사용할 것이냐에 대한 옵션입니다.

기본값은 0(false)이며, false라면 기존의 DB를 지우고 유저 벤치마크에 따라 DB를 새로 만들고 사용합니다. 1(true)로 설정하면, 유저가 이전에 사용했던 db를 이어서 사용하게됩니다.

따라서 fillseq/random등으로 DB를 채워놓고, 쓰인 상태가 동일한 조건의 DB에서 여러 조건의 읽기 실험을 진행할 때 "use existing db"옵션을 사용합니다.

min-guk commented 2 years ago

학생들에게 WAF/RAF/SAF와 db_bench 옵션들에 대해서, 이전에 보다 상세하게 설명하지 못했던 것이 많이 아쉽네요. 너무 많은 양을 다루다 보니, 어쩔 수 없이 빠진 내용들이 있는 것 같습니다. 구글링을 해봐도 잘 모르겠는 내용들이 생기시면, 다들 부담 갖지 않고 편하게 이슈로 질문해주시길 바랍니다.

감사합니다.

sss654654 commented 2 years ago

확인했습니다! 감사드립니다!!