PostgreSQL码农集散地

Snowflake开源pg_lake, 3天揽上千Star

Snowflake开源pg_lake, 3天揽上千Star

每次就是上一篇大新闻 | Snowflake 和 Databricks 为夺 PG 再次大打出手!说的主角,来了。

CrunchyData 被 Snowflake 收购后, 感觉更开放, 更给力了!

开源pg_lake系列插件, 让PG更顺畅的拥有数据湖的能力! 3天揽得1K Star.

https://github.com/Snowflake-Labs/pg_lake

pg_lake 是什么? 用于 Iceberg 和数据湖的 Postgres

pg_lake 将 Iceberg 和数据湖文件(data lake files)集成到 Postgres 中。通过 pg_lake扩展(extensions),您可以将 Postgres 用作一个独立的湖仓系统(lakehouse system),该系统支持对 Iceberg 表(Iceberg tables)执行事务(transactions)和快速查询(queries),并且可以直接处理 S3 等对象存储(object stores)中的原始数据文件(raw data files)。

pg_lake 的核心能力(At a high level)

在较高层面,pg_lake 允许您:

  • 直接通过 PostgreSQL创建(Create)和修改(modify) Iceberg 表,具有完整的事务保证(transactional guarantees),并可从其他引擎(engines)进行查询(query)。
  • 查询(Query)和导入(import) 对象存储(object storage)中的 Parquet、CSV、JSON 和 Iceberg 格式的数据文件(data files)。
  • 使用 COPY 命令将查询结果(query results)以 Parquet、CSV 或 JSON 格式导出(Export)回对象存储。
  • 读取 GDAL 支持的地理空间格式(geospatial formats),例如 GeoJSON 和 Shapefiles。
  • 使用内置的 map 类型(map type)处理半结构化(semi-structured)或键值(key–value)数据。
  • 在相同的 SQL 查询(SQL queries)和修改(modifications)中结合堆表(heap)、Iceberg 和外部 Parquet/CSV/JSON 文件——所有操作都具有完整的事务保证,且无 SQL 限制(SQL limitations)。
  • 从 Iceberg、Parquet、JSON 和 CSV 文件等外部数据源(external data sources)中推断(Infer) 表列(table columns)和类型(types)。
  • 利用(Leverage)底层的 DuckDB 查询引擎(query engine)进行快速执行(fast execution),而无需离开 Postgres。

来看看pg_lake的架构:

架构(Architecture)

一个 pg_lake实例(instance)由两个主要组件(components)组成:带有 pg_lake 扩展的 PostgreSQL 和 pgduck_server。用户连接到 PostgreSQL 运行 SQL 查询,而 pg_lake扩展通过与 Postgres 的钩子(hooks)集成,来处理查询规划(query planning)、事务边界(transaction boundaries)以及执行(execution)的整体编排(orchestration)。

在幕后(Behind the scenes),查询执行的部分被委托给 DuckDB。这是通过 pgduck_server 实现的,pgduck_server 是一个独立的多线程进程(multi-threaded process),它(在本地)实现了 PostgreSQL wire protocol 协议。

这个进程(process)运行 DuckDB,并结合我们的 duckdb_pglake扩展,该扩展添加了 PostgreSQL 兼容的函数(functions)和行为(behavior)。通常,用户不需要知道 pgduck_server 的存在;它透明地(transparently)运行以提高性能(performance)。在适当的时候,pg_lake 将数据扫描(scanning of the data)和计算(computation)委托给 DuckDB 的高度并行(highly parallel)、列式(column-oriented) 执行引擎。

这种分离(separation)也避免了将 DuckDB 直接嵌入(embedding)到 Postgres 进程(process)中可能产生的线程(threading)和内存安全限制(memory-safety limitations),因为 Postgres 进程是围绕进程隔离(process isolation)而非多线程执行设计的。



Image

组件(Components)

pg_lake 遵循模块化设计(modular design),围绕一组可互操作的组件(set of interoperating components)构建。这些组件主要实现为 PostgreSQL 扩展,其他则为支持服务(supporting services)或库(libraries)。

