본문 바로가기

Google Cloud Blog

Google BigQuery의 인메모리 쿼리 execution

BigQuery는 고성능의 페타바이트 규모 분석 데이터베이스입니다. 이러한 수준의 성능을 달성하기 위해 BigQuery는 완전히 메모리에서 쿼리를 실행합니다. 이에 반해 대부분의 데이터베이스 및 데이터 처리 시스템은 디스크와 메모리 모두에서 작동하는 하이브리드 실행기를 사용하여 확장성을 달성합니다. 한편 BigQuery의 실행 엔진은 단순하고 순수한 메모리 내 연산자를 구축하고 확장 가능한 데이터 재분할 또는 "셔플"을 통해 페타바이트 규모의 분석을 달성합니다. 본 글에서는 BigQuery 셔플을 자세히 살펴보고 Jupiter와 같은 Google의 페타비트 규모 네트워킹 기술을 활용하여 고성능 인메모리 쿼리 실행을 가능하게 하는 방법을 살펴봅니다.

Shuffle은 Hadoop 및 Spark에서 Google Cloud Dataflow에 이르는 모든 분산 데이터 처리 시스템의 핵심 요소입니다. Shuffle 단계는 크고 복잡한 조인, 집계 및 분석 작업을 실행하는 데 필요합니다. 예를 들어, MapReduce는 매핑된 키를 기반으로 "map" 단계와 "reduce" 단계 간에 데이터를 재배포하는 메커니즘으로 셔플(Shuffle)을 사용합니다. 즉, 대규모 계산을 지원하기 위해 섞인(shuffled) 데이터는 일시적으로 원격 서버에 저장됩니다. 이를 통해 "map" 및 "reduce" 단계를 분리할 수 있으며 대규모 데이터 처리를 지원하는 핵심 원칙입니다. 하지만 shuffle 단계는 악명 높게 느립니다. Hadoop 엔지니어는 MapReduce를 실제로 작은 map, 거대한 shuffle, 작은 reduce라고 불러야 한다고 농담을 합니다.

우리는 다양한 BigQuery의 쿼리 특성 및 요구사항으로 인해 Shuffle에 대해 처음부터 다시 생각하게 되었습니다. 2014년, BigQuery Shuffle은 메모리 기반(디스크 스풀링 지원 포함)이며 Google 데이터 센터 네트워킹 기술용으로 특별히 설계된 인프라로 이전되었습니다. 또한 해시 조인과 같은 특정 분산 작업을 효율적으로 처리할 수 있는 유연한 데이터 전달 시스템으로 설계되었습니다. 이 프로젝트는 데이터 전송 기술에 대한 Google의 다년간 연구개발의 결정체입니다.

메모리 내 BigQuery 셔플은 원격 메모리 호스팅 전용 노드 집합에 쿼리 처리의 다양한 단계에서 생성된 중간 데이터를 저장합니다. 데이터 처리 작업의 중간 결과를 유지하는 것은 Spark(RDD) 또는 Piccolo(분산 해시 세트)와 같은 많은 시스템에서 일반적입니다. 그러나 BigQuery는 셔플 작업과 긴밀하게 통합된 형태의 메모리 내 중간 결과와 관련하여 다른 방향을 취합니다.

BigQuery 셔플에 의해 정의된 데이터 재분할 추상화는 Producer가 재분할할 데이터를 생성하고 Consumer가 재분할된 데이터를 수신하며 컨트롤러 프로세스가 Shuffle을 관리하는 세 가지 항목으로 구성되며 다음과 같이 작업을 정의합니다.

Producer (producer_id) {  
  void SendRow(row, consumer_id) : Called to send a row to a given consumer  
                                   on behalf of this producer.
}
Consumer (consumer_id) {  
  string ReceiveRow() : Called to receive one row for this consumer.
}
Controller {  
  StartShuffle() : Called before any producers or consumers start sending or 
                   receiving rows.   
  EndShuffle()   : Called after all producers and consumers have successfully                   
                   sent and received all rows. 
}

