주요 컨텐츠로 이동
공학

오브젝트 스토리지 + WAL: 에이전트 시대를 위한 레이크베이스 Postgres

WAL을 내구성 있는 단일 진실 공급원(source of truth)으로 취급하여 에이전트가 Postgres를 사용하는 방식을 혁신해 보세요.

작성자: Cassie Murray , Carlota Soto

  • Lakebase Postgres는 컴퓨팅과 스토리지를 분리하고, S3와 같이 확장 가능한 오브젝트 스토리지의 WAL(Write-Ahead Log)을 최종적인 단일 진실 공급원(source of truth)으로 취급함으로써 기존 OLTP 데이터베이스를 새롭게 재정의합니다.
  • 무거운 물리적 데이터 복제를 LSN(Log Sequence Numbers)에 대한 경량 포인터로 대체함으로써, 이 아키텍처는 에이전트(agentic) 워크로드에 이상적인 즉각적인 데이터베이스 브랜칭, 특정 시점 복구(point-in-time restore), 시간 여행(time-travel) 쿼리를 지원합니다.
  • 변경 불가능한 트랜잭션 내역을 오픈 컬럼형(columnar) 포맷으로 저장하여 트랜잭션 및 분석 엔진 모두가 단일 통합 데이터 세트를 직접 쿼리할 수 있도록 지원하며, 이를 통해 별도의 읽기 복제본이나 복잡한 데이터 동기화 파이프라인의 필요성을 제거합니다.

기존 OLTP 데이터베이스와 상호작용하는 에이전트는 스토리지 레이어에서 병목 현상을 일으키는 경우가 많습니다. 새로운 배포, 복사, 복구, 복제본 생성은 모두 대량의 데이터를 이동해야 함을 의미하며, 이는 시간과 비용이 많이 드는 작업입니다.

오브젝트 스토리지는 이와 정반대입니다. 예를 들어 Amazon S3는 저렴하고 성능이 뛰어나며 운영 부담이 거의 없습니다. 이는 에이전트 메모리를 위한 확장 가능하고 비용 효율적인 스토리지 레이어를 제공합니다.

여기서 다음과 같은 질문이 생깁니다. 오브젝트 스토리지를 트랜잭션 데이터베이스 하단에 배치하여 에이전트가 더 쉽게 작업하도록 만들 수 있을까요?

이 질문이 바로 Lakebase Postgres의 시작점이었습니다. 그 답은 오브젝트 스토리지의 속도뿐만 아니라, 신뢰할 수 있는 단일 원천(source of truth)을 어디에 두느냐에 달려 있습니다.

두 가지 OLTP 모델

일반적인 OLTP의 멘탈 모델은 데이터 중심적입니다. 데이터는 각각의 엔티티를 나타내는 행과 열이 있는 테이블로 구성됩니다. 스토리지는 현재 상태가 저장되는 공간이며, 데이터베이스의 역할은 이를 저장하고 검색하는 것입니다.

하지만 두 번째 모델인 트랜잭션 중심 모델도 있습니다. 여기서 데이터베이스는 트랜잭션의 저널(기록)입니다. 각 항목은 하나의 작업이며, 스토리지는 현재의 스냅샷이 아니라 이러한 작업들의 타임라인입니다. 현재 상태는 이 타임라인에서 도출할 수 있는 결과물 중 하나일 뿐입니다.

오랫동안 실제 환경에서는 데이터 중심 모델만이 중요하게 여겨졌습니다. 운영 팀이 데이터베이스에 요구하는 것은 현재 상태에 대한 읽기 및 쓰기 작업이었기 때문입니다. 하지만 지난 몇 년 동안 상황이 극적으로 변했습니다. 에이전트 워크로드가 요구하는 작업은 거의 대부분 트랜잭션 이력에 대한 작업입니다.

  • 작업할 수 있는 격리된 프로덕션 복사본을 제공해 주세요
  • 마지막 3개의 문을 실행하기 전 상태로 되돌려 주세요
  • 마이그레이션 전에 이 테이블이 어떤 모습이었는지 보여주세요
  • 이 작업을 동시에 20개 실행하고, 한 시간 후에 그 중 19개를 삭제해 주세요

이것들은 모두 타임라인에 대한 쿼리입니다. 현재 상태만 저장하는 데이터베이스는 복사본과 백업을 제공해야 하므로 속도가 느리고 비용이 많이 듭니다.

