본문 바로가기
연구노트

SingleStoreDB 성능 이야기

by 에이플랫폼 [Team SingleStore Korea] 2023. 8. 31.

SingleStoreDB 를 처음 사용하게 되면서 가장 먼저 들었던 생각은 “아! 빠르다” 입니다. Oracle, MySQL, PostgreSQL 등 내노라 하는 RDBMS 에서도 왠만큼 큰 장비가 아니면 느낄 수 없는 “빠름”을 SingleStoreDB 는 그저 보통의 컴퓨팅 파워를 가지고 있는 작은 시스템에서도 쉽게 확인할 수 있습니다.

 

그 이유가 무엇일까요?

 

첫번째로 SingleStoreDB 는 Shared Nothing 구조의 분산(Distributed) DB 이기 때문입니다.

SingleStoreDB Cluster 에서 Leaf 노드들이 실제적인 데이터를 나누어 저장하고 있습니다. 만일 Leaf 노드가 4대라면 각각 1/4 씩의 데이터를 균등 배분하여 저장하고 있는 셈이죠. NoSQL 의 샤딩(Sharding) 개념과 유사합니다.

Query 및 DML 은 Aggregator 에서 전송된 SQL에 의해 각각 자신이 속한 Leaf 노드에서 수행되게 됩니다. 여기에 각 Leaf 노드는 파티션(Partition) 이라는 단위로 나눠어져서 Query 및 DML 수행시 병렬도의 기준이 됩니다. Oracle Exadata 에서 Query 가 Cell Server 로 오프로딩(offloading) 되어 수행되는 것과 유사한 개념이며 분석(Analytics) 용도에서 Parallel Query & DML 이 SingleStoreDB 에서 빠르게 수행되는 첫번째 이유입니다.

 

두번째 이유는 컬럼스토어(Columnstore)를 제공하기 때문입니다.

데이터 크기에 따라 다르지만 일반적으로 SingleStoreDB 는 컬럼을 종/횡으로 분할 및 압축하여 저장하고 있습니다. 즉 모든 컬럼별로 컬럼 세그먼트(Column Segment) 를 만들고 100만 행(rows)마다 다시 분할하여 로우 세그먼트(Row Segment)로 나누어 압축된 형태의 파일로 관리합니다. 세그먼트 마다 각각 컬럼의 최소값, 최대값 등 통계 정보를 갖고 있기 때문에 꼭 필요한 범위의 컬럼과 행만을 선택하여 읽을 수 있도록 합니다. 예를 들어 1TB 의 데이터는 전체적으로 이미 100~200GB 크기로 압축되어 여러 세그먼트 파일에 저장되어 있고, Query 수행 시 꼭 필요한 10~20GB 의 특정 컬럼/로우 세그먼트들을 모든 Leaf 노드의 각 파티션별로 분할하여 병렬로 읽게 되므로 성능이 비약적으로 향상될 수 있습니다. 마치 Oracle Exadata 에서 Storage Index 를 통해 대다수 필요없는 Block은 읽기를 수행하지 않고 필요한 Block 만을 읽게 하는 Smart Scan 기능과 유사한 개념입니다.

 

세번째는 컬럼스토어의 SIMD(Single Instruction Multiple Data) 기능 덕분입니다.

컬럼 조건에 대한 필터링(Filtering), 컬럼별 집계(Aggregation) 은 SISD(Single Instruction Single Data)로 수행될 때보다 SIMD을 사용할 때 2~3배 이상 성능 향상이 있습니다. SingleStoreDB 는 Intel 호환 시스템에서의 AVX2 Instruction 을 이용하여 SIMD 를 구현하고 있습니다.

 

네번째 이유는 인메모리 로우스토어(In-memory Rowstore) 이기 때문입니다.