이 API는 적절한 수준에서 공유 메모리 추상화를 제공하도록 엄밀하게 설계되었습니다. 데이터 처리 파이프라인에서 모든 형태의 데이터 재분할 및 전송을 지원하기에 충분히 범용적이지만 Google 네트워킹 기술을 사용하여 더욱 효율적으로 구현되었습니다. 개념적으로 셔플 작업은 다음과 같이 설명할 수 있습니다.

위의 추상화에서 작업들이 실행될 때 BigQuery Shuffle을 사용하면 많은 Producer가 오버헤드와 조각화를 최소화하면서 원격 메모리에 쓸 수 있고 Consumer는 높은 처리량으로 동시에 읽을 수 있습니다. 특히 Producer는 생성된 행을 연속 메모리 블록에 기록하고 인덱싱합니다. 이 인덱스를 통해 Consumer는 관련 행에 효율적으로 액세스하고 검색할 수 있습니다. 또한 BigQuery의 데이터 구조와 통신 프로토콜은 Jupiter 네트워킹 인프라에서 지원하는 하드웨어 가속을 활용합니다.

메모리 내 데이터 재분할 외에도 BigQuery Shuffle은 다른 측면에서 MapReduce 스타일의 Shuffle과 다릅니다. 데이터 흐름 그래프의 다양한 단계 사이에서 장벽 역할을 하지 않습니다. 모든 행이 전송 및 정렬되고 파티션을 다시 나눈 후 데이터 세트(첫 번째 행)을 사용할 수 있는 MapReduce 스타일 Shuffle과 달리 BigQuery에서는 Shuffle된 각 행이 Producer에 의해 생성되자마자 BigQuery 작업자가 사용할 수 있습니다. 이를 기반으로 파이프라인에서도 분산 작업을 실행할 수 있습니다.

데이터 파티셔닝은 BigQuery의 성능에 상당한 영향을 미칩니다. 특히, 최상의 결과를 얻기 위해서는 적절한 수의 Consumer와 Producer에서 Consumer로의 올바른 매핑 기능을 사용하는 것이 중요합니다. 최적이 아닌 파티셔닝으로 인해 쿼리 실행 속도가 훨씬 느려지고 리소스 제약으로 인해 실패할 수도 있습니다.

BigQuery는 쿼리에 사용된 연산자 유형, 데이터 볼륨, 백그라운드 로드 및 기타 요인에 따라 파티셔닝을 지능적으로 선택하는 동적 파티셔닝 메커니즘을 사용합니다. 이 기능을 통해 BigQuery 사용자는 배포 또는 정렬 키를 지정하는 오버헤드 없이 임의의 데이터세트에서 효율적인 쿼리를 실행할 수 있습니다.

BigQuery를 사용하면 페타바이트 규모의 데이터를 쿼리할 수 있지만 많은 경우에 재분할할 데이터의 양으로 인해 완전한 인메모리 셔플링 비용은 매우 높아집니다. 하지만 BigQuery Shuffle은 임시 데이터를 재구성하고 원격 메모리에서 Google의 분산 파일 시스템인 Colossus로 이동하여 이 문제를 해결합니다. 디스크의 성능 특성이 메모리와 근본적으로 다르기 때문에 BigQuery는 디스크 검색을 최소화하는 방식으로 데이터를 자동으로 구성하는 데 특별한 주의를 기울입니다.

BigQuery는 모든 고객이 가상 머신 클러스터의 크기를 조정하거나 리소스를 프로비저닝하지 않고도 쿼리 실행을 시작할 수 있는 멀티 테넌트 서비스입니다. 이를 위해 BigQuery shuffle은 대부분의 쿼리를 순전히 메모리에서 실행할 수 있는 지능형 메모리 리소스 관리 시스템을 사용합니다. 이를 기반으로 시스템은 고객의 부하 변화에 즉각적으로 적응합니다.

모든 BigQuery 쿼리에는 하나 이상의 Shuffle 작업이 포함되며 단일 데이터 행을 전송하거나 페타바이트 데이터를 쿼리하는 데 동일한 인프라가 사용됩니다. Google 네트워킹 기술과의 긴밀한 통합과 결합된 BigQuery Shuffle의 뛰어난 유연성 덕분에 BigQuery 사용자는 모든 규모에서 빠른 데이터 분석을 활용할 수 있습니다.


본 글의 원문은 이곳에서 확인할 수 있습니다.