Apache Iceberg 湖仓架构设计——动手实践 Apache Iceberg

128 阅读25分钟

我们已经探讨了 Apache Iceberg 湖仓背后的理论——其架构组件优势。现在,是时候通过一个动手实操(hands-on)把它“落地”:在你的笔记本电脑上搭建一个可完整运行的 Iceberg 湖仓

本章将带你完成一个端到端的搭建流程:从安装本地环境,到创建 Iceberg 表,使用 Dremio 进行查询,并在 BI(Business Intelligence) 仪表盘中进行可视化。读完本章,你将拥有一个可操作的 Iceberg 湖仓环境,便于你进行实验,为你设计生产级实现提供信心与基础。

在本章场景中,我们将摄取一家时尚零售连锁销售交易数据,既包含商品品类,也包含门店位置客户画像及其对应的营销活动。这些业务数据最初存放在 PostgreSQL 数据库中;我们将使用 Apache Spark 将其抽取并转换为 Iceberg 表。随后在 Dremio 中对这些 Iceberg 表进行整理,创建虚拟视图以呈现按区域按客户细分按活动效果的销售趋势。这些视图将驱动 Apache Superset 中的交互式仪表盘,为市场、销售与商品团队提供准实时洞察,以优化选品与活动策略。

下方 图 2.1 展示了本次实操流程的示意:

image.png

图 2.1 第 2 章动手练习的流程。

本章代码见:github.com/AlexMercedC…

让我们动手,上手 Apache Iceberg 吧!

2.1 搭建 Apache Iceberg 环境(Setting up an Apache Iceberg environment)

为演示如何与 Iceberg 表协作,我们将搭建一个端到端的本地湖仓环境。我们会使用 Docker Compose 启动一组代表典型分析技术栈的关键服务,包括:

  • 业务数据库(Operational Database)PostgreSQL(模拟事务型系统)
  • 数据湖存储层(Data Lake Storage Layer)MinIO(兼容 S3 的对象存储)
  • 摄取与处理层(Ingestion & Processing Layer)Apache Spark
  • 目录层(Catalog Layer)Nessie(用于跟踪 Iceberg 表)
  • 查询引擎(Query Engine)Dremio(用于执行高速 SQL 查询)
  • BI 与可视化(BI & Visualization)Apache Superset(用于仪表盘)

这些组件在 Apache Iceberg 湖仓 中都扮演关键角色。通过本地部署,我们可以观察它们在真实场景中的协同方式。关于这些角色的其他可选方案,我们会在后续讨论 Iceberg 湖仓各层时进一步展开。图 2.2 展示了第 1 章所述的 Iceberg 湖仓环境组件。 image.png

图 2.2 Apache Iceberg 数据湖仓的组成组件。

2.1.1 前置条件:安装 Docker(Prerequisites: Install Docker)

开始之前,你需要在机器上安装 Docker Desktop。若尚未安装,可前往 docker.com 免费下载并安装。Docker 允许我们创建用于运行软件的“容器(containers) ”虚拟环境,因此无需在笔记本上逐个安装 Nessie、Apache Spark、Dremio 等软件。

安装完成后,在终端执行以下命令,确认 Docker 已在运行:

docker --version

image.png

图 2.3 展示了检查 Docker 是否安装的预期输出示例。若看到与 图 2.3 类似的输出,即表示 Docker 已安装就绪。

2.1.2 创建 Docker Compose 文件(Creating the Docker compose file)

现在来定义我们的环境。在一个空目录中新建 docker-compose.yml 文件,并加入下方代码片段中的配置(完整代码见文末 GitHub 仓库链接)。在这个 Docker Compose 配置中,我们为本机部署湖仓所需的不同服务:包括目录(Nessie)存储层(MinIO)联邦/集成工具(Dremio)摄取工具(Spark)以及消费工具(Superset) 。我们指定了要使用的 Docker 镜像以及每个容器需要映射的网络端口,从而在本地运行一个完整的湖仓环境

代码链接:
github.com/AlexMercedC…

文件中可以看到如下代码示例:

version: "3"
Services:
  Nessie:
    image: projectnessie/nessie:latest
    container_name: nessie
    networks:
      lakehouse-net:
    ports:
      - 19120:19120