하지만 Postgres에는 이미 이 타임라인이 포함되어 있습니다. 바로 WAL(write-ahead log)입니다.

WAL에 기록되는 내용

Postgres의 WAL은 데이터 파일에 도달하기 전에 모든 변경 사항을 기록합니다. 원래 이는 Postgres의 복구를 위해 존재했습니다. 로그 쓰기와 데이터 파일 쓰기 사이에 서버가 다운되면, WAL 재실행을 통해 그 격차를 메웠습니다.

하지만 WAL의 콘텐츠는 단순한 복구 그 이상의 흥미로운 가능성을 가지고 있습니다. 테이블과 insert 작업을 예로 들어 보겠습니다.

해당 변경 사항이 디스크의 users 테이블에 도달하기 전에 Postgres는 이를 WAL에 추가합니다. 로그는 바이너리 형식이지만, pg_waldump을 통해 렌더링할 수 있습니다. 이 insert 작업에 대한 레코드는 대략 다음과 같습니다.

이것은 4개의 레코드와 1개의 트랜잭션입니다. 각 레코드가 단조 증가하는 식별자인 LSN(log sequence number)을 어떻게 가지고 있는지 확인해 보세요.

heap 및 btree 라인은 변경된 정확한 8 KB 페이지를 지정합니다. 로그는 "행이 추가되었습니다"라고 말하지 않습니다. 타임라인의 어느 시점에, 어떤 릴레이션의, 어떤 페이지가 변경되었는지를 알려줍니다.

이를 복구 메커니즘으로 읽는다면 크래시 발생 후 다시 실행해야 할 작업 목록이 됩니다. 하지만 이를 트랜잭션 저널로 읽는다면 완전히 다른 의미가 됩니다. 데이터베이스가 변경한 모든 페이지에 대한 완전하고 순서가 보장된 바이트 수준의 기록이며, 모든 항목에 고유한 이름이 부여된 것입니다.

그 이름인 LSN이 가장 중요한 부분입니다. 이는 타임라인이 이미 주소 지정이 가능함을 의미합니다. "특정 시점의 데이터베이스"를 명확하게 정의하기 위해 Postgres에 추가로 구현해야 할 것은 없습니다. 로그를 유지하고 이에 대한 질문에 답할 수 있는 스토리지 레이어만 있으면 됩니다.

로그가 신뢰할 수 있는 단일 원천이 되다

기존의 Postgres 배포에서 WAL은 목적을 위한 수단입니다. 데이터 파일이 곧 데이터베이스이며, 로그는 이를 보호하고 레코드가 안전하게 적용되면 삭제됩니다. 스토리지는 단순히 Postgres를 실행하는 머신에 연결된 디스크일 뿐이며, 데이터베이스의 정체성에 관한 모든 것은 해당 머신에 종속됩니다.

이제 이를 뒤집어 보겠습니다. 로그를 데이터베이스로 만들고, 데이터 파일을 로그에서 파생된 캐시된 표현으로 만드는 것입니다. 그러면 전체 타임라인을 유지할 수 있으며, 데이터베이스를 복사하거나 되돌리기 위해 데이터를 이동할 필요가 없어집니다. 이력이 주소 지정 가능해지므로, 데이터베이스 "복사본"은 두 번째 파일 세트가 아니라 포인터가 됩니다. 덕분에 배포, 복구, 복제를 코드처럼 가볍게 처리할 수 있습니다.

이것이 바로 저희가 Lakebase Postgres에서 구현한 방식입니다. 구체적으로는 시스템을 두 개의 레이어로 나누었습니다.

컴퓨트 레이어

컴퓨트 레이어는 표준 Postgres를 실행합니다. SQL을 파싱하고, 쿼리를 계획 및 실행하며, MVCC를 강제하고, 락과 인덱스를 관리합니다.

쿼리 엔진에서 재작성된 부분은 없습니다. 달라진 것은 컴퓨트 노드가 담당하는 역할입니다. 컴퓨트 노드는 데이터를 보존하는 것이 아니라 작업을 실행하기 위해 존재합니다. 공유 버퍼를 위한 RAM과 페이지 캐시 역할을 하는 로컬 NVMe를 갖추고 있으며, 내구성을 위협받지 않고 언제든지 시작, 중지, 확장 또는 종료될 수 있습니다.

스토리지 레이어

