Amazon Web Services 한국 블로그

Amazon S3 Table, sort 및 z-order 압축을 통해 Apache Iceberg 쿼리 성능 개선

이제 sortz-order 압축을 사용하여 Amazon S3 Tables범용 S3 버킷에서 Apache Iceberg 쿼리 성능을 개선할 수 있습니다.

일반적으로 Iceberg는 AWS Glue Data Catalog 또는 S3 테이블과 함께 Amazon Simple Storage Service(Amazon S3)에서 대규모 분석 데이터 세트를 관리하는 데 사용됩니다. Iceberg 테이블은 동시 스트리밍 및 배치 처리, 스키마 진화, 시점 복원 등 다양한 사용 사례를 지원합니다. 인제스트 양이 많거나 자주 업데이트되는 데이터 세트로 작업할 경우, 데이터 레이크에는 쿼리 비용과 성능에 영향을 미치는 작은 파일들이 다수 누적될 수 있습니다. Iceberg 데이터 레이아웃 최적화는 운영 측면에서 복잡하고, 맞춤형 파이프라인의 개발 및 유지 관리가 필요한 경우가 많다는 점을 말씀해주셨습니다. 관리형 압축을 사용하는 기본 binpack 전략은 눈에 띄는 성능 향상을 제공하지만 S3 및 S3 테이블 모두에 sortz-order 압축 옵션을 도입하면 하나 이상의 차원을 기준으로 쿼리를 필터링할 때 훨씬 더 큰 성능 향상을 기대할 수 있습니다.

두 가지 새로운 압축 전략: sortz-order
데이터를 보다 효율적으로 구성할 수 있도록 Amazon S3에서는 이제 기본 binpack 압축 외에도 sortz-order라는 두 가지 새로운 압축 전략을 지원합니다. 이러한 고급 전략은 AWS Glue Data Catalog 최적화를 통해 범용 S3 버킷의 완전 관리형 S3 테이블과 Iceberg 테이블에서 모두 사용할 수 있습니다.

정렬 압축은 사용자가 정의한 열 순서에 따라 파일을 구성합니다. 테이블에 정의된 정렬 순서가 있을 경우, 이제 S3 테이블 압축 과정에서 이 정렬 순서를 활용하여 유사한 값들을 함께 클러스터링합니다. 이렇게 하면 스캔되는 파일 수가 줄어들어 쿼리 실행 효율성이 향상됩니다. 예를 들어, statezip_code를 기준으로 sort 압축을 통해 테이블을 구성한 경우, 해당 열을 필터링하는 쿼리는 스캔하는 파일 수가 줄어들어 지연 시간이 단축되고 쿼리 엔진 비용이 절감됩니다.

z-order 압축은 한 단계 더 나아가 여러 차원에 걸쳐 효율적인 파일 정리를 가능하게 합니다. 여러 열의 값을 이진수 형태로 변환하여 정렬이 가능한 단일 스칼라 값으로 교차 병합함으로써, 이 전략은 공간 또는 다차원 쿼리에 특히 유용합니다. 예를 들어, 워크로드에 pickup_location, dropoff_locationfare_amount 기준으로 동시에 필터링하는 쿼리가 포함된 경우 z-order 압축을 사용하면 기존 정렬 기반 레이아웃에 비해 스캔한 총 파일 수를 줄일 수 있습니다.

S3 테이블은 Iceberg 테이블의 메타데이터를 사용하여 현재 정렬 순서를 결정합니다. 테이블에 정의된 정렬 순서가 있는 경우 정렬 압축을 활성화하기 위한 추가 구성이 필요하지 않습니다. sort 압축은 지속적인 유지 관리 중에 자동으로 적용됩니다. z-order를 사용하려면 S3 Tables API를 사용하여 테이블 유지 관리 구성을 업데이트하고 전략을 z-order로 설정해야 합니다. 범용 S3 버킷에 있는 Iceberg 테이블의 경우, 압축 설정을 업데이트하여 최적화 중에 sort 또는 z-order 압축을 사용하도록 AWS Glue Data Catalog를 구성할 수 있습니다.

sort 또는 z-order를 활성화한 후에 작성된 새 데이터만 영향을 받습니다. 기존 압축 파일은 테이블 유지 관리 설정에서 대상 파일 크기를 늘리거나, 표준 Iceberg 도구를 사용해 데이터를 명시적으로 다시 작성하지 않는 한 변경되지 않습니다. 이 동작은 사용자가 데이터 재구성 시기와 양을 제어하고 비용과 성능의 균형을 맞출 수 있도록 설계되었습니다.