当前的组件集(set of components)包括:

  • pg_lake_iceberg:一个实现了 Iceberg 规范 的 PostgreSQL 扩展。
  • pg_lake_table:一个实现了外部数据包装器(foreign data wrapper),用于查询对象存储中的文件的 PostgreSQL 扩展。
  • pg_lake_copy:一个实现了 COPY to/from 您的数据湖(data lake)的 PostgreSQL 扩展。
  • pg_lake_engine:用于不同 pg_lake扩展的通用模块(common module)。
  • pg_extension_base:其他扩展的基础构建块(foundational building block)。
  • pg_extension_updater:用于在启动时更新所有扩展的扩展。
  • pg_lake_benchmark:对湖表(lake tables)执行各种基准测试(benchmarks)的 PostgreSQL 扩展。
  • pg_map:一个通用 map 类型生成器(generic map type generator)。
  • pgduck_server:一个独立服务器(stand-alone server),它将 DuckDB加载(loads)到同一服务器机器(server machine)上,并通过 PostgreSQL 协议暴露 (exposes) DuckDB 。
  • duckdb_pglake:一个 DuckDB 扩展,它向 DuckDB 添加了缺失的 PostgreSQL 函数 。

准备 pg_lake(Setting up pg_lake)

准备 pg_lake 有两种方式:使用 Docker(用于易于运行的测试环境)或从源代码构建(Building from source)(用于手动设置或开发用途)。这两种方法都包括 PostgreSQL 扩展(extensions)、pgduck_server应用(application)以及设置 S3 兼容存储(S3-compatible storage)。

使用 Docker

遵循 Docker README 以使用 Docker 设置和运行 pg_lake。

从源代码构建(Building from source)

一旦您 构建并安装了所需的组件 ,您就可以在 Postgres 内部 初始化 (initialize)pg_lake。

创建扩展(Creating the extensions)

使用 CASCADE 一次性创建所有必需的扩展:

CREATE EXTENSION pg_lake CASCADE;  
NOTICE:  installing required extension "pg_lake_table"  
NOTICE:  installing required extension "pg_lake_engine"  
NOTICE:  installing required extension "pg_extension_base"  
NOTICE:  installing required extension "pg_lake_iceberg"  
NOTICE:  installing required extension "pg_lake_copy"  
CREATE EXTENSION  

运行 pgduck_server(Running pgduck_server)

pgduck_server 是一个独立进程(standalone process),它(在本地)实现了 Postgres 的协议(wire-protocol),并在底层使用 DuckDB 来执行查询。

当您运行 pgduck_server 时,它会开始监听 Unix 域套接字(unix domain socket)上的端口 5332:

pgduck_server  
LOG pgduck_server is listening on unix_socket_directory: /tmp with port 5332, max_clients allowed 10000  

由于 pgduck_server 实现了 Postgres 线协议,您可以通过 psql 在端口 5332 和主机 /tmp 上访问它,并通过 DuckDB 运行命令。

例如,您可以获取 DuckDB 版本(DuckDB version):

psql -p 5332 -h /tmp  

selectversion() as duckdb_version;   
duckdb_version   
----------------   
v1.3.2 (1 row)  

您也可以在启动服务器(server)时提供一些额外的设置(settings),要查看全部设置:

pgduck_server --help

在生产系统(production systems)上,有一些重要的设置应该被调整:

  • --memory_limit:可选地指定 pgduck_server 的最大内存(maximum memory),类似于 DuckDB 的 memory_limit,默认是系统内存(system memory)的 80%。
  • --init_file_path <path>:在启动(start-up)时执行此文件中的所有语句(statements)。
  • --cache_dir:指定用于缓存(cache) 远程文件(remote files)(来自 S3)的目录(directory)。

将 pg_lake 连接到 S3(或兼容服务)

pgduck_server 依赖 DuckDB [secrets manager] 进行凭证(credentials)管理,它默认遵循 AWS 和 GCP 的凭证链(credentials chain)。请确保您的云凭证(cloud credentials)配置正确,例如,通过在 ~/.aws/credentials 中设置它们。

一旦您设置了凭证链,您应该设置 pg_lake_iceberg.default_location_prefix。这是 Iceberg 表的存储位置(location)。