스토리지 레이어는 정확성, 내구성, 이력을 책임집니다. 개별 컴퓨트 노드보다 수명이 길며, 서로 다른 역할을 하는 세 가지 구성 요소로 구축됩니다.

  • Safekeeper는 WAL을 복제합니다. 컴퓨트 노드가 WAL 레코드를 생성하면 이를 여러 safekeeper로 스트리밍하며, Paxos 기반 프로토콜을 통해 정족수(quorum)가 레코드를 확인하면 트랜잭션이 커밋됩니다. 내구성은 단일 머신의 fsync이 아니라 복제 및 합의의 특성입니다.
  • Pageserver는 WAL을 페이지로 변환합니다. 기본 페이지와 커밋된 WAL 레코드를 결합하여 특정 쿼리가 필요한 페이지 버전을 구체화(materialize)하고, 구체화된 버전을 오브젝트 스토리지에 비동기적으로 영구 저장합니다.
  • 오브젝트 스토리지는 장기적이고 불변하는 이력을 보관합니다. 구체화된 페이지 버전과 과거 상태는 변경 가능한 파일 시스템이 아니라 추가 전용(append-only) 레코드로 유지됩니다.

image2.png

쓰기 경로

쓰기 경로는 어떤 모습일까요? 이 시스템에서 커밋은 다음 단계를 따릅니다.

  1. Postgres가 메모리에 변경 사항을 적용합니다. 평소와 똑같이 버퍼가 업데이트되고, 인덱스가 수정되며, WAL 레코드가 생성됩니다.
  2. 컴퓨트 노드는 WAL을 로컬 파일 시스템에 플러시하는 대신 네트워크를 통해 safekeeper로 스트리밍합니다.
  3. safekeeper 정족수가 레코드를 확인하면 트랜잭션이 커밋됩니다. 이 시점에 클라이언트는 성공 응답을 받게 됩니다.
  4. 페이지 구체화는 나중에 트랜잭션의 크리티컬 패스(critical path)를 벗어난 스토리지 레이어에서 발생합니다. 커밋은 페이지가 작성되거나 업로드될 때까지 기다리지 않습니다.

image3.png

이 설계에 대해 2단계가 커밋 경로에 네트워크 홉을 추가한다는 당연한 반론이 제기될 수 있습니다. 하지만 내구성을 진지하게 고려하는 모든 Postgres 배포는 이미 동기식 복제를 실행하고 있으며, 이 역시 네트워크 홉을 수반합니다. WAL을 외부화하는 것은 네트워크 왕복을 하나 더 추가하는 것이 아니라 기존의 네트워크 왕복을 다른 것으로 대체하는 것입니다.

읽기 경로

컴퓨트 노드의 모든 읽기 요청에는 페이지 식별자와 LSN이 포함되며, 스토리지 레이어는 해당 LSN 시점에 존재했던 페이지를 반환합니다. 이 GetPage@LSN은 이 아키텍처에서 핵심적인 작업입니다.

이를 처리하는 데는 다음과 같은 우선순위가 적용됩니다.

  1. 첫 번째는 다른 Postgres와 마찬가지로 Postgres 공유 버퍼를 위한 RAM입니다.
  2. 그 다음은 여전히 빠르고 로컬에 위치한 로컬 NVMe입니다. 페이지가 메모리에 없으면 컴퓨트 노드는 로컬 디스크 캐시를 확인합니다.
  3. 로컬 미스가 발생한 경우에만 요청이 네트워크를 거쳐 pageserver로 전달됩니다. 그런 다음 pageserver는 해당 페이지 버전이 이미 구체화되어 있는지 확인합니다. 그렇지 않은 경우, 요청된 LSN 또는 그 이전의 가장 최근 페이지 이미지를 찾고, 그 위에 WAL 레코드를 수집하여 재실행한 후 재구성된 페이지를 반환합니다.

반환된 페이지는 RAM 및 NVMe에 캐시되므로, 다음 읽기 작업은 다시 로컬에서 처리됩니다.

image4.png

기본 노드는 모든 페이지의 최신 버전을 요청하므로, 안정 상태에서는 웜 캐시(warm cache)에서 읽는 일반적인 Postgres처럼 작동합니다. 하지만 프로토콜에서 반드시 "최신" 버전을 요구하는 것은 아닙니다. 4시간 전의 LSN으로 페이지를 요청하면 4시간 전의 해당 페이지를 그대로 받을 수 있습니다.