Docker Compose 配置定义了一个使用内存型存储后端Project Nessie 目录服务。服务名为 nessie,基于 Project Nessie 的最新版镜像。它被分配到名为 lakehouse-net 的自定义网络,以便与同一网络中的其他服务(如 Apache SparkDremio 等计算引擎)通信。容器将 19120 端口在主机与容器中一一映射,便于从外部访问 Nessie 的 REST API。由于此配置使用的是内存存储,适合开发或测试环境(重启后无需持久化)。

  Minio:
    image: minio/minio:latest
    container_name: minio
    environment:
      - MINIO_ROOT_USER=admin
      - MINIO_ROOT_PASSWORD=password
      - MINIO_REGION=us-east-1
    networks:
      lakehouse-net:
    ports:
      - 9001:9001
      - 9000:9000
    command: ["server", "/data", "--console-address", ":9001"]

该服务定义启动一个本地 MinIO 服务器,这是一种高性能、兼容 Amazon S3 API 的对象存储系统。服务名为 Minio,使用最新版 MinIO 镜像。通过环境变量配置根用户凭据与区域(us-east-1)。容器加入 lakehouse-net 网络,便于与湖仓架构中的其他组件通信。暴露两个端口:9000(S3 兼容 API 访问)与 9001(MinIO Web 控制台)。命令指定将 /data 作为存储目录,并将管理控制台绑定到 9001 端口,便于通过浏览器访问。该配置适用于在 Iceberg 兼容环境中测试或原型化对象存储层

  Dremio:
    image: dremio/dremio-oss:latest
    container_name: dremio
    networks:
      lakehouse-net:
    ports:
      - 9047:9047
      - 31010:31010
      - 32010:32010

该服务定义了一个运行 Dremio 的容器。Dremio(开源版) 是为湖仓架构设计的高性能 SQL 查询引擎。服务使用 Dremio 最新开源镜像,名为 dremio。其加入 lakehouse-net 网络,能与 MinIO(存储)Nessie(目录) 等组件交互。容器暴露三个端口:9047(Dremio UI 与 REST API)、31010(JDBC 客户端连接)与 32010(Dremio 分布式引擎内部通信)。该配置让 Dremio 作为交互式查询平台,能够在多个数据源间进行联邦访问,并为 Iceberg 表提供统一的 SQL 接口。

  Spark:
    image: alexmerced/spark35nb:latest
    container_name: spark
    networks:
      lakehouse-net:
    ports:
      - 8080:8080  # Master Web UI
      - 7077:7077  # Master Port
      - 8888:8888  # Jupyter Notebook
    environment:
      - AWS_ACCESS_KEY_ID=admin
      - AWS_SECRET_ACCESS_KEY=password
      - AWS_DEFAULT_REGION=us-east-1
      - AWS_REGION=us-east-1

该服务启动了一个 Apache Spark 容器,面向开发与湖仓实验。它使用 alexmerced/spark35nb:latest 镜像,其中包含 Spark 3.5Jupyter Notebook 便于交互式开发。容器名为 spark,加入 lakehouse-net 网络,可与 MinIONessie 等服务交互。暴露三个端口:8080(Spark Master Web UI)、7077(Master 端口,供 worker/driver 使用)以及 8888(Jupyter Notebook)。环境变量为 Spark 提供 S3 兼容的访问凭据,从而通过 S3 API 无缝读写 MinIO。该配置便于运行 Spark 作业,或通过 Jupyter 交互式探索 Iceberg 表,非常适合本地测试与原型开发

  Postgres:
    image: postgres:latest
    container_name: postgres
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
    networks:
      lakehouse-net:
    ports:
      - "5435:5432"

该服务配置了一个 PostgreSQL 容器,作为湖仓架构示例中的业务数据源。服务使用官方最新版 PostgreSQL 镜像,并通过环境变量创建名为 mydb 的数据库与对应的用户凭据。它运行在共享网络 lakehouse-net 中,使 Spark 或其他摄取工具可以连接抽取数据。容器内部使用 5432 端口,对外映射为主机的 5435,以避免与本机现有 Postgres 实例冲突。该设置用于模拟一个事务型数据系统,从中可以周期性或持续性地将结构化数据摄取到湖仓供后续分析使用。

Superset:
    image: alexmerced/dremio-superset
    container_name: superset
    networks:
      lakehouse-net:
    ports:
      - 8088:8088
 
Networks:
  lakehouse-net:

该服务启动 Apache Superset,一款现代开源 BI 平台,且预配置为可与 Dremio 协同,用于湖仓环境中的可视化分析。它使用 alexmerced/dremio-superset 镜像,简化与 Dremio(作为后端 SQL 引擎)的集成。容器名为 superset,加入 lakehouse-net 网络,从而与 DremioIceberg 目录无缝联通。服务暴露 8088 端口,提供 Superset 的 Web 界面以构建仪表盘与探索数据。该配置允许用户通过 Dremio 交互式查询 Iceberg 表并在 Superset 中可视化结果,完成端到端分析流程