실제 작동 모습을 살펴보겠습니다.
Apache Spark와 AWS 명령줄 인터페이스(AWS CLI)를 사용하는 간단한 예제를 안내해 드리겠습니다. Spark 클러스터와 S3 테이블 버킷이 설치되어 있습니다. testnamespacetesttable이라는 테이블이 있습니다. 테이블에 데이터를 추가하는 동안 압축을 일시적으로 비활성화했습니다.

데이터를 추가한 후 테이블의 파일 구조를 확인합니다.

spark.sql("""
  SELECT 
    substring_index(file_path, '/', -1) as file_name,
    record_count,
    file_size_in_bytes,
    CAST(UNHEX(hex(lower_bounds[2])) AS STRING) as lower_bound_name,
    CAST(UNHEX(hex(upper_bounds[2])) AS STRING) as upper_bound_name
  FROM ice_catalog.testnamespace.testtable.files
  ORDER BY file_name
""").show(20, false)
+--------------------------------------------------------------+------------+------------------+----------------+----------------+
|file_name                                                     |record_count|file_size_in_bytes|lower_bound_name|upper_bound_name|
+--------------------------------------------------------------+------------+------------------+----------------+----------------+
|00000-0-66a9c843-5a5c-407f-8da4-4da91c7f6ae2-0-00001.parquet  |1           |837               |Quinn           |Quinn           |
|00000-1-b7fa2021-7f75-4aaf-9a24-9bdbb5dc08c9-0-00001.parquet  |1           |824               |Tom             |Tom             |
|00000-10-00a96923-a8f4-41ba-a683-576490518561-0-00001.parquet |1           |838               |Ilene           |Ilene           |
|00000-104-2db9509d-245c-44d6-9055-8e97d4e44b01-0-00001.parquet|1000000     |4031668           |Anjali          |Tom             |
|00000-11-27f76097-28b2-42bc-b746-4359df83d8a1-0-00001.parquet |1           |838               |Henry           |Henry           |
|00000-114-6ff661ca-ba93-4238-8eab-7c5259c9ca08-0-00001.parquet|1000000     |4031788           |Anjali          |Tom             |
|00000-12-fd6798c0-9b5b-424f-af70-11775bf2a452-0-00001.parquet |1           |852               |Georgie         |Georgie         |
|00000-124-76090ac6-ae6b-4f4e-9284-b8a09f849360-0-00001.parquet|1000000     |4031740           |Anjali          |Tom             |
|00000-13-cb0dd5d0-4e28-47f5-9cc3-b8d2a71f5292-0-00001.parquet |1           |845               |Olivia          |Olivia          |
|00000-134-bf6ea649-7a0b-4833-8448-60faa5ebfdcd-0-00001.parquet|1000000     |4031718           |Anjali          |Tom             |
|00000-14-c7a02039-fc93-42e3-87b4-2dd5676d5b09-0-00001.parquet |1           |838               |Sarah           |Sarah           |
|00000-144-9b6d00c0-d4cf-4835-8286-ebfe2401e47a-0-00001.parquet|1000000     |4031663           |Anjali          |Tom             |
|00000-15-8138298d-923b-44f7-9bd6-90d9c0e9e4ed-0-00001.parquet |1           |831               |Brad            |Brad            |
|00000-155-9dea2d4f-fc98-418d-a504-6226eb0a5135-0-00001.parquet|1000000     |4031676           |Anjali          |Tom             |
|00000-16-ed37cf2d-4306-4036-98de-727c1fe4e0f9-0-00001.parquet |1           |830               |Brad            |Brad            |
|00000-166-b67929dc-f9c1-4579-b955-0d6ef6c604b2-0-00001.parquet|1000000     |4031729           |Anjali          |Tom             |
|00000-17-1011820e-ee25-4f7a-bd73-2843fb1c3150-0-00001.parquet |1           |830               |Noah            |Noah            |
|00000-177-14a9db71-56bb-4325-93b6-737136f5118d-0-00001.parquet|1000000     |4031778           |Anjali          |Tom             |
|00000-18-89cbb849-876a-441a-9ab0-8535b05cd222-0-00001.parquet |1           |838               |David           |David           |
|00000-188-6dc3dcca-ddc0-405e-aa0f-7de8637f993b-0-00001.parquet|1000000     |4031727           |Anjali          |Tom             |
+--------------------------------------------------------------+------------+------------------+----------------+----------------+
상위 20개 행만 표시 

