

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 最佳化 Apache Iceberg 工作負載的最佳實務
<a name="best-practices"></a>

Iceberg 是一種資料表格式，旨在簡化資料湖管理並增強工作負載效能。不同的使用案例可能會優先考慮不同的層面，例如成本、讀取效能、寫入效能或資料保留，因此 Iceberg 提供組態選項來管理這些權衡。本節提供最佳化和微調 Iceberg 工作負載以符合需求的洞見。

**Topics**
+ [一般最佳實務](best-practices-general.md)
+ [最佳化讀取效能](best-practices-read.md)
+ [最佳化寫入效能](best-practices-write.md)
+ [最佳化儲存體](best-practices-storage.md)
+ [使用壓縮來維護資料表](best-practices-compaction.md)
+ [在 Amazon S3 中使用 Iceberg 工作負載](best-practices-workloads.md)

# 一般最佳實務
<a name="best-practices-general"></a>

無論您的使用案例為何，當您在 上使用 Apache Iceberg 時 AWS，我們建議您遵循這些一般最佳實務。
+ **使用 Iceberg 格式第 2 版。**

  Athena 預設使用 Iceberg 格式第 2 版。

  當您在 Amazon EMR 上使用 Spark 或 AWS Glue 建立 Iceberg 資料表時，請指定 [Iceberg 文件](https://iceberg.apache.org/docs/nightly/configuration/#reserved-table-properties)所述的格式版本。
+ **使用 AWS Glue Data Catalog 做為您的資料目錄。**

  Athena AWS Glue Data Catalog 預設會使用 。

  當您在 Amazon EMR 上使用 Spark 或使用 AWS Glue Iceberg 時，請將下列組態新增至 Spark 工作階段以使用 AWS Glue Data Catalog。如需詳細資訊，請參閱本指南稍早[中 Iceberg 的 Spark 組態 AWS Glue](iceberg-glue.md#glue-spark-config)一節。

  ```
  "spark.sql.catalog.<your_catalog_name>.type": "glue"
  ```
+ **使用 AWS Glue Data Catalog 做為鎖定管理員。**

  根據預設，Athena 會使用 AWS Glue Data Catalog 做為 Iceberg 資料表的鎖定管理員。

  當您在 Amazon EMR 上使用 Spark 或使用 AWS Glue Iceberg 時，請務必將 Spark 工作階段組態設定為使用 AWS Glue Data Catalog 做為鎖定管理員。如需詳細資訊，請參閱 Iceberg 文件中的[樂觀鎖定](https://iceberg.apache.org/docs/latest/aws/#optimistic-locking)。
+ **使用 Zstandard (ZSTD) 壓縮。**

  Iceberg 的預設壓縮轉碼器是 gzip，可以使用資料表屬性 修改`write.<file_type>.compression-codec`。Athena 已使用 ZSTD 做為 Iceberg 資料表的預設壓縮轉碼器。

  一般而言，我們建議您使用 ZSTD 壓縮轉碼器，因為它在 GZIP 和 Snappy 之間取得平衡，並提供良好的讀取/寫入效能，而不會影響壓縮率。此外，可以調整壓縮層級以符合您的需求。如需詳細資訊，請參閱 [Athena 文件中的 Athena 中的 ZSTD 壓縮層級](https://docs.aws.amazon.com/athena/latest/ug/compression-support-zstd-levels.html)。

  Snappy 可能會提供最佳的整體讀取和寫入效能，但壓縮比率低於 GZIP 和 ZSTD。如果您優先考慮效能，即使這意味著在 Amazon S3 中存放較大的資料磁碟區，Snappy 仍可能是最佳選擇。

# 最佳化讀取效能
<a name="best-practices-read"></a>

本節討論您可以調校的資料表屬性，以最佳化讀取效能，不受引擎影響。

## 分割
<a name="read-partitioning"></a>

如同 Hive 資料表，Iceberg 使用分割區做為索引的主要層，以避免讀取不必要的中繼資料檔案和資料檔案。資料欄統計資料也會納入考量，做為索引的輔助層，以進一步改善查詢規劃，進而改善整體執行時間。

### 分割您的資料
<a name="read-partitioning-data"></a>

若要減少查詢 Iceberg 資料表時掃描的資料量，請選擇符合您預期讀取模式的平衡分割區策略：
+ 識別查詢中經常使用的資料欄。這些是理想的分割候選項目。例如，如果您通常查詢特定日期的資料，分割區資料欄的自然範例會是日期資料欄。
+ 選擇低基數分割區資料欄，以避免建立過多分割區。太多分割區可能會增加資料表中的檔案數量，這可能會對查詢效能產生負面影響。根據經驗法則，「太多分割區」可定義為大多數分割區中的資料大小小於 所設定值的 2-5 倍的情況`target-file-size-bytes`。

**注意**  
如果您通常會在高基數資料欄 （例如，可以有數千個值的資料`id`欄） 上使用篩選條件進行查詢，請使用 Iceberg 的隱藏分割功能與儲存貯體轉換，如下一節所述。

### 使用隱藏的分割
<a name="read-partitioning-hidden"></a>

如果您的查詢通常會篩選資料表資料欄的衍生項目，請使用隱藏的分割區，而不是明確建立新的資料欄以做為分割區。如需此功能的詳細資訊，請參閱 [Iceberg 文件](https://iceberg.apache.org/docs/latest/partitioning/#icebergs-hidden-partitioning)。

例如，在具有時間戳記資料欄 （例如，`2023-01-01 09:00:00`) 的資料集中，使用分割區轉換從時間戳記擷取日期部分，並即時建立這些分割區，而不是建立具有剖析日期的新資料欄 （例如，`2023-01-01`)。

隱藏分割最常見的使用案例為：
+ 當資料具有時間戳記資料欄時，**依日期或時間進行分割**。Iceberg 提供多種轉換，以擷取時間戳記的日期或時間部分。
+ **當分割資料欄具有高基數且會導致太多分割區時，對資料欄的雜湊函數**進行分割。Iceberg 的儲存貯體轉換會使用分割區欄上的雜湊函數，將多個分割區值分組為較少的隱藏 （儲存貯體） 分割區。

如需所有可用[分割區轉換](https://iceberg.apache.org/spec/#partition-transforms)的概觀，請參閱 Iceberg 文件中的分割區轉換。

用於隱藏分割的資料欄可透過使用 `year()`和 等一般 SQL 函數，成為查詢述詞的一部分`month()`。述詞也可以與 `BETWEEN`和 等運算子結合`AND`。

**注意**  
Iceberg 無法對產生不同資料類型的函數執行分割區剔除；例如，`substring(event_time, 1, 10) = '2022-01-01'`。

### 使用分割區演變
<a name="read-partitioning-evolution"></a>

當現有的[分割區策略不最佳時，請使用 Iceberg 的分割區演變](https://iceberg.apache.org/docs/latest/evolution/#partition-evolution)。例如，如果您選擇每小時分割區太小 （每個分割區只有幾個 MB)，請考慮轉換為每日或每月分割區。

當資料表的最佳分割區策略一開始不清楚，而且您想要在獲得更多洞見時精簡分割區策略時，您可以使用此方法。分割區演變的另一個有效用途是資料磁碟區變更，且目前的分割區策略會隨著時間而變得較不有效。

如需如何發展分割區的說明，請參閱 Iceberg 文件中的 [ALTER TABLE SQL 延伸](https://iceberg.apache.org/docs/latest/spark-ddl/#alter-table-sql-extensions)。 

## 調校檔案大小
<a name="read-file-size"></a>

最佳化查詢效能涉及將資料表中的小型檔案數量降至最低。為了獲得良好的查詢效能，我們通常建議將 Parquet 和 ORC 檔案保留大於 100 MB。

檔案大小也會影響 Iceberg 資料表的查詢規劃。隨著資料表中的檔案數量增加，中繼資料檔案的大小也會增加。較大的中繼資料檔案可能會導致較慢的查詢規劃。因此，當資料表大小增加時*，*請增加檔案大小** **以減輕中繼資料的指數擴展。

使用下列最佳實務，在 Iceberg 資料表中建立適當大小的檔案。

### 設定目標檔案和資料列群組大小
<a name="read-file-size-target"></a>

Iceberg 提供下列關鍵組態參數來調校資料檔案配置。我們建議您使用這些參數來設定目標檔案大小和資料列群組或執行大小。


| **Parameter (參數)** | **預設值** | **註解** | 
| --- |--- |--- |
| `write.target-file-size-bytes` | 512 MB | 此參數指定 Iceberg 將建立的檔案大小上限。不過，某些檔案的寫入大小可能會小於此限制。 | 
| `write.parquet.row-group-size-bytes` | 128 MB | Parquet 和 ORC 都會將資料存放在區塊中，以便引擎可以避免讀取某些操作的整個檔案。 | 
| `write.orc.stripe-size-bytes` | 64 MB | 
| `write.distribution-mode` | 無，適用於 Iceberg 1.1 版和更低版本雜湊，從 Iceberg 1.2 版開始 | Iceberg 會請求 Spark 在寫入儲存體之前排序其任務之間的資料。 | 
+ 根據您預期的資料表大小，請遵循下列一般準則：
  + **小型資料表** （最多幾個 GB) – 將目標檔案大小縮減至 128 MB。同時減少資料列群組或條紋大小 （例如 8 或 16 MB)。
  + **中大型資料表** （從幾 GB 到數百 GB) – 預設值是這些資料表的良好起點。如果您的查詢非常選擇性，請調整資料列群組或條紋大小 （例如，調整為 16 MB)。
  + **非常大的資料表** （數百 GB 或 TB) – 將目標檔案大小增加到 1024 MB 或更多，如果您的查詢通常提取大量資料集，請考慮增加資料列群組或條紋大小。
+ 若要確保寫入 Iceberg 資料表的 Spark 應用程式建立適當大小的檔案，請將 `write.distribution-mode` 屬性設定為 `hash`或 `range`。如需這些模式之間差異的詳細說明，請參閱 Iceberg 文件中的[撰寫分佈模式](https://iceberg.apache.org/docs/latest/spark-writes/#writing-distribution-modes)。

這些是一般準則。建議您執行測試，以識別特定資料表和工作負載最合適的值。

### 執行定期壓縮
<a name="read-file-size-compaction"></a>

上表中的組態會設定寫入任務可建立的檔案大小上限，但不保證檔案會有該大小。為了確保適當的檔案大小，請定期執行壓縮，將小型檔案合併成較大的檔案。如需執行壓縮的詳細指引，請參閱本指南稍後的 [Iceberg 壓縮](best-practices-compaction.md)。

## 最佳化資料欄統計資料
<a name="read-column-statistics"></a>

Iceberg 使用資料欄統計資料來執行檔案刪除，透過減少查詢掃描的資料量來改善查詢效能。若要受益於資料欄統計資料，請確定 Iceberg 會收集查詢篩選條件中常用的所有資料欄統計資料。

根據預設，Iceberg 只會收集[每個資料表中前 100 個資料欄](https://github.com/apache/iceberg/blob/ae15c7e36973501b40443e75816d3eac39eddc90/core/src/main/java/org/apache/iceberg/TableProperties.java#L276)的統計資料，如資料表屬性 所定義`write.metadata.metrics.max-inferred-column-defaults`。如果您的資料表有超過 100 個資料欄，而且您的查詢經常參考前 100 個資料欄以外的資料欄 （例如，您可能有篩選資料欄 132 的 查詢），請確定 Iceberg 收集這些資料欄的統計資料。有兩種選項可達成此目標：
+ 當您建立 Iceberg 資料表時，請重新排序資料欄，以便查詢所需的資料欄落在 設定的資料欄範圍內 `write.metadata.metrics.max-inferred-column-defaults`（預設為 100)。

  注意：如果您不需要 100 個資料欄的統計資料，您可以將`write.metadata.metrics.max-inferred-column-defaults`組態調整為所需的值 （例如 20) 並重新排序資料欄，以便您需要讀取和寫入查詢的資料欄落在資料集左側的前 20 個資料欄內。
+ 如果您在查詢篩選條件中只使用幾個資料欄，您可以停用指標收集的整體屬性，並選擇性地選擇要收集統計資料的個別資料欄，如本範例所示：

  ```
  .tableProperty("write.metadata.metrics.default", "none")
  .tableProperty("write.metadata.metrics.column.my_col_a", "full")
  .tableProperty("write.metadata.metrics.column.my_col_b", "full")
  ```

注意：當資料對這些資料欄進行排序時，資料欄統計資料最有效。如需詳細資訊，請參閱本指南稍後的設定[排序順序](#read-sort-order)一節。

## 選擇正確的更新策略
<a name="read-update"></a>

當您的使用案例接受較慢的寫入操作時，請使用copy-on-write策略來最佳化讀取效能。這是 Iceberg 使用的預設策略。

Copy-on-write可提高讀取效能，因為檔案是以讀取最佳化的方式直接寫入儲存體。不過，相較於merge-on-read，每個寫入操作需要更長的時間，並耗用更多運算資源。這提供了讀取和寫入延遲之間的傳統取捨。一般而言，copy-on-write非常適合大多數更新共置於相同資料表分割區 （例如，用於每日批次載入） 的使用案例。

Copy-on-write組態 (`write.update.mode`、 `write.delete.mode`和 `write.merge.mode`) 可以在資料表層級設定，或在應用程式端獨立設定。

## 使用 ZSTD 壓縮
<a name="read-compression"></a>

您可以使用資料表屬性 修改 Iceberg 使用的壓縮轉碼器`write.<file_type>.compression-codec`。我們建議您使用 ZSTD 壓縮轉碼器來改善資料表的整體效能。

根據預設，Iceberg 1.3 版和更早版本使用 GZIP 壓縮，相較於 ZSTD，其提供較慢的讀取/寫入效能。

注意：某些引擎可能會使用不同的預設值。對於[使用 Athena 或 Amazon EMR 7.x 版建立的 Iceberg 資料表](https://docs.aws.amazon.com/athena/latest/ug/compression-support-iceberg.html)，這是這種情況。

## 設定排序順序
<a name="read-sort-order"></a>

為了改善 Iceberg 資料表的讀取效能，建議您根據查詢篩選條件中常用的一或多個資料欄來排序資料表。排序結合 Iceberg 的資料欄統計資料，可大幅提高檔案剔除的效率，進而加快讀取操作。排序也會減少在查詢篩選條件中使用排序資料欄之查詢的 Amazon S3 請求數量。

您可以使用 Spark 執行資料定義語言 (DDL) 陳述式，在資料表層級設定階層排序順序。如需可用選項，請參閱 [Iceberg 文件](https://iceberg.apache.org/docs/latest/spark-ddl/#alter-table--write-ordered-by)。設定排序順序後，寫入器會將此排序套用至 Iceberg 資料表中的後續資料寫入操作。

例如，在大部分查詢依 篩選的日期 (`yyyy-mm-dd`) 分割的資料表中`uuid`，您可以使用 DDL 選項來`Write Distributed By Partition Locally Ordered`確保 Spark 寫入具有非重疊範圍的檔案。

下圖說明排序資料表時，資料欄統計資料的效率如何改善。在此範例中，排序的資料表只需要開啟單一檔案，並從 Iceberg 的分割區和檔案獲得最大效益。在未排序的資料表中，任何 `uuid` 都可能存在於任何資料檔案中，因此查詢必須開啟所有資料檔案。

![\[在 Iceberg 資料表中設定排序順序\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/apache-iceberg-on-aws/images/setting-sort-order.png)


變更排序順序不會影響現有的資料檔案。您可以使用 Iceberg 壓縮來套用排序順序。

使用 Iceberg 排序資料表可能會降低工作負載的成本，如下圖所示。

![\[Iceberg 和 Parquet 資料表的比較成本\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/apache-iceberg-on-aws/images/cost-graph.png)


這些圖表摘要了執行 Hive (Parquet) 資料表與 Iceberg 排序資料表的 TPC-H 基準測試的結果。不過，其他資料集或工作負載的結果可能不同。

![\[Parquet 與 Iceberg 資料表的 TPC-H 基準結果\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/apache-iceberg-on-aws/images/s3-api-calls.png)


# 最佳化寫入效能
<a name="best-practices-write"></a>

本節討論您可以調校的資料表屬性，以最佳化 Iceberg 資料表的寫入效能，不受引擎影響。

## 設定資料表分佈模式
<a name="write-distribution-mode"></a>

Iceberg 提供多種寫入分佈模式，可定義寫入資料在 Spark 任務中的分佈方式。如需可用模式的概觀，請參閱 Iceberg 文件中的[撰寫分佈模式](https://iceberg.apache.org/docs/latest/spark-writes/#writing-distribution-modes)。

對於優先考慮寫入速度的使用案例，特別是在串流工作負載中，請將 `write.distribution-mode`設定為 `none`。這可確保 Iceberg 不會請求額外的 Spark 隨機播放，而且資料會在 Spark 任務中可用時寫入。此模式特別適合 Spark 結構化串流應用程式。

**注意**  
將寫入分佈模式設定為 `none` 往往會產生許多小型檔案，進而降低讀取效能。我們建議定期壓縮，將這些小型檔案合併為適當大小的檔案，以獲得查詢效能。

## 選擇正確的更新策略
<a name="write-update-strategy"></a>

當您的使用案例接受最新資料的較慢讀取操作時，請使用merge-on-read** **策略來最佳化寫入效能。

當您使用merge-on-read，Iceberg 會將更新寫入儲存，並刪除為個別的小型檔案。讀取資料表時，讀取器必須將這些變更與基礎檔案合併，以傳回資料的最新檢視。這會導致讀取操作的效能懲罰，但可加快更新和刪除的寫入速度。一般而言，merge-on-read非常適合具有更新或任務的串流工作負載，這些更新較少，且分散在許多資料表分割區中。

您可以在資料表層級或應用程式端獨立設定merge-on-read組態 (`write.delete.mode`、 `write.update.mode`和 `write.merge.mode`)。

使用merge-on-read需要執行定期壓縮，以防止讀取效能隨著時間降低。壓縮會與現有的資料檔案協調更新和刪除，以建立新的一組資料檔案，從而消除讀取端產生的效能損失。根據預設，除非您將 `delete-file-threshold` 屬性的預設值變更為較小的值，否則 Iceberg 的壓縮不會合併刪除檔案 （請參閱 [Iceberg 文件](https://iceberg.apache.org/docs/latest/spark-procedures/#rewrite_data_files))。若要進一步了解壓縮，請參閱本指南稍後的 [Iceberg 壓縮](best-practices-compaction.md)一節。

## 選擇正確的檔案格式
<a name="write-file-format"></a>

Iceberg 支援以 Parquet、ORC 和 Avro 格式寫入資料。Parquet 是預設格式。Parquet 和 ORC 是單欄式格式，可提供卓越的讀取效能，但寫入速度通常較慢。這代表讀取和寫入效能之間的典型取捨。

如果寫入速度對您的使用案例很重要，例如在串流工作負載中，請考慮在寫入器的選項`Avro`中`write-format`將 設定為 ，以 Avro 格式寫入。由於 Avro 是以資料列為基礎的格式，因此能以較慢的讀取效能提供更快的寫入時間。

為了改善讀取效能，請執行定期壓縮，將小型 Avro 檔案合併並轉換為較大的 Parquet 檔案。壓縮程序的結果由`write.format.default`資料表設定管理。Iceberg 的預設格式為 Parquet，因此如果您在 Avro 中寫入 ，然後執行壓縮，Iceberg 會將 Avro 檔案轉換為 Parquet 檔案。範例如下：

```
spark.sql(f"""
    CREATE TABLE IF NOT EXISTS glue_catalog.{DB_NAME}.{TABLE_NAME} (
        Col_1 float, 
        <<<…other columns…>>
        ts timestamp)
    USING iceberg
    PARTITIONED BY (days(ts))
    OPTIONS (
      'format-version'='2',
      write.format.default'=parquet)
""")

query = df \
    .writeStream \
    .format("iceberg") \
    .option("write-format", "avro") \
    .outputMode("append") \
    .trigger(processingTime='60 seconds') \
    .option("path", f"glue_catalog.{DB_NAME}.{TABLE_NAME}") \
    .option("checkpointLocation", f"s3://{BUCKET_NAME}/checkpoints/iceberg/")

    .start()
```

# 最佳化儲存體
<a name="best-practices-storage"></a>

更新或刪除 Iceberg 資料表中的資料會增加資料的複本數量，如下圖所示。執行壓縮也是如此：它會增加 Amazon S3 中的資料複本數量。這是因為 Iceberg 將所有資料表基礎的檔案視為不可變。

![\[更新或刪除 Iceberg 資料表中資料的結果\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/apache-iceberg-on-aws/images/optimizing-storage.png)


遵循本節中的最佳實務來管理儲存成本。

## 啟用 S3 Intelligent-Tiering
<a name="storage-s3-intelligent-tiering"></a>

使用 [Amazon S3 Intelligent-Tiering](https://docs.aws.amazon.com/AmazonS3/latest/userguide/intelligent-tiering-overview.html) 儲存類別，在存取模式變更時，自動將資料移至最具成本效益的存取層。此選項不會對效能造成操作額外負荷或影響。 

注意：請勿在 S3 Intelligent-Tiering 搭配 Iceberg 資料表 中使用選用層 （例如 Archive Access 和 Deep Archive Access)。若要封存資料，請參閱下一節中的準則。

您也可以使用 [Amazon S3 生命週期規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html)來設定自己的規則，將物件移至另一個 Amazon S3 儲存類別，例如 S3 Standard-IA 或 S3 One Zone-IA （請參閱 Amazon S3 文件中的[支援的轉換和相關限制](https://docs.aws.amazon.com/AmazonS3/latest/userguide/lifecycle-transition-general-considerations.html#lifecycle-general-considerations-transition-sc))。

## 封存或刪除歷史快照
<a name="storage-snapshots"></a>

對於 Iceberg 資料表的每個遞交交易 （插入、更新、合併、壓縮），會建立新的資料表版本或快照。隨著時間的推移，Amazon S3 中的版本數量和中繼資料檔案數量會累積。

快照隔離、資料表復原和時間歷程查詢等功能需要保留資料表的快照。不過，儲存成本會隨著您保留的版本數量而增加。

下表說明您可以實作的設計模式，以根據您的資料保留需求來管理成本。


| **設計模式** | **解決方案** | **使用案例** | 
| --- |--- |--- |
| **刪除舊快照** |   使用 Athena 中的 [VACUUM 陳述](https://docs.aws.amazon.com/athena/latest/ug/vacuum-statement.html)式來移除舊快照。此操作不會產生任何運算成本。    或者，您可以在 Amazon EMR 上使用 Spark 或 AWS Glue 移除快照。如需詳細資訊，請參閱 Iceberg 文件中的 [expire\$1snapshots](https://iceberg.apache.org/docs/latest/spark-procedures/#expire_snapshots)。   | 此方法會刪除不再需要的快照，以降低儲存成本。您可以根據您的資料保留需求，設定應保留多少快照或保留多久。此選項會執行快照的硬刪除。您無法復原或時間歷程至過期的快照。 | 
| **設定特定快照的保留政策** |   使用標籤來標記特定快照，並在 Iceberg 中定義保留政策。如需詳細資訊，請參閱 Iceberg 文件中的[歷史標籤](https://iceberg.apache.org/docs/latest/branching/#historical-tags)。 例如，您可以在 Amazon EMR 上的 Spark 中使用下列 SQL 陳述式，每月保留一個快照一年： <pre>ALTER TABLE glue_catalog.db.table <br />CREATE TAG 'EOM-01' AS OF VERSION 30 RETAIN 365 DAYS</pre>   在 Amazon EMR 上使用 Spark 或 AWS Glue 移除剩餘的未標記中繼快照。   | 此模式有助於遵守業務或法律要求，這些要求要求您在過去的特定時間點顯示資料表的狀態。透過在特定標記的快照上放置保留政策，您可以移除已建立的其他 （未標記） 快照。如此一來，您可以滿足資料保留要求，而無需保留建立的每個快照。 | 
| **封存舊快照** |   使用 Amazon S3 標籤以 Spark 標記物件。(Amazon S3 標籤與 Iceberg 標籤不同；如需詳細資訊，請參閱 [Iceberg 文件](https://iceberg.apache.org/docs/latest/aws/#s3-tags)。) 例如： <pre>spark.sql.catalog.my_catalog.s3.delete-enabled=false and \<br />spark.sql.catalog.my_catalog.s3.delete.tags.my_key=to_archive</pre>   在 Amazon EMR 上使用 Spark 或 AWS Glue 移除快照。 [https://iceberg.apache.org/docs/latest/spark-procedures/#expire_snapshots](https://iceberg.apache.org/docs/latest/spark-procedures/#expire_snapshots)當您使用範例中的設定時，此程序會標記物件，並將其從 Iceberg 資料表中繼資料分離，而不是從 Amazon S3 刪除它們。   使用 S3 生命週期規則，將標記為 的物件轉換為`to_archive`其中一個 [S3 Glacier 儲存類別](https://docs.aws.amazon.com/amazonglacier/latest/dev/introduction.html)。   若要查詢封存的資料：   [還原封存的物件](https://docs.aws.amazon.com/AmazonS3/latest/userguide/restoring-objects.html) （如果物件已轉換為 Amazon Glacier Instant Retrieval 儲存類別，則不需要此步驟）。   使用 Iceberg 中的 [register\$1table 程序](https://iceberg.apache.org/docs/latest/spark-procedures/#register_table)，將快照註冊為目錄中的資料表。    如需詳細說明，請參閱 AWS 部落格文章 [改善 Apache Iceberg 資料表建置在 Amazon S3 資料湖上的操作效率](https://aws.amazon.com/blogs/big-data/improve-operational-efficiencies-of-apache-iceberg-tables-built-on-amazon-s3-data-lakes/)。  | 此模式可讓您以較低的成本保留所有資料表版本和快照。在未先將這些版本還原為新資料表的情況下，您無法安排時間或轉返至封存的快照。這通常適用於稽核目的。您可以結合此方法與先前的設計模式，為特定快照設定保留政策。 | 

## 刪除孤立檔案
<a name="storage-orphan-files"></a>

在某些情況下，Iceberg 應用程式可能會在您遞交交易之前失敗。這會在 Amazon S3 中留下資料檔案。由於沒有遞交，因此這些檔案不會與任何資料表相關聯，因此您可能必須以非同步方式清除它們。

若要處理這些刪除，您可以在 Amazon Athena 中使用 [VACUUM 陳述](https://docs.aws.amazon.com/athena/latest/ug/vacuum-statement.html)式。此陳述式會移除快照，也會刪除孤立的檔案。這非常符合成本效益，因為 Athena 不會收取此操作的運算成本。此外，使用 `VACUUM`陳述式時，您不需要排程任何其他操作。

或者，您可以在 Amazon EMR 上使用 Spark 或 AWS Glue 來執行`remove_orphan_files`程序。此操作具有運算成本，必須獨立排程。如需詳細資訊，請參閱 [Iceberg 文件](https://iceberg.apache.org/docs/latest/spark-procedures/#remove_orphan_files)。

# 使用壓縮來維護資料表
<a name="best-practices-compaction"></a>

Iceberg 包含的功能可讓您在將資料寫入資料表後執行[資料表維護操作](https://iceberg.apache.org/docs/latest/maintenance/)。有些維護操作著重於簡化中繼資料檔案，而其他維護操作則強化資料在檔案中的叢集方式，以便查詢引擎可以有效地找到必要資訊來回應使用者請求。本節著重於壓縮相關最佳化。

## Iceberg 壓縮
<a name="iceberg-compaction"></a>

在 Iceberg 中，您可以使用壓縮來執行四個任務：
+ 將小型檔案合併成大小通常超過 100 MB 的大型檔案。此技術稱為 *bin packing*。
+ 將刪除檔案與資料檔案合併。使用merge-on-read方法的更新或刪除會產生刪除檔案。
+ （重新）根據查詢模式排序資料。您可以不使用任何排序順序或適合寫入和更新的排序順序來寫入資料。
+ 使用空間填入曲線來叢集資料，以最佳化不同的查詢模式，特別是 z 順序排序。

在 上 AWS，您可以透過 Amazon Athena 或在 Amazon EMR 或 中使用 Spark，為 Iceberg 執行資料表壓縮和維護操作 AWS Glue。

當您使用 [rewrite\$1data\$1files](https://iceberg.apache.org/docs/latest/spark-procedures/#rewrite_data_files) 程序執行壓縮時，您可以調整數個旋鈕來控制壓縮行為。下圖顯示 bin 封裝的預設行為。了解 bin 封裝壓縮是了解階層排序和 Z 順序排序實作的關鍵，因為它們是 bin 封裝界面的延伸，並以類似方式操作。主要區別是排序或叢集資料所需的額外步驟。

![\[Iceberg 資料表中的預設 bin 封裝行為\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/apache-iceberg-on-aws/images/compaction.png)


在此範例中，Iceberg 資料表包含四個分割區。每個分割區都有不同的大小和不同的檔案數量。如果您啟動 Spark 應用程式來執行壓縮，應用程式會建立總共四個要處理的檔案群組。檔案群組是 Iceberg 抽象，代表將由單一 Spark 任務處理的檔案集合。也就是說，執行壓縮的 Spark 應用程式將建立四個 Spark 任務來處理資料。

## 調校壓縮行為
<a name="compaction-behavior"></a>

下列金鑰屬性會控制如何選取資料檔案進行壓縮：
+ [MAX\$1FILE\$1GROUP\$1SIZE\$1BYTES](https://iceberg.apache.org/javadoc/1.2.0/org/apache/iceberg/actions/RewriteDataFiles.html#MAX_FILE_GROUP_SIZE_BYTES) 預設會將單一檔案群組 (Spark 任務） 的資料限制設為 100 GB。此屬性對於沒有分割區的資料表或具有跨數百 GB 分割區的資料表特別重要。透過設定此限制，您可以細分操作來規劃工作並取得進展，同時防止叢集上的資源耗盡。

  注意：每個檔案群組都會分別排序。因此，如果您想要執行分割區層級排序，您必須調整此限制以符合分割區大小。
+ [MIN\$1FILE\$1SIZE\$1BYTES](https://iceberg.apache.org/javadoc/1.2.0/org/apache/iceberg/actions/BinPackStrategy.html#MIN_FILE_SIZE_BYTES) 或 [MIN\$1FILE\$1SIZE\$1DEFAULT\$1RATIO](https://iceberg.apache.org/javadoc/1.2.0/org/apache/iceberg/actions/BinPackStrategy.html#MIN_FILE_SIZE_DEFAULT_RATIO) 預設為資料表層級設定之目標檔案大小的 75%。例如，如果資料表的目標大小為 512 MB，則任何小於 384 MB 的檔案都會包含在將壓縮的一組檔案中。
+ [MAX\$1FILE\$1SIZE\$1BYTES](https://iceberg.apache.org/javadoc/1.2.0/org/apache/iceberg/actions/BinPackStrategy.html#MAX_FILE_SIZE_BYTES) 或 [MAX\$1FILE\$1SIZE\$1DEFAULT\$1RATIO](https://iceberg.apache.org/javadoc/1.2.0/org/apache/iceberg/actions/BinPackStrategy.html#MAX_FILE_SIZE_DEFAULT_RATIO) 預設為目標檔案大小的 180%。與設定最小檔案大小的兩個屬性一樣，這些屬性用於識別壓縮任務的候選檔案。
+ 如果資料表分割區大小小於目標檔案大小，[MIN\$1INPUT\$1FILES](https://iceberg.apache.org/javadoc/1.2.0/org/apache/iceberg/actions/BinPackStrategy.html#MIN_INPUT_FILES) 會指定要壓縮的檔案數目下限。此屬性的值用於判斷根據檔案數量壓縮檔案是否值得 （預設為 5)。
+ [DELETE\$1FILE\$1THRESHOLD](https://iceberg.apache.org/javadoc/1.2.0/org/apache/iceberg/actions/BinPackStrategy.html#DELETE_FILE_THRESHOLD) 會指定檔案在壓縮前的刪除操作數目下限。除非您另有指定，否則壓縮不會將刪除檔案與資料檔案合併。若要啟用此功能，您必須使用此屬性來設定閾值。此閾值專屬於個別資料檔案，因此如果您將其設定為 3，只有在有三個或多個參考該檔案的刪除檔案時，才會重新寫入資料檔案。

這些屬性可讓您深入了解上圖中檔案群組的形成。

例如，標記為 的分割區`month=01`包含兩個檔案群組，因為它超過 100 GB 的大小限制上限。相反地，`month=02`分割區包含單一檔案群組，因為它小於 100 GB。`month=03` 分割區不符合五個檔案的預設最低輸入檔案需求。因此，它不會壓縮。最後，雖然`month=04`分割區不包含足夠的資料來形成所需大小的單一檔案，但檔案將會壓縮，因為分割區包含五個以上的小型檔案。

您可以為在 Amazon EMR 或 上執行的 Spark 設定這些參數 AWS Glue。對於 Amazon Athena，您可以使用字首為 的[資料表](https://docs.aws.amazon.com/athena/latest/ug/querying-iceberg-creating-tables.html#querying-iceberg-table-properties)屬性來管理類似的屬性`optimize_`)。

## 在 Amazon EMR 或 上使用 Spark 執行壓縮 AWS Glue
<a name="compaction-emr-glue"></a>

本節說明如何正確調整 Spark 叢集的大小，以執行 Iceberg 的壓縮公用程式。下列範例使用 Amazon EMR Serverless，但您可以在 Amazon EMR on EC2 或 EKS 或 中使用相同的方法 AWS Glue。

您可以利用檔案群組與 Spark 任務之間的相互關聯來規劃叢集資源。若要循序處理檔案群組，請考慮每個檔案群組的大小上限為 100 GB，您可以設定下列 [Spark 屬性](https://docs.aws.amazon.com/emr/latest/EMR-Serverless-UserGuide/jobs-spark.html#spark-defaults)：
+ `spark.dynamicAllocation.enabled` = `FALSE`
+ `spark.executor.memory` = `20 GB`
+ `spark.executor.instances` = `5`

如果您想要加速壓縮，您可以透過增加平行壓縮的檔案群組數量來水平擴展。您也可以使用手動或動態擴展來擴展 Amazon EMR。
+ **手動擴展** （例如，因數為 4)
  + `MAX_CONCURRENT_FILE_GROUP_REWRITES` = `4`（我們的因素）
  + `spark.executor.instances` = `5`（範例中使用的值） x `4`（我們的因素） = `20`
  + `spark.dynamicAllocation.enabled` = `FALSE`
+ **動態擴展**
  + `spark.dynamicAllocation.enabled` = `TRUE `（預設，無需採取任何動作）
  + [MAX\$1CONCURRENT\$1FILE\$1GROUP\$1REWRITES](https://iceberg.apache.org/javadoc/1.2.0/org/apache/iceberg/actions/RewriteDataFiles.html#MAX_CONCURRENT_FILE_GROUP_REWRITES) = `N `（將此值與 對齊`spark.dynamicAllocation.maxExecutors`，預設為 100；根據範例中的執行器組態，您可以將 `N` 設定為 20)

  這些是協助調整叢集大小的指導方針。不過，您也應該監控 Spark 任務的效能，以尋找工作負載的最佳設定。

## 使用 Amazon Athena 執行壓縮
<a name="compaction-athena"></a>

Athena 透過 [OPTIMIZE 陳述](https://docs.aws.amazon.com/athena/latest/ug/optimize-statement.html)式，將 Iceberg 的壓縮公用程式實作為受管功能。您可以使用此陳述式來執行壓縮，而不必評估基礎設施。

此陳述式使用 bin 封裝演算法將小型檔案分組為較大的檔案，並將刪除檔案與現有的資料檔案合併。若要使用階層排序或 z 順序排序來叢集資料，請在 Amazon EMR 或 上使用 Spark AWS Glue。

您可以在建立資料表時，透過在 `OPTIMIZE` 陳述式中傳遞資料表屬性，或使用 陳述式在建立資料表之後，變更 `CREATE TABLE` `ALTER TABLE`陳述式的預設行為。如需預設值，請參閱 [Athena 文件](https://docs.aws.amazon.com/athena/latest/ug/querying-iceberg-creating-tables.html#querying-iceberg-table-properties)。

## 執行壓縮的建議
<a name="compaction-recommendations"></a>


| **使用案例** | **建議** | 
| --- |--- |
| **根據排程執行 bin 封裝壓縮** |   如果您不知道資料表包含多少小型檔案，請在 Athena 中使用 `OPTIMIZE`陳述式。Athena 定價模型是以掃描的資料為基礎，因此，如果沒有要壓縮的檔案，則不會產生與這些操作相關的成本。為了避免在 Athena 資料表上遇到逾時，`OPTIMIZE`請per-table-partition執行 。   當您預期壓縮大量小型檔案時，請使用 Amazon EMR 或 AWS Glue 搭配動態擴展。   | 
| **根據事件執行 bin 封裝壓縮** |   當您預期壓縮大量小型檔案時，請使用 Amazon EMR 或 AWS Glue 搭配動態擴展。   | 
| **執行壓縮以排序資料** |   使用 Amazon EMR 或 AWS Glue，因為排序是一項昂貴的操作，可能需要將資料溢出到磁碟。   | 
| **執行壓縮以使用 z 順序排序來叢集資料** |   使用 Amazon EMR 或 AWS Glue，因為 z 順序排序是非常昂貴的操作，可能需要將資料溢出到磁碟。   | 
| **在可能因延遲抵達資料而由其他應用程式更新的分割區上執行壓縮** |   使用 Amazon EMR 或 AWS Glue。啟用 Iceberg [PARTIAL\$1PROGRESS\$1ENABLED](https://iceberg.apache.org/javadoc/1.2.0/org/apache/iceberg/actions/RewriteDataFiles.html#PARTIAL_PROGRESS_ENABLED) 屬性。當您使用此選項時，Iceberg 會將壓縮輸出分割成多個遞交。如果發生碰撞 （亦即，如果資料檔案在壓縮執行時更新），則此設定會將其限制為包含受影響檔案的遞交，以降低重試成本。否則，您可能需要重新編譯所有檔案。   | 
| **在冷分割區上執行壓縮 （不再接收作用中寫入的資料分割區）** |   使用 Amazon EMR 或 AWS Glue。在`rewrite_data_files`程序中，指定排除主動寫入分割區的`where`述詞。此策略可防止寫入器和壓縮任務之間的資料衝突，並只留下 Iceberg 可以自動解決的中繼資料衝突。   | 

# 在 Amazon S3 中使用 Iceberg 工作負載
<a name="best-practices-workloads"></a>

本節討論 Iceberg 屬性，您可以用來最佳化 Iceberg 與 Amazon S3 的互動。

## 防止熱分割 (HTTP 503 錯誤）
<a name="workloads-503"></a>

在 Amazon S3 上執行的某些資料湖應用程式會處理數百萬或數十億個物件，並處理 PB 的資料。這可能會導致接收大量流量的字首，這通常透過 HTTP 503 （服務無法使用） 錯誤偵測到。若要避免此問題，請使用下列 Iceberg 屬性：
+ 將 `write.distribution-mode`設定為 `hash`或 ，`range`讓 Iceberg 寫入大型檔案，這會導致較少的 Amazon S3 請求。這是偏好的組態，應處理大多數案例。
+ 如果您因為工作負載中的大量資料而持續遇到 503 個錯誤，您可以在 Iceberg `true`中`write.object-storage.enabled`將 設定為 。這會指示 Iceberg 雜湊物件名稱，並將負載分配到多個隨機的 Amazon S3 字首。

如需這些屬性的詳細資訊，請參閱 Iceberg 文件中的[寫入屬性](https://iceberg.apache.org/docs/latest/configuration/#write-properties)。

## 使用 Iceberg 維護操作來釋出未使用的資料
<a name="workloads-unused-data"></a>

若要管理 Iceberg 資料表，您可以使用 Iceberg 核心 API、Iceberg 用戶端 （例如 Spark) 或 Amazon Athena 等受管服務。若要從 Amazon S3 刪除舊或未使用的檔案，建議您僅使用 Iceberg 原生 APIs來[移除快照](https://iceberg.apache.org/docs/latest/maintenance/#expire-snapshots)、[移除舊中繼資料檔案](https://iceberg.apache.org/docs/latest/maintenance/#remove-old-metadata-files)，以及[刪除孤立檔案](https://iceberg.apache.org/docs/latest/maintenance/#delete-orphan-files)。

透過 Boto3、Amazon S3 SDK 或 AWS Command Line Interface (AWS CLI) 使用 Amazon S3 APIs，或使用任何其他非 Iceberg 方法來覆寫或移除 Iceberg 資料表的 Amazon S3 檔案，會導致資料表損毀和查詢失敗。

## 跨 複寫資料 AWS 區域
<a name="workloads-replication"></a>

在 Amazon S3 中存放 Iceberg 資料表時，您可以使用 Amazon S3 中的內建功能，例如[跨區域複寫 (CRR)](https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html) 和[多區域存取點 (MRAP)](https://docs.aws.amazon.com/AmazonS3/latest/userguide/MultiRegionAccessPoints.html)，跨多個區域複寫資料 AWS 區域。MRAP 為應用程式提供全域端點，以存取位於多個 中的 S3 儲存貯體 AWS 區域。Iceberg 不支援相對路徑，但您可以使用 MRAP 透過將儲存貯體映射至存取點來執行 Amazon S3 操作。MRAP 也會與 Amazon S3 跨區域複寫程序無縫整合，進而產生長達 15 分鐘的延遲。您必須複寫資料和中繼資料檔案。

**重要**  
目前，與 MRAP 的 Iceberg 整合僅適用於 Apache Spark。如果您需要容錯移轉至次要 AWS 區域，您必須計劃將使用者查詢重新導向至容錯移轉區域中的 Spark SQL 環境 （例如 Amazon EMR)。

CRR 和 MRAP 功能可協助您為 Iceberg 資料表建置跨區域複寫解決方案，如下圖所示。

![\[Iceberg 資料表的跨區域複寫\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/apache-iceberg-on-aws/images/cross-region-replication.png)


若要設定此跨區域複寫架構：

1. 使用 MRAP 位置建立資料表。這可確保 Iceberg 中繼資料檔案指向 MRAP 位置，而不是實體儲存貯體位置。

1. 使用 Amazon S3 MRAP 複寫 Iceberg 檔案。** **MRAP 支援服務層級協議 (SLA) 為 15 分鐘的資料複寫。Iceberg 可防止讀取操作在複寫期間引入不一致。

1. 在次要區域中，讓 AWS Glue Data Catalog 中的資料表可用。您可以從兩個選項中選擇：
   + 使用複寫設定用於 AWS Glue Data Catalog 複寫 Iceberg 資料表中繼資料的管道。此公用程式可在 GitHub [Glue Catalog 和 Lake Formation Permissions 複寫](https://github.com/aws-samples/lake-formation-pemissions-sync)儲存庫中使用。此事件驅動機制會根據事件日誌複寫目標區域中的資料表。
   + 當您需要容錯移轉時，在次要區域中註冊資料表。對於此選項，您可以使用先前的公用程式或 Iceberg [register\$1table 程序](https://iceberg.apache.org/docs/latest/spark-procedures/#register_table)，並將其指向最新的`metadata.json`檔案。