이로 인한 유용한 결과는 실시간 데이터와 과거 백업 간의 구분이 사라진다는 점입니다. 단 하나의 스토리지 시스템만 존재하게 됩니다. 이전 페이지 버전은 다른 곳에 다른 형식으로 보관되는 별도의 아티팩트가 아닙니다. 여전히 주소 지정이 가능한 동일한 불변(immutable) 파일입니다.

덮어쓰지 않는 스토리지

다시 말해, 페이지서버(pageserver)는 파일을 제자리에서 업데이트(in-place update)하지 않습니다. 파일은 생성, 병합, 삭제될 뿐 절대 수정되지 않습니다. 이는 임의 업데이트(random update)를 제공하지 않는 오브젝트 스토리지에 완벽하게 부합하며, 덕분에 이력을 저렴한 비용으로 보관할 수 있습니다.

데이터는 두 가지 종류의 레이어 파일로 구성됩니다.

  • 이미지 레이어는 하나의 LSN에서 특정 키 범위에 있는 모든 키의 스냅샷을 보유합니다.
  • 델타 레이어는 특정 키 및 LSN 범위의 모든 변경 사항을 보유합니다. 수정되지 않은 키는 저장되지 않습니다. 들어오는 WAL은 델타 레이어로 기록됩니다.

이미지 레이어는 두 가지 이유로 백그라운드에서 생성됩니다. 읽기 작업이 거쳐야 하는 재실행 체인(replay chain)을 단축하고, 오래된 델타를 수집할 수 있게 만들기 때문입니다. 이미지 레이어가 없다면 페이지를 재구성하기 위해 임의로 먼 과거까지 거슬러 올라가야 할 수도 있습니다.

따라서 GetPage@LSN은(는) 일종의 검색이 됩니다. 요청된 키와 LSN에서 시작하여 레이어를 따라 내려가며 해당 페이지의 WAL 레코드를 수집하고, 첫 번째 이미지 레이어에서 멈춥니다. 이 검색을 짧게 유지하기 위해 백그라운드 압축(compaction)을 통해 델타 및 이미지 레이어가 재정렬되며, 보존 기간(retention window)을 벗어난 레이어는 가비지 컬렉션(garbage collection)됩니다.

올바른 레이어를 빠르게 찾는 방법

위에서 설명한 검색은 간단해 보이지만 그렇지 않습니다. 전체 설계의 실현 가능성을 결정하는 중요한 부분인 만큼, 시간을 들여 살펴볼 가치가 있습니다.

읽기 작업은 키와 LSN을 지정합니다. 스토리지 시스템은 해당 LSN 이하에서 해당 키를 포함하는 가장 가까운 레이어를 찾아야 합니다. 이는 기하학적인 문제이며, 수천만 개의 레이어 중에서 이를 해결하는 방법은 명확하지 않습니다. 선형 탐색(linear scan)은 너무 느리고, 일반적인 공간 구조는 적합하지 않습니다. R-트리는 "이 지점 아래의 첫 번째 레이어"가 아닌 포함 여부 쿼리(containment query)에 응답하며, 세그먼트 트리는 레이어 수가 아닌 좌표 공간의 크기에 따라 확장되기 때문입니다.

이 설계에는 여러 가지 접근 방식이 있지만, 효과적이었던 방법은 먼저 쉬운 문제를 해결한 다음 데이터 구조가 자체의 과거를 기억하도록 만드는 것이었습니다.

1단계: 단일 LSN에 대해 해결하기

하나의 고정된 LSN에 대해 어떤 레이어가 각 키에 응답하는지 파악합니다. 이 응답은 키 공간 전체에서 몇 안 되는 지점에서만 변경되므로, 해당 지점들을 기록하고 이진 탐색 트리(binary search tree)에 저장합니다. 이 트리는 해당 LSN에 대한 레이어 커버리지(layer coverage)가 되며, 단 한 번의 조회로 해당 LSN에서의 모든 읽기 요청에 응답합니다.

이 방식은 작동하지만 단 하나의 LSN에 대해서만 유효합니다. 레이어가 추가될 때마다 커버리지가 변경되고 LSN은 수백만 개에 달하므로, 각 LSN마다 별도의 트리를 생성하고 유지할 수는 없습니다.

2단계: 트리를 영속적으로 만들기

