회사에서 발표한 자료를 공유합니다.
간단한 로그 기반 DB를 만들어봅시다.
db_set (key,value) {
// database 라는 파일에 ${key},${value} 로 만들어서 append 한다.
}
db_get (key) {
// database 에 첫번째 argument 로 시작하는 모든 줄을 찾는다.
// 마지막 라인의 value를 return 한다.
// 혹은 뒤에서 부터 읽어온다
}
ternimal
db_set 1 jaquan1
db_set 2 jaquan2
db_set 1 jaqquan1_update
db_get 1 -> jaqquan1_update
db_get 2 -> jaquan2
database file
1,jaquan1
2,jaquan2
1,jaquan1_update
index:= map[string]int{}
db_set (key,value) {
// database 라는 파일에 ${key},${value} 로 만들어서 append 한다.
// append 시 return 으로 디스크에서 삽입된 라인 수를 받는다.
// index[key] = offset
}
db_get (key) {
// offset := index[key]
// 없으면 null 로 return
// offset 으로 database 에 접근해서 한줄을 읽는다.
// value를 return 한다.
}
terminal
db_set 1 jaquan1
db_set 2 jaquan2
db_set 1 jaquan3
db_get 1 -> jaquan3
db_get 2 -> jaquan2
database file
1,jaquan1
2,jaquan2
1,jaquan3
...
index in memory
{
"1":3L
"2":2L
}
segmentId:= 0
db_set (key,value) {
// database_{segmentID} 라는 파일에 ${key},${value} 로 만들어서 append 한다.
// append 시 return 으로 disk 에서 라인 수를 받는다.
// index_{segmentID}[key] = offset
// database_{segementID} 파일이 특정 크기를 넘어가면 segmentID 를 올린다.
}
db_get (key) {
// key 를 찾을때까지 segmentID 를 순회한다.
// while (index_{segmentID}[key)){
if segmentID == 0 {
return null
}
segmentID-=1
}
// offset 으로 database_{segmentID} 에 접근해서 한줄을 읽는다.
// value를 return 한다.
}
segment 단위를 3L 으로 한정한다고 가정하자
terminal
db_set 1 jaquan1
db_set 1 jaquan2
db_set 1 jaquan3
// segement id 1 증가
db_set 1 jaquan4
db_set 1 jaquan5
db_set 1 jaquan6
// segemetn id 1 증가
db_set 1 jaquan7
db_set 1 jaquan8
db_get 1
-> index_{2} 에서 찾아서
-> jaquan8
db_get 2
-> index_{2} 에서 찾고
-> index_{1} 에서 찾고
-> index_{0} 에서 찾고
-> 없네!
database_{0}
1,jaquan1
1,jaquan2
1,jaquan3
database_{1}
1,jaquan4
1,jaquan5
1,jaquan6
database_{2}
1,jaquan7
1,jaquan8
index_0 (memory)
{
"1": 3L
}
index_{1} (memory)
{
"1": 3L
}
index_{2} (memory)
{
"1": 2L
}
... 위와 같음
background_compaction_cron_job (){
// 연속된 version의 segement 파일들을 가지고 와서
// key 를 최신화 한다.
// 컴팩션된 오래된 파일과 인덱스는 제거한다.
}
background_compaction_cron_job()
database_0
1,jaquan1
1,jaquan2
1,jaquan3
database_1
1,jaquan4
1,jaquan5
1,jaquan6
⇒ compaction_database_{0,1}
1,jaquan6
⇒ compaction_index_{0,1}
{
"1": 1L
}
앞서 다뤄본 고민들을 개선한 LSM table(with sstable) 을 소개합니다.
in memory 안에 balanced b tree 형태로 key, value 들을 들고 있는 자료 구조를 뜻한다.
disk 안에 key 를 sorted 하게 보관하고 있는 segment
file full scan query 를 개선하기 위해서 offset key index 를 들고 있는다.
다만, sorted 되어있기 때문에 부분적으로만 들고 있을 수 있다.
예를 들어서 key 2111
은 memeory index에 없어도 유추해서 찾을 수 있다.
또한 range query 를 수행 할 수 있다.
주기적으로 compaction 을 통해 최적화를 진행한다.
0.key,value 가 들어오면
1. memtable, 임시 로그 파일에 삽입
2. memtable 의 사이즈가 일정 이상이면 sstable 로 변환
2. 주기적으로 segment 단위당 머지를 수행