주요 컨텐츠로 이동
데이터 엔지니어링

Lakebase Postgres 컴퓨팅 캐시 개선

파트 1: 대형 Postgres 컴퓨트 노드가 더 낮은 대기 시간으로 최대 2배 더 빠르게 실행되는 방법

작성자: David Wein, Sunil Kamath , Haoyu Huang

  • 표준 Postgres 캐시 vs Lakebase Postgres 캐시
  • 공유 버퍼와 연동하여 작동하며 컴퓨트에 가능한 한 많은 데이터를 유지하는 자동 확장 캐시를 생성한 방법
  • 2배의 처리량, 스토리지 계층으로부터의 읽기 감소, 더 낮은 대기 시간을 포함한 프로덕션 결과

Lakebase Postgres의 스토리지 분리 모델은 기능이 풍부하고 유연하며 비용 효율적인 플랫폼을 제공합니다. 데이터가 S3와 같은 객체 스토리지에 백업되는 동안 높은 처리량과 낮은 대기 시간을 제공하려면 효율적인 데이터 캐싱이 필수적입니다.

이 캐싱은 두 개의 레이어에서 수행됩니다. 첫째는 높은 쓰기 처리량과 읽기 서비스를 위해 Postgres 페이지가 실체화되는 분산 스토리지 레이어이고, 둘째는 자주 액세스하는 페이지를 DRAM에서 제공하여 초고속 액세스를 가능하게 하는 Postgres 컴퓨트 자체 레이어입니다.

저희는 컴퓨트 측 캐싱을 개선하기 위해 열심히 노력해 왔으며, 이 블로그에서는 단기 계획을 설명하고 이미 고객에게 제공된 기능에 대해 자세히 살펴보겠습니다.

먼저, 이 단계에 이르게 된 배경을 설명해 드리겠습니다.

표준 Postgres 캐시

데이터베이스는 DRAM(메모리)을 많이 소모하는 것으로 유명합니다. 주로 이 메모리를 데이터 캐시로 사용하며, 캐시 내 행에 대한 액세스 시간이 가장 빠른 NVMe 드라이브보다 몇 배나 빠른 나노초 단위로 측정되기를 기대합니다.

Postgres는 데이터를 페이지의 행 단위로 구성하며, 활발히 액세스되는 페이지는 "shared buffers"(공유 버퍼)라고 알려진 메모리 영역에 로드되어야 합니다. Postgres는 전통적으로 운영체제의 파일 시스템을 사용하여 페이지를 저장하므로, OS 커널도 유연한 페이지 캐시를 사용하여 Postgres 공유 버퍼와 디스크 간의 캐싱을 제공합니다.

이 공유 버퍼와 페이지 캐시 결합 방식은 상당히 잘 작동하지만 몇 가지 단점과 기술적 과제가 있습니다.

단점

  1. 이중 버퍼링으로 인해 컴퓨트에서 효과적으로 캐싱할 수 있는 데이터의 양이 줄어듭니다. 예를 들어 4 GB의 RAM을 장착한 컴퓨트에서 1 GB를 공유 버퍼로 사용한다고 가정해 보겠습니다. 1 GB의 공유 버퍼를 채우기 위해 디스크에서 페이지를 읽을 때, 이 읽기 작업은 해당 데이터도 보유하고 있는 OS 페이지 캐시를 거치게 됩니다. 결과적으로 1 GB의 데이터를 캐싱하기 위해 2 GB의 RAM을 소비하게 됩니다.
  2. OS 페이지 캐시는 공유 버퍼나 Postgres 내부 구조에 대해 전혀 알지 못하므로, 어떤 페이지를 교체해야 할지 스마트한 결정을 내릴 수 없습니다.

기술적 과제

  1. Lakebase Postgres와 같은 스토리지 분리형 시스템에서는 스토리지에서 읽은 데이터가 OS 파일 시스템이나 페이지 캐시를 거치지 않습니다.
  2. 공유 버퍼는 정적 파라미터이므로 Postgres를 시작하기 전에 설정되며 데이터베이스를 재부팅하지 않고는 변경할 수 없습니다. 이는 Lakebase와 같은 서버리스 오토스케일링 시스템에 있어 중대한 과제입니다.
  3. Postgres는 활성 연결마다 별도의 운영체제 프로세스를 사용하므로, 공유 버퍼가 클수록(즉, Postgres에 더 많은 메모리를 할당할수록) OS가 모든 개별 연결에 대해 더 많은 메모리 관리를 수행해야 하며, 이는 결국 메모리 소비로 이어집니다.