애초에 SingleStoreDB 는 MemSQL 이란 이름을 갖고 있었던 것에서도 알 수 있듯이 로우스토어 테이블은 메모리가 주 저장소인 메모리 DB 이기 때문에 OLTP 및 Data Ingestion 에서 강점을 가지고 있습니다. 특히 인덱스의 경우 Index Maintenance 및 Lock 처리에서 상대적으로 속도가 떨어지는 B-Tree 가 아닌 Lock-free Skiplist 구조를 채용하고 있어 Index Split 으로 인한 Lock 경합이나 관리 부하없이 Index Seek & Scan 이 원활히 수행됩니다.

 

다섯번째는 컬럼스토어와 로우스토어의 결합에서 옵니다.

디스크 기반의 컬럼스토어 테이블에 DML 이 발생하면 즉시 해당 세그먼트에 변경분을 기록하는 것이 아니라 메모리에 로우스토어 형식의 세그먼트(Rowstore Backed Segment)를 만들어 사용합니다. 일정 정도 이상의 DML이 쌓여 해당 메모리가 커지게 되면 자동으로 백그라운드 쓰레드(Flusher/Merger) 에 의해 플러쉬(Flush)되고 이후 기존의 컬럼세그먼트와 병합(merge)됩니다. 따라서 동시적으로 발생하는 대량의 DML 도 컬럼스토어에서 충분히 수용할 수 있으며 파일에 대한 동시 Read-Write, Write-Write Lock 경합 문제를 피할 수 있게 됩니다.

 

여섯번째는 분산 DB, 인메모리 DB 의 특성에서 비롯된 Lock-free 환경 때문입니다.

일반적인 RDBMS 는 디스크가 주 데이터 저장소이고 메모리가 Cache 역할을 합니다. 그래서 가급적 적게 읽고 많이 caching 시키며 자주 사용되는 데이터는 cache miss 가 발생하지 않도록 노력합니다. 이렇게 유지 관리하기 위해 내부적으로 해당 cache memory 및 리스트를 lock, latch, mutex 등으로 보호하여 동시성 문제를 해결해야 하는 등 오버헤드가 만만치 않습니다. SingleStoreDB 는 이렇게 동시성, 병렬성에 영향을 주는 Buffer cache 없이 로우스토어는 바로 주 저장소인 메모리에서, 컬럼스토어는 파일에서 각각의 Leaf 노드 및 파티션에서 꼭 필요한 양의 데이터만을 직접 읽고 해당 결과를 취합하여 리턴하므로 타 RDBMS 의 Buffer Cache 관리 에서 오는 성능 오버헤드가 발생하지 않습니다.

일곱번째로는 Compute-Data 분리 구조의 Cluster 환경입니다.

OLTP 업무 위주로 빠른 Insert 와 가벼운 조회 가 주일 경우는 Rowstore 위주의 많은 Aggregator 노드로 Scale-out 정책을 사용하고, 대용량의 데이터 처리가 주용도일 경우엔 Columnstore 위주의 많은 Leaf 노드로 Scale-out 정책을 사용할 수 있어 성능 향상의 유연성을 쉽게 확보할 수 있습니다.

여덟번째는 분산 DB, 컬럼스토어의 장점에서 비롯됩니다.

컬럼스토어를 액세스해야 할 때 꼭 필요한 컬럼만을 읽게 되므로 일반적인 행기반(Row-based) RDBMS 가 전체 행 데이터를 읽는 것에 비해 속도가 빠를 수 밖에 없습니다. 여기에 각 Leaf 노드의 파티션별로 조인(Join) 및 집계(Aggregation)가 병렬로 수행된 후 크게 작아진 결과 집합만을 Aggregator 에게 전송하므로 속도가 빠릅니다.

일반 RDBMS에서는 최종적으로 필터링되어 집계에 참여하게 되는 데이터를 작게 만들기 위해 Query를 튜닝해야 하는 필요가 많아지게 됩니다. SingleStoreDB 는 아키텍처상 Query 가 병렬 수행되는 과정중에 Map-Reduce 사상이 자연스럽게 구현되며 결과 집합이 작아지게 되므로 별도의 튜닝없이도 기본적으로 성능상 이점을 가져갈 수 있습니다.

이상으로 SingleStoreDB 의 독특한 아키텍쳐로 인한 8가지 주요 성능 개선효과에 대해 간략히 알아보았습니다.