여기서 영속적(persistent)이라는 것은 “이전 버전을 계속 사용할 수 있도록 유지한다”는 의미입니다. 우리는 아래에서 위로 LSN 순서대로 레이어를 삽입하면서 커버리지를 점진적으로 구축합니다. 하나의 레이어를 삽입할 때는 루트에서 아래로 향하는 단일 경로를 따라 노드만 터치합니다. 시스템은 이러한 노드를 덮어쓰는 대신 복사하고 원본은 그대로 둡니다. 새로운 복사본은 양쪽에 있는 변경되지 않은 기존 서브트리를 가리킵니다.

이로 인해 다음 두 가지 결과가 따릅니다.

  • 경로를 벗어난 모든 노드가 공유되므로, 삽입 시 전체 트리를 새로 만드는 대신 몇 개의 새로운 노드만 생성하는 비용이 듭니다.
  • 기존 루트는 삽입 전의 트리 상태를 그대로 설명하므로, 이전 LSN에 대해 여전히 유효한 커버리지로 남습니다.

모든 레이어에 대해 이 작업을 순서대로 수행하면, 각기 다른 LSN에서의 커버리지인 모든 중간 루트를 포함하는 단일 구조가 완성됩니다. 거의 트리 하나 값의 비용으로 이 모든 트리를 얻을 수 있습니다.

따라서 과거 시점의 읽기 비용은 현재 읽기 비용과 동일합니다. 시스템이 원하는 LSN의 루트를 선택하고 동일하게 단 한 번의 조회를 수행하기 때문입니다.

요약하자면 다음과 같은 비결이 있습니다.

  • 최신 데이터만 읽는 작업은 한 번의 트리 조회로 완료됩니다.
  • 과거 데이터 읽기는 이전 루트를 사용하므로 비용이 동일합니다.
  • 레이어가 누적되어도 이러한 루트를 구축하는 비용은 저렴하게 유지되므로, 이력이 길어져도 조회가 느려지지 않습니다.

오브젝트 스토리지가 실제로 위치하는 곳

이 지점에서 Postgres와 오브젝트 스토리지에 대한 현재의 논쟁이 양방향 모두에서 잘못되는 경향이 있습니다.

오브젝트 스토리지에 OLTP를 구축하는 것에 반대하는 전통적인 주장은 다음과 같습니다.

  • Postgres는 지연 시간에 민감한 소규모 I/O를 많이 처리합니다.
  • 오브젝트 스토리지는 더 높은 지연 시간에서 더 큰 요청을 처리하도록 설계되었으며, 데이터를 읽는 데 수백 밀리초가 걸릴 수 있습니다.
  • 쿼리 실행 앞에 S3를 두면 결국 데이터베이스가 느려집니다.

그 자체로는 논란의 여지가 없는 주장입니다. 하지만 이 주장이 잘못 짚은 부분은 오브젝트 스토리지 기반으로 구축된 데이터베이스가 쿼리에 응답하기 위해 오브젝트 스토리지에서 데이터를 읽어야만 한다고 가정하는 점입니다.

우리가 제안하는 아키텍처에서는 절대 그렇지 않습니다.

  • 쿼리는 오브젝트 스토리지를 읽지 않습니다. 컴퓨트 노드는 RAM, 로컬 NVMe, 페이지서버 순으로 읽습니다. 오브젝트 스토리지는 페이지서버 내부에서 가지고 있지 않은 페이지 버전을 재구성할 때만 읽히며, Postgres가 직접 읽는 일은 절대 없습니다.
  • 커밋은 오브젝트 스토리지에 기록되지 않습니다. 커밋은 세이프키퍼(safekeeper)의 정족수(quorum)가 WAL 레코드를 확보하면 승인되며, 페이지 구체화 및 업로드는 그 이후에 발생합니다.

Postgres를 이와 같이 설계하면 에이전트 기반 워크로드(agentic workloads)를 처리하도록 구축된 기존 OLTP 시스템의 진화형이 됩니다. 이것이 바로 우리가 Lakebase Postgres를 만든 이유입니다. Lakebase Postgres는 컴퓨팅과 스토리지가 분리되고, 신뢰할 수 있는 단일 원천(durable source of truth)이 오브젝트 스토리지에 구축된 OLTP 데이터베이스입니다.

바닐라 Postgres 대신 Lakebase Postgres를 사용해야 하는 이유