Lakebase 캐시 경로

image3.png

배경을 설명해 드렸으니, 이제 Databricks에서 이 문제들을 어떻게 해결하고 있는지 알아보겠습니다.

저희가 목표로 하는 최종 상태는 워크로드에 따라 자동으로 확장되고 사용 가능한 메모리의 최대 75%를 사용하는 Postgres 동적 공유 버퍼를 통해 컴퓨트의 DRAM을 가장 효율적으로 사용하는 것입니다.

결과적으로 오토스케일링 공유 버퍼를 활용하도록 컴퓨트 플랫폼을 조정해야 하지만, 동시에 고객이 바로 이용할 수 있는 합리적인 점진적 개선 사항도 제공하고자 합니다. 각 점진적 릴리스를 통해 로드맵의 일부를 자신 있게 출시하는 동시에 고객에게 실제적인 이점을 제공할 수 있습니다. 따라서 오토스케일링 컴퓨트가 최종 목표일지라도, 다음 섹션에서 다룰 고정 크기 컴퓨트부터 시작했습니다.

저희가 구현한 내용은 다음과 같습니다.

더 큰 공유 버퍼

image1.png

앞서 언급한 기술적 과제에서 기억하시겠지만, Lakebase와 같은 분리형 시스템은 표준 OS 파일 시스템과 페이지 캐시를 통해 읽기 작업을 라우팅하지 않습니다. 또한 Postgres 공유 버퍼는 정적이며 자동으로 확장될 수 없다는 점도 기억하실 것입니다.

이를 해결하기 위해 저희는 로컬 파일 캐시(LFC)라고 부르는 레이어를 만들었습니다. LFC는 대역 역할을 하여 공유 버퍼와 연동되어 작동하는 오토스케일링 캐시를 생성하고, 가능한 한 많은 데이터를 컴퓨트에 캐싱된 상태로 유지했습니다. 이는 Lakebase Postgres가 오토스케일링을 시작할 수 있게 해준 영리하고 실용적인 솔루션이었으며, 출시 이후 모든 컴퓨트에서 사용되고 있습니다.

사용자에게는 단일 고속 컴퓨트 캐시로 노출되지만, 기본 아키텍처는 최대 두 개의 티어를 지원합니다.

  • 공유 버퍼(Shared buffers): 가장 대기 시간이 짧은 액세스 경로를 제공하는 Postgres의 인메모리 공유 버퍼입니다.
  • 로컬 파일 캐시(Local file cache): 컴퓨트 노드의 로컬 NVMe에 상주하는 확장된 보조 캐시로, 메모리보다 더 큰 용량을 제공하지만 페이지에 액세스하려면 디스크 I/O가 필요합니다.

공유 버퍼는 최소 구성 CU에서 실행될 때 너무 많은 메모리를 소비하지 않도록 보수적으로 튜닝되었으며, 최대 크기는 1 GB의 공유 버퍼로 구성되고 LFC가 전체 컴퓨트 캐시 용량의 나머지(DRAM의 최대 75%)를 소비하도록 설정되었습니다. 두 티어 모두에서 미스(miss)가 발생하는 요청은 컴퓨트 노드에서 분산 스토리지 레이어로 라우팅됩니다.

더 큰 작업 세트의 경우 공유 버퍼를 1 GB로 제한하면 대부분의 캐시 히트(hit)가 더 느린 LFC 티어를 거쳐야 했습니다. LFC는 그동안 유용하게 사용되었지만, 완전히 동적인 공유 버퍼로 나아감에 따라 현재 형태의 LFC는 점차 폐지할 계획입니다.

참고: 고정 크기 컴퓨트가 먼저 적용되었습니다

공유 버퍼가 아직 동적이지 않기 때문에, 더 큰 공유 버퍼의 첫 번째 릴리스는 고정 크기 컴퓨트를 대상으로 합니다. 이러한 컴퓨트에서는 이제 LFC를 비활성화하고 공유 버퍼를 DRAM의 75%로 설정합니다. 이는 현재 CU >= 80인 고정 크기 컴퓨트에 적용되어 있습니다. 약 1 GB의 버퍼 제한을 제거함으로써 자주 사용되는 핫 페이지(hot page)가 로컬 파일 스토리지로 내려가지 않고 가장 빠른 메모리 레이어에 유지됩니다.