2.1.3 运行环境(Running the environment)

现在我们已经准备好了 Docker Compose 文件,开始启动湖仓环境。

在终端中,进入保存 docker-compose.yml 的目录并运行:

docker-compose up -d

这将会:

  • 启动 Nessie 目录,用于跟踪我们的 Iceberg 表
  • 启动 MinIO,作为存放 Iceberg 元数据数据文件的对象存储;
  • 部署 Dremio,基于 SQL 的查询引擎;
  • 设置 Apache Spark,用于将数据写入 Iceberg 表
  • 创建 PostgreSQL 数据库,模拟业务(事务)系统;
  • 初始化 Apache Superset,我们将在其中构建 BI 仪表盘。

验证一切是否已运行

一旦 Docker Compose 执行完成,运行下面的命令查看正在运行的容器:

docker ps

你应当能看到类似如下的输出:

CONTAINER ID   IMAGE                         STATUS         PORTS
xxxxxxxxxx     projectnessie/nessie:latest   Up 5 minutes   19120/tcp
xxxxxxxxxx     minio/minio:latest            Up 5 minutes   9000-9001/tcp
xxxxxxxxxx     dremio/dremio-oss:latest      Up 5 minutes   9047/tcp, 31010-32010/tcp
xxxxxxxxxx     alexmerced/spark35notebook    Up 5 minutes   7077/tcp, 8888/tcp
xxxxxxxxxx     postgres:latest               Up 5 minutes   5435->5432/tcp
xxxxxxxxxx     alexmerced/dremio-superset    Up 5 minutes   8088/tcp

如果所有容器都在运行,你的 Iceberg 湖仓就已就绪!参见图 2.4,了解 Docker 应创建的各容器网络(每个容器都有自己的 IP 地址)。

image.png

这些容器的协作流程是:当我们需要摄取新数据时,会编写 Python 脚本提交给 Spark 执行作业(本例中是从 Postgres 读取数据并写入 Iceberg 湖仓)。这些作业会将 Nessie 配置为目录、将 MinIO 配置为存储层。这使 Spark 明确所有数据与元数据文件都应写入 MinIO 中配置的位置;随后目录会更新到该表新创建或更新后的元数据
Dremio 同样会配置使用 NessieMinIO,以便浏览与管理数据集,并在这些表之上整理逻辑视图,为特定用例进行数据清洗与准备。我们可以将 Apache Superset 这类 BI 工具连接到 Dremio,作为 BI 仪表盘的数据源,从而直接基于我们的数据运行交互式可视化分析。

2.1.4 访问各项服务(Accessing the services)

现在来逐一验证每个服务是否可用:

  • MinIO(对象存储) :打开 http://localhost:9001,使用 admin/password 登录。
  • Dremio(查询引擎) :打开 http://localhost:9047,创建一个管理员账户。
  • Spark(数据处理) :打开 http://localhost:8888 访问 Jupyter Notebook
  • PostgreSQL(业务库) :使用 Postgres 客户端连接 localhost:5435,用户名 myuser,密码 mypassword
  • Superset(BI 仪表盘) :打开 http://localhost:8088,使用 admin/admin 登录(后续我们会进行初始化)。

至此,我们的湖仓环境已经运行起来了,接下来就可以正式使用它!

2.2 在 Spark 中创建 Iceberg 表(Creating Iceberg tables in Spark)

现在我们的 Apache Iceberg 湖仓环境已就绪,是时候开始处理真实数据了。在本阶段,我们将模拟通常存在于业务系统(如事务型 PostgreSQL 数据库)中的数据。本练习的数据代表零售场景中的销售交易:包括商品详情、销售金额、客户画像以及门店位置。这个数据集为后续分析提供了丰富基础,使我们能够探索客户行为趋势、营销活动效果以及区域表现

第一步是从 PostgreSQL 抽取数据。在真实生产中,这可能意味着连接到支撑业务应用的系统(POS 收银系统、CRM、电商平台等)。在这里,我们通过本地的 PostgreSQL 实例来模拟该环境,并预置了一份示例销售数据。需要重点考虑数据变更频率以及你采用批量加载、微批还是流式摄取——这些因素会影响稍后架构层面的决策(相关内容将在“摄取”章节详细介绍)。

接下来,我们使用 Apache Spark 将这些数据转换并写入 Apache Iceberg 表Apache Iceberg 提供了模式演进(schema evolution)时光回溯(time travel)分区等强大特性,是在湖仓中管理大规模、面向分析数据集的关键。

