[발 번역] Leveled Compaction in Apache Cassandra

해당 블로그는 KT Ucloud의 지원을 받고 있습니다.

해당 글은 http://www.datastax.com/dev/blog/leveled-compaction-in-apache-cassandra 의 글을 발 번역한 것입니다. HBase 나 Cassandra의 경우 Compaction이라는 단계가 있습니다. Write 속도를 빠르게 해주기도 하고 Locality를 높일 수 있으므로 성능을 높여주는 요소이기도 하지만, 또한 자바의 GC 처럼, 한번 Major Compaction이 일어나면, 시스템에 큰 부담을 주는 기능이기도 합니다. HBase의 경우 내부적으로 HDFS를 사용하고 있고, Cassandra의 경우는 로컬 파일시스템을 사용합니다. mongodb 역시 로컬 파일시스템을 사용합니다. GC가 꾸준히 발전하는 것처럼 Cassandra에서도 Leveled Compaction 이라는 기능을 추가했습니다.(다만, 아직까지 Major Compaction 일 때 큰 성능 저하는 피할 수 없는 듯 합니다.) 그럼 Apache Cassandra에서 사용하는 Leveled Compaction에 대해서 간략하게 알아보도록 하겠습니다. 오역에 주의하세요.

Leveled Compaction in Apache Cassandra

By Jonathan Ellis | October 10, 2011

Introduction to Compaction

카산드라의 로그 스토리지 엔진은 모든 업데이트를 sstables 이라는,순차적으로 디스크에 저장하는 방식을 이용하여, 놀라운 성능과 application-transparent compression 같은 기능을 가능하게 합니다. 이미 쓰여진 데이터를 업데이트 하지 않고( 이것은 Random I/O를 요구하기 때문에 ), 새로운 sstable 에 새로운 버전의 컬럼을 삽입하거나 업데이트 정보를 추가합니다.(역자 주, sstable 은 딱 한번만 쓰여지기 때문에, 컬럼의 업데이트 역시 insert 같이 처리됩니다. 그래서 하나의 컬럼 내용을 여러 sstable에서 읽어와서 최종 버전의 값을 확인해서 보여주게 됩니다. )

Figure 1: adding sstables with size tiered compaction

Figure 1: adding sstables with size tiered compaction

그래서, 시간이 지나면, 많은 버전의 row 가 다른 sstable 들에 존재할 수 있습니다. 각 버전들은 각각 다른 부분의 컬럼을 가지고 있습니다. 하나의 row를 읽기 위해서는 많은 파일을 찾아서 그 결과를 합쳐서 보내야만 합니다.

읽기 속도 악화를 방지하기 위해서, sstable들을 합치는 compaction 이 백그라운드로 동작합니다.( 각 sstable들에 들어있는 row들이 primary key로 정렬되어 있어서  Random I/O 없이,  해당 작업을 효과적으로 수행할 수 있습니다. )

Tiered Compaction

Figure 2: sstables under size-tiered compaction after many inserts

Figure 2: sstables under size-tiered compaction after many inserts

카산드라의 size-tiered compaction 전략은  Google’s Bigtable paper 에 묘사된 것과 매우 유사합니다. 비슷한 사이즈의 sstable들이 충분히 있으면(기본적으로 4개), 카산드라는 그 sstable 들을 합칠 것입니다. figure 1 에서 각 녹색 바는 하나의 sstable을 나타내고, 화살표는 compaction을 의미합니다. 새로운 sstable이 생성되고, 처음에는 아무일도 발생하지 않습니다. 4개가 되고 나면, 서로 합치기 시작합니다. 그리고 다시 새로운 4개가 발생하면 다시 반복하게 됩니다. Figure 2는 나중에 기대할 수 있는 결과를 보여줍니다. 2 tier의 sstable 들이 합쳐져서 3 tier의 sstable을 생성하고, 3 tier들이 합쳐져서 4 tier sstable을 생성합니다. 이게 계속 됩니다.