컴퓨트에 대용량 공유 버퍼가 활성화되어 있는지 확인하려면 Postgres 연결 내에서 show shared_buffers을(를) 실행하세요. Databricks의 80 CU Lakebase 엔드포인트에서는 15278640 값이 표시되어야 합니다.

OS 페이지 캐시 대신 공유 버퍼에 핫 데이터를 유지하면 앞서 설명한 단점도 해결됩니다. 이중 버퍼링이 발생하지 않으므로 1 GB의 캐싱된 데이터가 2 GB가 아닌 1 GB의 RAM만 소비합니다. 또한 캐시가 커널이 아닌 Postgres 내부에 존재하기 때문에 데이터베이스 상태를 파악하여 제거(eviction) 결정을 내릴 수 있습니다. 이를 통해 OS가 제공할 수 있는 것보다 더 스마트한 교체 정책을 추진할 수 있는 기반이 마련됩니다.

고정 크기 컴퓨트에서 공유 버퍼 크기를 DRAM의 75%로 설정하는 것은 단순히 구성을 변경하는 것만큼 간단하지 않았습니다. 세 번째 기술적 과제인 백엔드당 프로세스(process per backend) 아키텍처 때문이었습니다.

다음 섹션에서는 이에 대한 솔루션을 설명합니다.

huge pages를 통한 메모리 및 변환 오버헤드 해결

Postgres는 각 백엔드가 공유 버퍼를 자체 주소 공간에 매핑하는 프로세스 기반 구조를 사용하므로, 자체 페이지 테이블 엔트리(가상 주소를 물리 메모리로 변환하기 위해 하드웨어가 탐색하는 커널 유지 구조)가 필요합니다. 기본적으로 Linux는 이 매핑을 4 KB 페이지 단위로 수행합니다.

간단한 수치로 예를 들면, 1 GB의 공유 버퍼는 프로세스당 262,144개의 페이지 테이블 엔트리에 해당합니다. 32 GB의 공유 버퍼와 512개의 백엔드가 있는 경우, 이는 약 43억 개의 엔트리에 달하며, 32 GB의 캐시를 매핑하는 데 약 32 GB의 페이지 테이블이 필요함을 의미합니다.

이 작업 세트는 가상 주소에서 물리 주소로의 변환을 가속화하는 CPU 메모리 관리 장치(MMU)의 캐시인 TLB(Translation Lookaside Buffer)의 용량도 훨씬 초과합니다. 따라서 공유 버퍼 히트가 발생하더라도 TLB 미스 및 페이지 테이블 탐색(page table walk)으로 인한 성능 저하가 발생합니다.

이를 완화하기 위해 Postgres 커뮤니티는 대용량 공유 버퍼와 함께 huge pages(각 2 MB)라는 OS 메커니즘을 사용할 것을 권장합니다. huge pages로 전환하면 페이지 테이블 크기가 512분의 1로 줄어들고 TLB 미스율이 크게 낮아집니다.

자체 벤치마크 테스트에서 Postgres를 huge pages로 구성한 결과, 꼬리 읽기 대기 시간(tail read latency)이 최대 약 40% 감소하고 CPU 사용률이 최대 약 30% 감소했습니다.

가상화 환경에서의 Huge page 지원

Lakebase Postgres는 베어메탈 호스트 위의 경량 게스트 가상 머신(VM) 내에서 실행됩니다. 메모리 주소 변환에는 두 개의 가상화 레이어가 관여합니다. huge pages를 활용하려면 호스트 수준의 예약부터 VM 메모리를 지원하는 하이퍼바이저, 게스트 커널에 이르기까지 전체 스택에 걸쳐 일관된 구현이 필요합니다. 어느 한 티어에서라도 문제가 발생하면 결과적인 성능 이점이 저하됩니다.

최근 저희는 VM 인프라 전반에 전용 huge-page 지원을 도입했습니다. 최선 노력(best-effort) 방식의 투명한 대형 페이지(transparent huge pages)에 의존하는 대신 명시적인 2 MB HugeTLB 페이지를 사용하기로 결정했습니다. 이제 대규모 고정 크기 컴퓨트용으로 할당된 VM은 Postgres 시작에 충분한 사전 결정된 볼륨의 huge pages로 초기화됩니다. 시스템 리소스를 최적화하기 위해, 컴퓨트 시작 시 Postgres에 필요한 양을 초과하는 잉여 huge pages는 자동으로 해제됩니다.