SET pg_lake_iceberg.default_location_prefix TO's3://testbucketpglake';  

您也可以在 pgduck_server 上设置凭证,用于 [使用 minio 进行本地开发] 。

使用 pg_lake(Using pg_lake)

创建 Iceberg 表(Create an Iceberg table)

您可以通过在 CREATE TABLE 语句中添加 USING iceberg 来创建 Iceberg 表。

CREATETABLE iceberg_test USING iceberg   
ASSELECT
            i askey, 'val_'|| i  as val  
FROM
            generate_series(0,99)i;  

然后,查询它:

SELECTcount(*) FROM iceberg_test;  
 count   
-------  
   100  
(1 row)  

然后您可以看到 Iceberg 元数据位置(metadata location):

SELECT table_name, metadata_location FROM iceberg_tables;  


    table_name     |                                                metadata_location  
-------------------+--------------------------------------------------------------------------------------------------------------------  
 iceberg_test      | s3://testbucketpglake/postgres/public/test/435029/metadata/00001-f0c6e20a-fd1c-4645-87c9-c0c64b92992b.metadata.json  

COPY 导入/导出 S3(COPY to/from S3)

您可以使用 COPY 命令直接导入(import)或导出(export) Parquet、CSV 或换行符分隔的 JSON(newline-delimited JSON)格式的数据。格式会从文件扩展名(file extension)中自动推断(inferred),或者您可以使用 COPY 选项(options)如 WITH (format 'csv', compression 'gzip') 来显式指定(specify it explicitly)。

-- 将数据从 Postgres 以 Parquet 格式复制到 S3  
-- 从任何数据源读取,包括 iceberg 表、堆表或任何查询结果  
COPY (SELECT * FROM iceberg_test) TO's3://testbucketpglake/parquet_data/iceberg_test.parquet';  

-- 从 S3 复制回 Postgres 中的任何表  
-- 此示例复制到 iceberg 表中,但也可以是堆表 (heap table)  
COPY iceberg_test FROM 's3://testbucketpglake/parquet_data/iceberg_test.parquet';  

为 S3 上的文件创建外部表(Create foreign table for files on s3)

您可以直接从一个文件或一组文件中创建外部表(foreign table),而无需指定列名(column names)或类型(types)。

-- 使用该路径下的文件,可以使用 * 代表所有文件  
CREATEFOREIGNTABLE parquet_table()   
SERVER pg_lake   
OPTIONS (path's3://testbucketpglake/parquet_data/*.parquet');  

-- 注意,我们从文件中推断列  
\d parquet_table  
              Foreign table "public.parquet_table"  
 Column |  Type   | Collation | Nullable | Default | FDW options   
--------+---------+-----------+----------+---------+-------------  
 key    | integer |           |          |         |   
 val    | text    |           |          |         |   
Server: pg_lake  
FDW options: (path 's3://testbucketpglake/parquet_data/*.parquet')  

-- 然后,查询它  
select count(*) from parquet_table;  
 count   
-------  
   100  
(1 row)  

历史(History)

pg_lake开发(development)始于 2024 年初的 Crunchy Data,目标是将 Iceberg 引入 PostgreSQL。最初的几个月专注于构建外部查询引擎(external query engine)(即 DuckDB)的稳健集成(integration)。为了尽早推向市场,查询/导入/导出(query/import/export)功能以 [Crunchy Bridge for Analytics] 的名称提供给 [Crunchy Bridge] 客户。

接下来,我们开始构建 Iceberg (v2) 协议的全面实现(comprehensive implementation),支持事务(transactions)和几乎所有 PostgreSQL 特性(features)。2024 年 11 月,我们将 Crunchy Bridge for Analytics 重新发布为 Crunchy Data Warehouse,可在 Crunchy Bridge 和本地(on-premises)使用。

2025 年 6 月,**[Crunchy Data 被 Snowflake 收购]。在收购(acquisition)之后,Snowflake** 决定在 2025 年 11 月将该项目开源(open source)为 pg_lake。初始版本(initial version)是 3.0,因为它之前已经有两代产品。