테이블이 여러 개의 작은 파일로 구성되어 있으며, 새로 생성된 파일들의 상한값과 하한값이 서로 겹치는 것으로 보아 데이터가 정렬되어 있지 않음이 분명합니다.

테이블 정렬 순서를 설정했습니다.

spark.sql("ALTER TABLE ice_catalog.testnamespace.testtable WRITE ORDERED BY name ASC")

테이블 압축을 다시 활성화합니다(기본적으로는 활성화, 이 데모를 시작할 때 비활성화한 상태).

aws s3tables put-table-maintenance-configuration --table-bucket-arn ${S3TABLE_BUCKET_ARN} --namespace testnamespace --name testtable --type icebergCompaction --value "status=enabled,settings={icebergCompaction={strategy=sort}}"

그런 다음, 다음 압축 작업이 실행되기를 기다립니다. 소형 파일이 일정량 이상 누적되면, 이러한 작업은 하루 동안 수시로 실행됩니다. 다음 명령으로 압축 상태를 확인할 수 있습니다.

aws s3tables get-table-maintenance-job-status --table-bucket-arn ${S3TABLE_BUCKET_ARN} --namespace testnamespace --name testtable

압축이 완료되면, 테이블을 구성하는 파일을 다시 한 번 확인합니다. 데이터가 두 개의 파일로 압축된 것을 확인할 수 있으며, 상한값과 하한값을 통해 이 두 파일에 걸쳐 데이터가 정렬되었음을 알 수 있습니다.

spark.sql("""
  SELECT 
    substring_index(file_path, '/', -1) as file_name,
    record_count,
    file_size_in_bytes,
    CAST(UNHEX(hex(lower_bounds[2])) AS STRING) as lower_bound_name,
    CAST(UNHEX(hex(upper_bounds[2])) AS STRING) as upper_bound_name
  FROM ice_catalog.testnamespace.testtable.files
  ORDER BY file_name
""").show(20, false)
+------------------------------------------------------------+------------+------------------+----------------+----------------+
|file_name                                                   |record_count|file_size_in_bytes|lower_bound_name|upper_bound_name|
+------------------------------------------------------------+------------+------------------+----------------+----------------+
|00000-4-51c7a4a8-194b-45c5-a815-a8c0e16e2115-0-00001.parquet|13195713    |50034921          |Anjali          |Kelly           |
|00001-5-51c7a4a8-194b-45c5-a815-a8c0e16e2115-0-00001.parquet|10804307    |40964156          |Liza            |Tom             |
+------------------------------------------------------------+------------+------------------+----------------+----------------+

파일 수는 적어지고 크기는 커졌으며, 지정된 정렬 열에서 클러스터링이 개선되었습니다.

z-order를 사용하려면 동일한 단계를 따르되, 유지 관리 구성에서 strategy=z-order를 설정하면 됩니다.

리전별 가용성
이제 Amazon S3 테이블이 지원되는 모든 AWS 지역과 AWS Glue Data Catalog 최적화가 가능한 범용 S3 버킷에서 sortz-order 압축을 사용할 수 있습니다. 기존 사용 및 유지 관리 비용 외에 S3 테이블에 대한 추가 요금은 없습니다. 데이터 카탈로그 최적화 시 압축 작업 중에는 컴퓨팅 요금이 발생합니다.

이러한 변경으로 인해 sort 또는 z-order 열을 기준으로 필터링하는 쿼리는 스캔 시간이 단축되고 엔진 비용이 절감됩니다. 제 경험상 데이터 레이아웃과 쿼리 패턴에 따라 binpack에서 sort 또는 z-order로 전환할 때 성능이 3배 이상 향상되는 것을 확인했습니다. 실제 데이터에서 어느 정도의 성능 향상을 얻으셨는지 공유해 주세요.

자세히 알아보려면 Amazon S3 테이블 제품 페이지를 방문하거나 S3 테이블 유지 관리 설명서를 검토해 주세요. S3 테이블 API 또는 AWS Glue 최적화를 사용하여 자체 테이블에서 새로운 전략을 지금 테스트할 수도 있습니다.

— seb