Lakebase Postgres를 사용하면 트랜잭션 이력을 LSN으로 주소 지정할 수 있으며, 복사본은 데이터가 아닌 참조가 됩니다. 덕분에 에이전트의 필수 요구 사항인 가벼운 워크플로를 Postgres에 제공하는 기능을 구축할 수 있습니다.

브랜칭(Branching)

첫째, 이제 Postgres에서 브랜치를 생성할 수 있습니다. 브랜치를 생성해도 페이지가 복사되지 않고 특정 LSN에 대한 포인터가 생성되며, 브랜치는 쓰기 시 복사(copy-on-write) 의미 체계에 따라 해당 지점부터 갈라지기 시작합니다.

브랜치에 대한 쓰기 작업은 상위(parent)에 대한 델타로 저장되므로, 2 TB 데이터베이스의 브랜치도 몇 초 만에 생성되며 무언가 변경되기 전까지는 비용이 전혀 들지 않습니다. 상위 데이터베이스에는 추가 부하가 발생하지 않으므로 프로덕션 환경에서도 안전하게 수행할 수 있습니다.

이것이 바로 에이전트가 안전하게 작업하는 데 필요한 방식입니다. 작업당 하나의 브랜치를 가져와 방금 작성한 마이그레이션을 실제 볼륨의 실제 데이터에 대해 실행하고, 상위 데이터베이스에 영향을 주기 전에 결과를 검사할 수 있습니다. 20개의 에이전트가 동시에 이 작업을 수행할 수 있으며, 각 에이전트는 다른 에이전트 및 프로덕션 환경으로부터 격리됩니다.

Lakebase Postgres를 통해 우리는 데이터베이스를 넘어 브랜칭을 확장했습니다. 오브젝트 스토리지 버킷, Functions, Managed Better Auth 상태, AI Gateway 구성이 데이터베이스와 함께 브랜칭되므로, 브랜치는 단순한 Postgres 테이블이 아니라 백엔드의 격리된 복사본이 됩니다.

즉각적인 복구

특정 시점 복구(Point-in-time recovery)는 다른 의도를 가진 브랜칭입니다. 복구한다는 것은 이전 LSN을 가리키고 거기서부터 재개하는 것을 의미하므로, 데이터를 원래 위치로 다시 복사할 필요가 없으며 비용이 데이터베이스 크기에 비례하여 증가하지 않습니다. 얼마나 먼 과거로 돌아갈 수 있는지는 보존 설정(retention setting)에 따라 다릅니다.

덕분에 에이전트의 실수를 저렴한 비용으로 해결할 수 있습니다. 에이전트가 잘못된 구문을 실행했을 때 복구 창을 열고 복구 계획을 세울 필요 없이, 실행 전의 LSN으로 브랜치를 다시 가리키기만 하면 됩니다. 실행 취소 비용은 빈 데이터베이스에서나 2 TB 데이터베이스에서나 동일하므로, 에이전트는 사람에게 보고하는 대신 작업을 다시 시도할 수 있습니다.

시간 여행 쿼리

페이지서버는 이력 보존 기간 내의 어떤 LSN에서든 모든 페이지를 재구성할 수 있으므로, 먼저 복구할 필요 없이 과거 상태를 직접 쿼리할 수 있습니다.

실제 유용한 용도는 차이점 비교(diffing)입니다. 마이그레이션 전에 이 테이블이 어떻게 생겼는지, 그리고 지금은 어떻게 생겼는지 비교할 수 있습니다. 또한 복구를 확정하기 전에 올바른 타임스탬프를 선택했는지 확인하는 방법이기도 합니다.

복제본 없는 읽기 복제본

읽기 전용 컴퓨트 노드는 데이터의 복사본이 아닙니다. 기본 노드와 동일한 스토리지 레이어에 페이지를 요청하므로, 노드를 추가한다고 해서 데이터 세트를 프로비저닝하고 동기화될 때까지 기다릴 필요가 없습니다. 노드를 구동하는 것은 단순한 메타데이터 작업입니다.

제로(0)로 확장