数据加载完成后,我们需要核验数据是否正确写入对象存储后端 MinIO,并确认 Nessie 目录追踪到了每一步操作Nessie 作为目录负责追踪与治理我们的 Iceberg 表,使任何需要使用这些表的工具都能便捷发现与访问,从而实现良好的工具互操作。这与现代湖仓架构中的数据工程工作流一致:将事务源数据摄入到开放、受治理、可扩展的存储格式中,为分析、报表甚至 AI/ML 训练做好准备。

2.2.1 填充 PostgreSQL 数据库(Populating the PostgreSQL database)

通过前面的 docker-compose up,我们的 PostgreSQL 容器已经在运行。现在我们向其中填充一份示例销售数据集。这些写入 PostgreSQL 的数据相当于业务系统产生的数据;我们的目标是把它迁移到像 Iceberg 湖仓这样的分析型系统中。

本小节的 SQL 也可在本书的 GitHub 仓库中找到:
github.com/AlexMercedC…

在终端执行以下命令,进入 Postgres Shell:

docker exec -it postgres psql -U myuser mydb

进入后,创建表并插入模拟数据:

CREATE TABLE fashion_sales (
    id SERIAL PRIMARY KEY,
    product_name VARCHAR(255),
    category VARCHAR(50),
    sales_amount DECIMAL(10, 2),
    sales_date DATE,
    store_location VARCHAR(100),
    customer_age_group VARCHAR(50),
    campaign_name VARCHAR(100)
);

INSERT INTO fashion_sales (product_name, category, sales_amount, sales_date, store_location, customer_age_group, campaign_name)
VALUES
    ('Slim Fit Jeans', 'Denim', 89.99, '2024-03-01', 'New York', '18-24', 'Spring Launch'),
    ('Leather Jacket', 'Outerwear', 249.99, '2024-03-01', 'Los Angeles', '25-34', 'Spring Launch'),
    ('Graphic T-Shirt', 'Tops', 39.99, '2024-03-02', 'Chicago', '18-24', 'March Madness'),
    ('Summer Dress', 'Dresses', 129.99, '2024-03-03', 'New York', '35-44', 'March Madness'),
    ('Casual Sneakers', 'Footwear', 99.99, '2024-03-03', 'Los Angeles', '25-34', 'Spring Launch');

退出 Postgres:

\q

此时,PostgreSQL 中已准备好可摄取进 Iceberg 表的数据集。

2.2.2 启动 Apache Spark 环境(Starting the Apache Spark environment)

现在我们将使用 Apache Spark(流行的开源数据处理引擎)从 PostgreSQL 抽取数据并写入 Iceberg 表。在使用 Spark 前,先为 Iceberg 表创建一个存储位置MinIO 将作为对象存储后端。

  1. 打开浏览器访问 http://localhost:9001 进入 MinIO 控制台,使用用户名 admin、密码 password 登录。
  2. 创建一个名为 warehousebucket,Spark 将把 Iceberg 表数据写入此处。

我们的 Spark 容器已在 Docker 环境中运行,并包含 Jupyter Notebook 以便交互式处理数据:

  • 打开 http://localhost:8888
  • 新建一个 Python Notebook 以编写 PySpark 脚本

你需要获取 MinIO 容器的 IP 地址,在终端执行:

docker network ls

根据输出找到正确的网络名(通常由你的 compose 目录名与 compose 文件底部的网络名拼接而成),然后执行:

docker network inspect <network_name>