size-tiered compaction 는 update 가 많은 환경에서 3가지 문제점이 있습니다.

  • 성능이 일정하지 못합니다. 하나의 row 가 얼마나 많은 sstable에 걸쳐있을지 모르기 때문에, 최악의 경우에는, 모든 sstable 에서 해당 row를 찾아야 할지도 모릅니다.
  • 안쓰는 컬럼에 대해서 얼마나 빨리 병합해서 없앨지에 대해서 보장하지 않기 때문에, 상당한 양의 공간이 낭비될 수 있습니다. 특히 높은 비율로 삭제가 발생하면, 특별히 발생하기 쉽습니다.
  • 반복되는 Compaction으로 인해서 쓸모 없는 sstable이 병합되어  완전하게 쓰여지기 전까지, 너무 커지는 것도 공간에 문제가 됩니다.  최악의 경우에는 굉장히 큰 하나의 sstable 이 지울 수 있는 삭제된 row들이 없을 수 있습니다. 카산드라는 compaction이 진행될 때, 병합된 sstable을 쓰기 위해서 그 만큼의 빈 공간이 필요합니다.

Leveled Compaction

Figure 3: adding sstables under leveled compaction

Figure 3: adding sstables under leveled compaction

카산드라 1.0에서는 구글의 Chromium 팀에서 개발한 LevelDB 에 기반한  Leveled Compaction 전략을 제공하고 있습니다.(역자 주: 저도 이래서 이름이 그런건 처음 알았네요.)

Leveled compaction 은 sstable을 “levels” 로 그룹화되는 고정된 크기에 상대적으로 적은 크기(기본적으로 5MB)로 생성합니다. 그리고 각 레벨 내에서는 데이터가 겹치지 않는 다는 것을 보장하고, 각 레벨은 이전 레벨보다 10배 크기가 큽니다.

Figure 3에서 새로운 sstable이 첫번째 레벨에 저장이 됩니다. 그리고 L1에서 즉시 sstable 들은 compaction 됩니다.(파란색) L1이 가득 찼을 때, 추가된 sstable들이 L2로 올라가게 됩니다.(보라색). 상당 수의 L1에서 생성된 sstable 들이 compaction 되면서 L2 로 올라가게 됩니다.(이 때, 데이터가 겹칠 수 있습니다.) 데이터가 더더욱 추가되면, leveled compaction의 결과로 Figure 4 처럼 되게 됩니다.

Figure 4: sstables under leveled compaction after many inserts

Figure 4: sstables under leveled compaction after many inserts

tiered compaction 을 이용해서 위의 문제를 해결할 수 있습니다.

  • Leveled compaction 은 모든 읽기의 90%를 하나의 sstable 에서 히트시킬 것입니다.( 거의 같은 크기의 row 라고 가정했을 때 ), 최악의 경우에도 레벨의 최대 수에 한정됩니다. 예를 들어, 10TB 데이터를 위해서 7레벨 정도 입니다.
  • 삭제된 row 에 의해서 10% 정도 공간이 낭비될 수 있습니다.
  • compaction을 위해서 임시로 사용되는 공간을 위해서 오직 sstable의 10배 크기만 남아있으면 됩니다.

compaction_strategy 옵션을 LeveledCompactionStrategy로 설정하고, Column Family를 생성하면(업데이트 함으로써) Leveled compaction 을 활성화 할 수 있습니다. 존재하는 Column Family를 수정할 때 백그라운드로 현재 존재하는 sstable들의 레벨링이 수행되는 동안 , 읽기와 쓰기는 정상적으로 수행됩니다.

Considerations

leveled compaction이 위의 얘기들을 보장해주도록 해주기 때문에, size-tiered compaction 보다 대략 2배 정도 많은 i/o를 수행합니다. 주로 쓰기 중심의 작업에서, 거기에 삭제된 row 가 거의 포함되지 않았다면, 이 추가적인 i/o는 어떠한 도움도 되지 않습니다.

Leveled compaction 은 concurrent_compactors 옵션을 무시합니다. 병렬 compaction은 compaction 시스템이 큰 sstable 셋을 처리한다고 바쁜 동안에, 백로그에 작은 compaction 셋들이 임시적으로 멈추어 있는 tiered compaction의 문제를 피하기 위해서 디자인되었습니다. Leveled compaction에는 모든 compaction이 거의 같은 사이즈를 가지기 때문에 이러한 문제가 발생하지 않습니다. Leveded compaction은 하나의 스레드가 몇개의 sstable을 처리할 것인지를 결정하는 multithreaded_compaction 옵션을 compaction의 속도 향상을 위해서 이용합니다. 그러나, 대부분의 compaction 튜닝은 compaction_throughput_mb_per_sec 을 이용해서(기본: 16)  compaction의 속도를 조절합니다.