팁: 컴퓨트에 대용량 명시적 huge pages가 활성화되어 있는지 확인하려면 Postgres 연결 내에서 show huge_pages을(를) 실행하세요. 80 CU Lakebase 엔드포인트에서는 "on" 값이 표시되어야 합니다.

프로덕션 결과

몇 주 전부터 지역별로 순차적인 배포가 시작되었습니다. 아래 예시는 새로운 구성을 활성화하는 재시작 이후 대규모 프로덕션 엔드포인트에서 측정한 결과입니다.

예시 1: 처리량 약 2배 증가, 스토리지 읽기 5배 감소

한 대규모 엔드포인트에서는 8월 11일 06:10 UTC경에 변경 사항이 적용되었습니다. 여기에서 처리량의 대리 지표로 사용하는 초당 액세스된 Postgres 블록 수가 두 배로 증가했습니다. 고객은 전날, 전주, 전월 대비 p50 및 p99 대기 시간이 단축되었다고 보고했습니다.

image2.png

이 엔드포인트는 대용량 로컬 파일 캐시를 구성했습니다. 공유 버퍼가 커지면서 스토리지 GetPage/s가 초당 약 8K에서 약 1.5K로 감소했습니다.

image4.png

예시 2: 처리량 1.3배 증가

또 다른 대규모 엔드포인트에서는 8월 14일 01:30 UTC경에 변경 사항이 적용되었습니다. 처리량이 약 43% 증가했습니다.

image7.png

컴퓨트 캐시 적중률이 거의 100%에 달했으며, 요청은 거의 전적으로 공유 버퍼에서 처리되었습니다.

image8.png

예시 3: CPU 사용량 5배 감소, 처리량 2배 증가

이 워크로드에서는 8월 15일 배포 이후 CPU 사용량이 20코어에서 4코어로 감소했습니다. 컴퓨트 캐시 적중률은 거의 100%로 상승했고, 측정된 처리량은 두 배로 증가했습니다.

image5.png

image6.png

파트 2: 오토스케일링

저희는 현재 오토스케일링 Postgres 컴퓨트에 더 큰 공유 버퍼를 제공하기 위해 노력하고 있습니다. 오토스케일링은 추가적인 복잡성을 수반합니다. 즉, 스케일 업할 때는 공유 버퍼를 동적으로 확장하고 스케일 다운할 때는 축소해야 하며, 이 모든 과정에서 필요한 정확한 용량의 huge page를 할당해야 합니다.

고정된 크기의 컴퓨트를 넘어서기 위해, 저희는 게스트에 제공되는 huge page를 오토스케일링하는 프로토콜을 개발했습니다. Huge page는 동적 공유 버퍼와 연동하여 확장되므로 높은 동시성과 메모리 크기에서도 효율적인 주소 변환을 유지할 수 있습니다. 다음 포스트(파트 2)에서는 오픈 소스 Postgres의 현재 상태와 이 기능을 더욱 발전시키고 업스트림에 기여하기 위해 선택한 영역을 포함하여, 이러한 동적 공유 버퍼 구현의 기술적 세부 사항을 다룰 예정입니다.

직접 사용해 보세요

이 모든 성능 향상은 Lakebase Postgres 아키텍처에서 비롯됩니다. 스토리지 레이어는 신뢰할 수 있는 기록 시스템(system of record) 역할을 하고, 컴퓨트 노드는 상태가 없으며(stateless) 메모리는 캐싱 레이어 역할을 합니다.

Lakebase Postgres를 배포하고 성능을 직접 테스트해 보세요. 여기에서 시작할 수 있습니다.

Lakebase Postgres는 독립형 데이터베이스로 사용할 수 있으며, Unity Catalog 거버넌스, 레이크하우스 분석, 노트북, AI 워크플로 등 Databricks Data + AI Platform의 나머지 기능과도 통합할 수 있습니다.

(이 글은 AI의 도움을 받아 번역되었습니다. 원문이 궁금하시다면 여기를 클릭해 주세요)

최신 게시물을 이메일로 받아보세요

블로그를 구독하고 최신 게시물을 이메일로 받아보세요.