在输出中找到 minio 容器的 IPv4 地址。该地址是容器在 Docker 网络中的唯一地址。通常直接用容器名(如 http://minio:9001)就能访问,但在本练习中 MinIO 有时可能无法通过 DNS 正确解析。为解决该问题,我们在 PySpark 脚本中直接使用 IP 指向 MinIO,从而确保网络连通。

image.png

图 2.5 检查 Docker 网络并查找各容器 IP 的示意。

2.2.3 为 Iceberg 配置 Apache Spark(Configuring Apache Spark for Iceberg)

Jupyter Notebook 中,粘贴并运行以下 Python 代码(Python 是编写 Spark 代码最常用的语言之一)。注意:把下面占位的 <minio_ip> 替换为前面查到的 MinIO IP

完整代码参见:
github.com/AlexMercedC…

import pyspark
from pyspark.sql import SparkSession  #A

## DEFINE VARIABLES #B
CATALOG_URI = "http://nessie:19120/api/v1"
WAREHOUSE = "s3://warehouse/"
STORAGE_URI = "http://<minio_ip>:9000"

说明:

  • import pysparkfrom pyspark.sql import SparkSession 引入 PySpark 库,用于创建/管理 SparkSession(DataFrame 操作入口)。
  • CATALOG_URI 指向 Nessie 目录的 REST 端点(追踪 Iceberg 表的元数据与版本)。
  • WAREHOUSE 指定 Iceberg 表在对象存储中的根位置(S3 兼容路径,指向我们刚创建的 warehouse bucket)。
  • STORAGE_URI 指定访问 MinIO 的地址,供 Spark 通过 S3 API 读写表数据(使用前面获得的 MinIO IP)。
    这些变量共同将 Spark 配置为:用 Nessie 进行表版本管理、用 MinIO 作为 Iceberg 兼容的存储层。
conf = (
    pyspark.SparkConf()
        .setAppName('Iceberg Ingestion')
        .set('spark.jars.packages', 
             'org.postgresql:postgresql:42.7.3,'
             'org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.5.0,'
             'org.projectnessie.nessie-integrations:nessie-spark-extensions-3.5_2.12:0.77.1,'
             'software.amazon.awssdk:bundle:2.24.8,'
             'software.amazon.awssdk:url-connection-client:2.24.8')
        .set('spark.sql.extensions', 
             'org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions,'
             'org.projectnessie.spark.extensions.NessieSparkSessionExtensions')
        .set('spark.sql.catalog.nessie', 'org.apache.iceberg.spark.SparkCatalog')
        .set('spark.sql.catalog.nessie.uri', CATALOG_URI)
        .set('spark.sql.catalog.nessie.ref', 'main')
        .set('spark.sql.catalog.nessie.authentication.type', 'NONE')
        .set('spark.sql.catalog.nessie.catalog-impl', 'org.apache.iceberg.nessie.NessieCatalog')
        .set('spark.sql.catalog.nessie.s3.endpoint', STORAGE_URI)
        .set('spark.sql.catalog.nessie.warehouse', WAREHOUSE)
        .set('spark.sql.catalog.nessie.io-impl', 'org.apache.iceberg.aws.s3.S3FileIO')
)

说明:

  • 通过 SparkConf 设置应用名 Iceberg Ingestion,并在 spark.jars.packages 中加载:PostgreSQL JDBC 驱动Iceberg Spark Runtime 3.5Nessie Spark 扩展、以及 AWS SDK(用于与 S3 兼容MinIO 通信)。
  • 注册 IcebergNessie 所需的 Spark Session 扩展
  • 定义逻辑目录 nessie 并指定其实现与配置(Nessie REST URI、分支 main、简化起见禁用认证、NessieCatalog 实现、S3 端点与仓库目录、采用 S3FileIO 进行读写)。
  • 这套配置让 Spark 作业可将数据写入由 Nessie 管理、存储在 MinIOIceberg 表,并具备时光回溯、分支、原子提交等能力。
spark = SparkSession.builder.config(conf=conf).getOrCreate()
print("Spark Running")

说明:

  • 使用前述 conf 初始化(或获取)SparkSession,这是与 Spark API 交互的入口,可读写 Iceberg 表
  • print("Spark Running") 用于确认 Spark 会话已成功启动,环境已准备好执行数据处理任务。

2.2.4 将 PostgreSQL 数据加载到 Iceberg(Loading data from PostgreSQL into Iceberg)

现在,连接 PostgreSQL,读取 sales_data(本例为 fashion_sales)表,并把它写入数据湖中的 Iceberg 表。这里的数据湖(本例中的 MinIO)是我们数据文件的存储库,典型实现是分布式存储(如 HDFS对象存储)。

将以下代码粘贴到 Jupyter Notebook 的新单元格并运行:

# Define the JDBC connection properties
jdbc_url = "jdbc:postgresql://postgres:5432/mydb"
properties = {
    "user": "myuser",
    "password": "mypassword",
    "driver": "org.postgresql.Driver"
}
 
# Read the sales_data table from Postgres into a Spark DataFrame
sales_df = spark.read.jdbc(url=jdbc_url, table="fashion_sales", properties=properties)
 
# Show the first few rows of the dataset
sales_df.show()

你应当能看到来自 PostgreSQL 的销售数据输出(见图 2.6)。

image.png

图 2.6 将源系统数据加载到 DataFrame

接下来,把这份数据写入由 Nessie 追踪的 Apache Iceberg 表。下面的命令会先创建一个“命名空间(namespace) ”(类似于你电脑上的子文件夹,用于组织数据集)。然后,我们将前面从 Postgres 读入并存到 Spark DataFrame 的表写入到 Iceberg 表;同时把数据文件写入 MinIO 存储,并更新 Nessie,使其知道该表的存在以及其元数据文件的位置

#Create a namespace
spark.sql("CREATE NAMESPACE nessie.sales;")
 
# Write the DataFrame to an Iceberg table in the Nessie catalog
sales_df.writeTo("nessie.sales.fashion_sales").createOrReplace()
 
# Verify that the data was written to Iceberg by reading the table
spark.read.table("nessie.sales.fashion_sales").show()

如果成功,你应当会看到已存入 Iceberg 的同样销售数据(见图 2.7)。

image.png

图 2.7 将数据写入 Iceberg 表并完成读取验证

2.2.5 在 MinIO 中验证数据存储(Verifying data storage in MinIO)

由于我们使用 MinIO 作为对象存储,下面来检查数据是否已正确写入:

  1. 打开 http://localhost:9001
  2. 使用 admin/password 登录
  3. 点击 warehouse bucket
  4. 依次进入 sales/sales_data/

你应该能看到Parquet 文件(存放我们的数据)以及JSON 与 AVRO 格式的元数据文件。其中,Parquet 文件代表实际数据;JSON 文件是 Iceberg “Metadata” 结构顶层的表级元数据(第一章已介绍其作用与层级);AVRO 文件则是该结构中的 “Manifest”“Manifest List”
这表明数据已通过 Spark 成功摄入 Iceberg 表,并以 Parquet 形式存放在 MinIO 对象存储中。 image.png

图 2.8 在 MinIO 数据湖中查看 Iceberg 表数据

现在我们的 Iceberg 表已经创建好,可以使用 Dremio(面向数据湖的高性能 SQL 引擎)对其进行查询与快速分析了。

2.3 在 Dremio 中读取 Iceberg 表(Reading Iceberg tables in Dremio)

我们已通过 Spark 成功将数据摄入 Apache Iceberg,现在该使用 Dremio 来查询这些 Iceberg 表了——Dremio 是为数据湖而生的湖仓查询引擎,可在数据湖上提供分析能力。全书后续还会讨论与 Apache Iceberg 集成的其他引擎(如 TrinoDuckDB),以便在为湖仓各层选型时全面了解 Iceberg 生态。

本节将演示如何将 Dremio 连接到 Nessie Catalog,从而访问并探索我们的 Apache Iceberg 表。连接建立后,我们会在 Dremio 界面用标准 SQL 查询之前摄取的销售数据集。这将展示:无需为数据建模而进行数据移动或复制,就能像在传统数据仓库中一样便捷地使用 Iceberg 表

在运行查询的同时,我们也会看看 Apache Iceberg 如何通过元数据裁剪(metadata pruning)等特性提升性能。Iceberg 维护了丰富的表元数据(如分区信息与文件级统计),使 Dremio 能在执行时跳过不必要的数据,即使数据集规模扩大也能保持较快查询性能。读完本节,你将看到:Iceberg 可以直接在数据湖上实现快速、高效的分析,提供接近数据仓库的查询体验,同时避免数据复制带来的复杂度和成本。

2.3.1 启动 Dremio(Starting Dremio)

Dremio 已作为我们 Docker Compose 环境的一部分在运行。访问方式:

  1. 在浏览器打开 http://localhost:9047
  2. 使用先前创建的 admin 账户登录

进入 Dremio UI 后,你可以将其连接至不同数据源,对这些数据源中的数据集运行 SQL,并跨多源执行查询(称为查询联邦,query federation)。Dremio 可连接的一类数据源就是湖仓目录(Lakehouse Catalog) (如 Nessie),从而快速发现并使用目录中登记的 Iceberg 表

2.3.2 将 Dremio 连接到 Nessie Catalog(Connecting Dremio to the Nessie Catalog)

在本例中,为了查询 Iceberg 表,需要把 Dremio 连接到 Iceberg Catalog(即我们的 Nessie)。我们以未配置鉴权的方式运行了 Nessie 容器,便于演示;在生产中,无论使用哪种目录,都应启用相应治理能力来管控用户对目录的访问。关于目录的更多选项,将在“目录”章节展开。按照以下步骤操作:

  1. 点击 “Add Source”
  2. 在可用源类型中选择 “Nessie”
  3. 填写以下设置:

General Settings

  • Source Name: nessie
  • Nessie Endpoint URL: http://nessie:19120/api/v2
  • Auth Type: None

image.png

(见图 2.9:配置 Nessie General Settings)

Storage Settings

  • AWS Root Path: warehouse
  • AWS Access Key: admin
  • AWS Secret Key: password
  • 取消勾选 “Encrypt Connection” (本例未使用 SSL)

image.png

(见图 2.10:配置 Nessie Storage Settings)

Connection Properties

fs.s3a.path.style.access = true
fs.s3a.endpoint = minio:9000
dremio.s3.compat = true

以上连接属性使 Dremio 能将其他“S3 兼容”存储当作 AWS S3 使用。MinIO 即为 S3 兼容存储;通过这些设置,Dremio 能正确连接至 MinIO 并定位文件。

image.png

(见图 2.11:配置 Nessie Connection Properties)

  1. 点击 “Save” 保存该 Nessie 源。添加完成后,Dremio 会自动发现 Nessie 中登记的 Iceberg 表

image.png

(见图 2.12:在 Dremio 平台中查看我们的 Iceberg 表)

2.3.3 在 Dremio 中查询 Iceberg 表(Querying Iceberg tables in Dremio)

现在 Dremio 已与 Nessie 连接,来对我们的 Iceberg 销售数据集执行一些 SQL 查询。在 Dremio 的 SQL Editor 中运行:

SELECT * FROM nessie.sales.fashion_sales;

你应当看到与最初从 PostgreSQL 摄取的相同销售数据——它现在以 Iceberg 表 的形式存放在 MinIO 中。Iceberg 的一大优势是其基于元数据的裁剪(metadata-driven pruning) :通过跳过无关数据文件来加速查询。表的元数据为每个文件提供统计信息,使得像 Dremio 这样的引擎可以跳过不包含目标数据的文件。例如:如果只需扫描 sales_amount = 35 的记录,而某个文件的元数据指明该列数值范围是 38–40,引擎即可直接跳过该文件。

查看表元数据(Checking table metadata)

要查看某个 Iceberg 元数据表,运行:

SELECT * FROM TABLE( table_snapshot( 'nessie.sales.fashion_sales' ) )

该结果会显示快照(snapshot)列表,即表的历史版本;其 snapshot_id 可用于时光回溯(time travel)查询。借助这些信息(如 snapshot_id),即可使用 Iceberg时光回溯能力。

image.png

图 2.13 在 Dremio 中查询表的快照历史

使用快照进行时光回溯(Using Time Travel with Iceberg Snapshots)

Iceberg 支持时光回溯,允许你查询数据集的历史版本。

  • 按快照 ID 时光回溯:
SELECT * FROM nessie.sales.sales_data AT SNAPSHOT <snapshot_id>;
  • 按时间戳 时光回溯:
SELECT * FROM nessie.sales.sales_data AT TIMESTAMP <timestamp>;

时光回溯查询可用于调试数据(查看早期版本以定位错误),也可用于审计与合规(提供历史数据以供检视)。

2.4 基于你的 Iceberg 表创建 BI 仪表盘(Creating a BI dashboard from your Iceberg tables)

我们已经把数据成功摄入 Apache Iceberg,并用 Dremio 完成了查询。现在更进一步:构建一个 BI 仪表盘,将洞察可视化。

本节我们将把 Apache Superset 连接到 Dremio,基于 Iceberg 表创建数据集(dataset),并设计交互式图表与仪表盘。完成后,你将拥有一个由 Dremio + Apache Iceberg 驱动的在线 BI 仪表盘,展示开放湖仓分析的威力。

2.4.1 启动 Apache Superset(Starting Apache Superset)

Apache Superset 是开源 BI 工具,支持基于 SQL 的数据源创建交互式仪表盘与可视化。若 Superset 尚未运行,执行:

docker-compose up -d superset

然后初始化 Superset(创建默认用户、元数据库表与角色):

docker exec -it superset superset init

初始化完成后,打开浏览器访问 http://localhost:8088,使用以下凭据登录:

  • Username: admin
  • Password: admin

进入 Superset 首页后,我们将其与 Dremio 连接。

2.4.2 将 Superset 连接到 Dremio(Connecting Superset to Dremio)

需要在 Superset 中把 Dremio 配置为数据源:

  1. 点击 Settings → Database Connections

  2. 点击 + Add Database

  3. 数据库类型选择 “Other”

  4. Dremio URI 输入:

    dremio+flight://USERNAME:PASSWORD@dremio:32010/?UseEncryption=false
    

    (将 USERNAMEPASSWORD 替换为你的 Dremio 凭据)

  5. 点击 Test Connection 测试连接

  6. 点击 Save

至此,Superset 已成功连接 Dremio!该 URI 使用 Dremio 的 Arrow Flight 协议(第 7、8 章会谈到通信协议)以获得快速高效的数据访问。此处为本地环境关闭加密;生产环境应将 UseEncryption=true 以启用安全连接。USERNAME/PASSWORD 使用你的 Dremio 管理员账户。

image.png

图 2.14 从 Superset 连接 Dremio

2.4.3 基于 Iceberg 表创建数据集(Creating a dataset from Iceberg tables)

连接完成后,从我们的 Iceberg 表创建一个数据集:

  1. 右上角点击 + → Create Dataset
  2. 选择 Dremio 作为数据库
  3. 导航到 nessie.sales.fashion_sales
  4. 点击 Create Dataset

image.png

图 2.15 在 Superset 中基于我们的 Iceberg 表创建新数据集

这样就可以用该表来创建图表与仪表盘了。

2.4.4 构建图表与仪表盘(Building charts and dashboards)

现在用一些交互式图表来可视化 Iceberg 数据。Apache Superset 的流程很直观:从数据源添加数据集 → 基于数据集创建图表 → 把多个图表组合成一个仪表盘,并分享给需要查看数据的人。

创建折线图(Line Chart)

  1. 点击 + → Create Chart

  2. 选择数据集 sales_data(注:若你用的是 fashion_sales,请在界面中选择对应数据集)

  3. 图表类型选择 Line Chart

  4. 设置:

    • X-Axis: sales_date
    • Metric: SUM(sales_amount)
  5. 点击 Run Query 预览

  6. 点击 Save,命名为 Sales by Day,并添加到新建仪表盘

image.png

图 2.16 由我们的 Iceberg 数据生成的折线图

再创建一个饼图(Pie Chart)

  1. 点击 + Create Chart

  2. 选择数据集 sales_data

  3. 图表类型选择 Pie Chart

  4. 设置:

    • Dimension: category
    • Metric: SUM(sales_amount)
  5. 点击 Run Query 生成图表

  6. 点击 Save,命名为 Sales by Category,并添加到仪表盘

image.png

图 2.17 在 Superset 中基于我们的 Iceberg 数据生成的饼图

组合成一个仪表盘

  1. 点击 Dashboards → + Create Dashboard

  2. 命名为 Sales Analytics

  3. 点击 + Add Chart,选择:

    • Sales by Day
    • Sales by Category
  4. 调整图表大小与布局

  5. 点击 Save & Publish

image.png

图 2.18 在 Superset 中基于我们的 Iceberg 数据搭建的仪表盘

现在,你已经拥有一个完全可用的 BI 仪表盘,直接运行在你的数据湖之上的 Apache Iceberg 数据之上!你会注意到:使用 Apache Superset 等工具与使用任何数据库/数据仓库中的表并无二致——这正是重点。你现在拥有以开放格式提供的表,能被整个企业复用,而无需改变消费数据的方式。由于使用的是 Iceberg,本练习中使用的任何工具都可以与其他兼容工具互换,这正体现了 Apache Iceberg 模块化生态的价值。

结束后关闭环境,执行:

docker compose down -v

其中 -v 标志指示 Docker 清理为各容器创建的存储卷(volumes) ,释放运行这些容器时占用的存储空间。

在下一章中,我们将回到全局视角,评估你当前的数据基础设施,并开始规划如何在真实环境中采纳 Iceberg:从定义架构需求到选择合适的组件,以实现一次成功的落地实施。

2.5 小结(Summary)

  • Apache Iceberg 通过提供丰富的元数据管理schema 演进ACID 保证,将传统数据湖转变为高性能分析平台
  • 可使用 Docker Compose 搭建本地 Apache Iceberg 湖仓环境,部署 MinIO、Apache Spark、Nessie、Dremio、Superset、PostgreSQL 等服务。
  • MinIO 作为对象存储层,存放 Iceberg 表的数据文件与元数据文件,实现对云存储的本地化模拟。
  • Project Nessie 作为目录(catalog) ,跟踪 Iceberg 表,便于 Apache SparkDremio 发现与使用。
  • Apache SparkPostgreSQL 业务库抽取销售数据,完成转换,并将其加载到由 Nessie 管理的 Iceberg 表中。
  • Dremio 连接 Nessie 目录,直接从对象存储查询 Iceberg 表,支撑分析型工作负载。
  • Apache Superset 连接 Dremio,基于 Iceberg 湖仓环境创建交互式 BI 仪表盘,将洞察可视化展示。