Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Boto3로 AWS Glue의 S3 버킷 객체 버전 페이지네이션 처리하기

문제 상황

Python의 boto3 라이브러리를 사용하여 본인 계정에서 생성한 AWS Glue Data Catalog의 S3 버킷에 저장된 객체 버전(object versions)을 페이지네이션 방식으로 조회하는 방법을 알아보겠습니다.

문제 해결 접근 방식

  • 1단계: 예외 처리를 위해 boto3botocore의 예외 클래스를 임포트합니다.

  • 2단계: 함수의 파라미터를 이해합니다. bucket_name은 필수 파라미터이며, max_items, page_size, starting_token은 선택적 파라미터입니다.

    • max_items: 반환할 총 레코드 수를 의미합니다. 사용 가능한 레코드 수가 max_items보다 많으면 응답에 NextToken이 포함되어 이후 페이지네이션을 이어갈 수 있습니다.

    • page_size: 한 페이지당 크기를 나타냅니다.

    • starting_token: 페이지네이션을 시작할 위치를 지정하며, 이전 응답의 NextKeyMarker 값을 사용합니다.

  • 3단계: boto3를 사용해 AWS 세션을 생성합니다. 기본 프로필에 region_name이 설정되어 있지 않다면 세션 생성 시 명시적으로 리전 이름을 전달해야 합니다.

  • 4단계: S3용 AWS 클라이언트를 생성합니다.

  • 5단계: list_object_versions 연산을 기반으로 S3 버킷의 객체 버전 정보를 담는 페이지네이터(paginator) 객체를 생성합니다.

  • 6단계: paginate 함수를 호출하고, max_items, page_size, starting_tokenPaginationConfig 파라미터로, bucket_name은 Bucket 파라미터로 각각 전달합니다.

  • 7단계: max_sizepage_size 설정에 따라 지정된 개수만큼의 레코드가 반환됩니다.

  • 8단계: 페이지네이션 과정에서 오류가 발생하면 일반 예외(generic exception)를 처리합니다.

예제 코드

다음 코드를 사용하면 본인 계정에 생성된 S3 버킷의 객체 버전을 페이지네이션 방식으로 조회할 수 있습니다.

import boto3
from botocore.exceptions import ClientError


def paginate_through_object_version_s3_bucket(bucket_name, max_items=None, page_size=None, starting_token=None):
    session = boto3.session.Session()
    s3_client = session.client('s3')
    try:
        paginator = s3_client.get_paginator('list_object_versions')
        response = paginator.paginate(
            Bucket=bucket_name,
            PaginationConfig={
                'MaxItems': max_items,
                'PageSize': page_size,
                'StartingToken': starting_token
            }
        )
        return response
    except ClientError as e:
        raise Exception("boto3 client error in paginate_through_object_version_s3_bucket: " + e.__str__())
    except Exception as e:
        raise Exception("Unexpected error in paginate_through_object_version_s3_bucket: " + e.__str__())


# 첫 번째 실행
a = paginate_through_object_version_s3_bucket('s3-test-bucket', 2, 5)
print(*a)

# 두 번째 실행
for items in a:
    next_token = items['NextKeyMarker']
    b = paginate_through_object_version_s3_bucket('s3-test-bucket', 2, 5, next_token)
    print(*b)

실행 결과

첫 번째 실행에서는 MaxItems=2, PageSize=5 조건으로 객체 버전 목록과 함께 다음 페이지를 가리키는 NextKeyMarker가 반환됩니다.

{'ResponseMetadata': {'RequestId': 'XEVY**************CD0', 'HostId': **************, 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amz-id-2': *******************, 'x-amz-request-id': 'XEVYV***************', 'date': 'Sat, 03 Apr 2021 07:14:49 GMT', 'content-type': 'application/xml', 'transfer-encoding': 'chunked', 'server': 'AmazonS3'}, 'RetryAttempts': 0}, 'IsTruncated': True, 'KeyMarker': '', 'VersionIdMarker': '', 'NextKeyMarker': 'analytics-s3/template.json', 'NextVersionIdMarker': 'null',
'Versions': [{'ETag': '"e66659e02"', 'Size': 1554, 'StorageClass': 'STANDARD', 'Key': 'analytics-s3i/param.json', 'VersionId': 'null', 'IsLatest': True, 'LastModified': datetime.datetime(2020, 10, 29, 19, 50, 55, tzinfo=tzutc()), 'Owner': {'DisplayName': 'AWS.Development', 'ID': '928b5bd**************3d70'}},
{'ETag': '"22a4bf7**************9c1ed2612"', 'Size': 1756, 'StorageClass': 'STANDARD', 'Key': 'analytics-s3i/params.json', 'VersionId': 'null', 'IsLatest': True, 'LastModified': datetime.datetime(2021, 3, 10, 20, 10, 47, tzinfo=tzutc()), 'Owner': {'DisplayName': 'AWS.Development', 'ID': '928b5bde*****************2d4423d70'}}],
'Name': 's3-test-bucket', 'Prefix': '', 'MaxKeys': 5, 'EncodingType': 'url', 'DeleteMarkers': None, 'CommonPrefixes': None}

두 번째 실행에서는 이전 응답의 NextKeyMarkerstarting_token으로 전달하여 나머지 객체 버전을 이어서 조회합니다.

{'ResponseMetadata': {'RequestId': '3V9*********703V', 'HostId': ****************, 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amz-id-2': '************************', 'x-amz-request-id': '3V9****************V', 'date': 'Sat, 03 Apr 2021 07:18:56 GMT', 'content-type': 'application/xml', 'transfer-encoding': 'chunked', 'server': 'AmazonS3'}, 'RetryAttempts': 0},
'IsTruncated': True, 'KeyMarker': analytics-s3i2/template.json, 'VersionIdMarker': '', 'NextKeyMarker': 'analytics-s3l/params.json', 'NextVersionIdMarker': 'null', 'Versions':
[{'ETag': '"dbd336ff00cb5af3d"', 'Size': 1557, 'StorageClass': 'STANDARD', 'Key': 'analytics-s3i3/param.json', 'VersionId': 'null', 'IsLatest': True, 'LastModified': datetime.datetime(2020, 10, 28, 18, 16, 38, tzinfo=tzutc()), 'Owner': {'DisplayName': 'AWS.Development', 'ID': '*****************'}},
{'ETag': '"66b49598df6"', 'Size': 21334, 'StorageClass': 'STANDARD', 'Key': 'analytics-s3i3/template.json', 'VersionId': 'null', 'IsLatest': True, 'LastModified': datetime.datetime(2020, 10, 28, 18, 16, 38, tzinfo=tzutc()), 'Owner': {'DisplayName': 'AWS.Development', 'ID': '****************'}}],
'Name': 's3-test-bucket', 'Prefix': '', 'MaxKeys': 5, 'EncodingType': 'url', 'DeleteMarkers': None, 'CommonPrefixes': None}

정리

boto3의 페이지네이터를 활용하면 대량의 S3 객체 버전도 MaxItemsPageSize로 조회량을 제어하고, StartingToken으로 이어서 조회할 수 있어 효율적인 데이터 관리가 가능합니다.