지속성 상태가 컴퓨트 외부에 존재하므로, 데이터를 보호하기 위해 컴퓨트를 계속 실행해 두는 대신 유휴 컴퓨트 노드를 완전히 종료할 수 있습니다. 컴퓨트는 5분 동안 활동이 없으면 일시 중지되며, 다음 쿼리가 실행될 때 수백 밀리초 내에 다시 활성화됩니다. 대부분의 시간 동안 유휴 상태인 세션별 또는 브랜치별 데이터베이스 플릿의 경우, 이는 실행 가능한 비용 모델과 실행 불가능한 비용 모델을 가르는 결정적인 차이입니다. 일시 중지된 동안에는 컴퓨트 요금 청구가 중단되지만, 이력이 그대로 유지되므로 스토리지 요금은 계속 청구됩니다.

4분 동안 작동한 후 유휴 상태가 된 에이전트 세션은 수동으로 종료할 필요 없이 5분 후에 컴퓨트 비용 발생이 중단됩니다. 바로 이 점 덕분에 에이전트별, 세션별 또는 브랜치별 데이터베이스를 기본 옵션으로 사용할 수 있을 만큼 비용을 합리적으로 유지할 수 있습니다.

트랜잭션 및 분석을 위한 단일 복사본

운영 데이터를 오브젝트 스토리지에 두면 또 다른 변화가 생깁니다.

트랜잭션 데이터베이스의 지속성 기록이 범용 오브젝트 스토리지에 저장되면, 특정 엔진 디스크의 전용 포맷에 더 이상 종속되지 않습니다. 다른 엔진에서도 이 기록을 읽을 수 있게 됩니다.

이것이 바로 저희가 LTAP(Lake Transactional/Analytical Processing)라고 부르는 개념의 기초입니다. 즉, 파이프라인을 통해 동기화되는 두 가지 포맷의 데이터 복사본 두 개를 유지하는 대신, 트랜잭션과 분석 측면 모두에서 읽을 수 있는 개방형 열 지향(columnar) 포맷의 지속성 복사본 하나만 존재하게 됩니다.

이 메커니즘은 앞서 설명한 읽기 경로를 따릅니다. 페이지서버(pageserver)가 페이지를 오브젝트 스토리지에 실체화(materialize)할 때, 모든 값의 정확한 Postgres 표현을 유지하면서 Postgres 행 포맷에서 열 지향(columnar) 형태로 트랜스코딩합니다. 분석 쿼리는 Postgres에 현재 LSN을 요청하고(비용이 적게 드는 메타데이터 조회 작업), 해당 LSN 기준의 데이터 대부분을 오브젝트 스토리지에서 읽은 다음, 아직 실체화되지 않은 가장 최근의 변경 사항만 페이지서버에서 가져옵니다. Postgres는 이 숫자 하나를 반환하는 것 외에는 분석 읽기 트래픽을 전혀 처리하지 않으므로, 대규모 분석 쿼리가 동일한 CPU를 두고 트랜잭션과 경쟁하지 않습니다.

CDC(변경 데이터 캡처) 및 미러링과의 차이점은 별도로 설정할 필요가 없다는 것입니다. 복제가 발생하지 않으므로 복제된 테이블 목록도 존재하지 않습니다. 테이블이 이미 레이크에 존재하므로 두 뷰(view)가 서로 달라질 염려도 없습니다.

에이전트를 위한 Lakebase Postgres

이 글은 "오브젝트 스토리지를 Postgres 하단에 배치하여 에이전트가 더 쉽게 작업하도록 만들 수 있을까?"라는 질문으로 시작했습니다.

대답은 '예'입니다. 오브젝트 스토리지는 Postgres 하단에 위치하여 상호 작용 방식을 바꿀 수 있지만, 단순히 S3의 속도가 빠르거나 운영 비용이 저렴해서만은 아닙니다. 이 글에서 설명했듯이, 그보다 더 많은 엔지니어링이 필요합니다. 쿼리를 충분히 빠르게 처리하려면 여전히 RAM과 로컬 NVMe가 필요하며, 커밋은 버킷이 아니라 복제된 WAL에 기록됩니다.

바로 이 WAL 부분이 핵심입니다. 오브젝트 스토리지는 모든 이력을 저렴하고 확장 가능한 방식으로 저장할 수 있게 해주지만, WAL을 단일 진실 공급원(source of truth)으로 삼음으로써 해당 이력에 접근(addressable)할 수 있게 되고, 에이전트가 Postgres와 상호 작용하는 방식과 그 위에 구축할 수 있는 기능이 달라집니다.

에이전트에게 Lakebase Postgres를 배포하고 테스트해 보도록 요청해 보세요. 여기에서 시작하기.

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

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

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

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