본문 바로가기
🌿 Data with AI/Data Engineering

📖[Redshift][S3] 대용량 데이터 처리 고민: S3 Unload/Copy와 Redshift Specturm 외부테이블

by 카프리썬 2023. 4. 23.
728x90

오늘도 짱구 알통만큼 성장했다....(뿌듯)

대용량 데이터에 대한 고민 

요즘들어 이런게 바로 데이터엔지니어링인가?싶은 부분이 있어서 기록해보려고 한다. 

 

한창 개발중인 알고리즘은 최소 4주 이상의 사용자 행동로그를 기반으로 동작한다.

그런데 이때 이렇게 큰 대용량 데이터를 수집하고 처리하는데 아래와 같은 두가지 고민사항이 있었다.

1. 수집한 대용량 로그 데이터를 어디에 어떻게 저장할 것인가? 

2. 분석하기 위해 대용량 데이터를 불러오는 가장 효율적인 방법은?

3. 최종 분석결과를 어디에 어떻게 저장할 것인가? 

이러한 고민들을 엔지니어링 관점에서 어떻게 해결했는지 그리고 관련 기술에 대해 작성해보려고 한다.

 

1. 날짜기준으로 파티셔닝하여 s3에 unload한다 ( Redshift -> S3 )

우리는 redshift에서 어찌저찌 수집 및 분석한 데이터를 보통 그대로 넣어두는 datalake S3를 사용한다.

그래서 redshift에서 사용자 행동로그를 쿼리하고, 약 2G정도의 데이터를 s3에 parquet포맷으로 unload한다.

reshift docs에 따르면, 개방형 열 기반 스토리지 형식인 Apache Parquet의 Amazon S3 데이터 레이크에 언로드할 수 있습니다. Parquet 형식은 텍스트 형식에 비해 언로드 속도가 최대 2배 빠르고 Amazon S3에서 스토리지 사용량이 최대 6배 적습니다. 라고 한다.

 

매시간마다 수집하는 데이터를 어떻게 저장할것인가? 그냥 계속 s3에 unload하면 되는가..? No.....

아무래도 시간마다 업데이트 되는 데이터이기 때문에 언제기준으로 수집된 데이터인지 파악하면 좋을것 같았다.

그리고 해당 데이터는 정확한 날찌를 기준으로 몇일간의 데이터를 불러와야했기에 더더욱 날짜로 분리되는게 필요했다. 

 

그래서 날짜별로, 시간별로 분리되어 저장될 수 있도록 unload할 때 날짜기준으로 파티셔닝을 했다.

UNLOAD ( 'SELECT * FROM TALBLE_NAME' )
TO 's3://{s3_bucket_name}/{S3_PREFIX}/'
IAM_ROLE ''
ALLOWOVERWRITE
PARQUET
PARTITION BY (year,month,day,hour)

UNLOAD 구문을 보면, PARTITION BY 키워드 이후에 파티셔닝을 할 컬럼을 추가하는 것이다.

 

년,월,시 기준으로 파티셔닝하여 s3에 저장

 

 

참고 : s3 unload 구문 

https://docs.aws.amazon.com/ko_kr/redshift/latest/dg/r_UNLOAD.html

 

UNLOAD - Amazon Redshift

UNLOAD 명령은 병렬 처리를 사용하도록 설계되었습니다. 따라서 대부분의 경우 특히, COPY 명령을 사용하여 테이블을 로드하는 데 파일이 사용되는 경우 PARALLEL을 활성화하는 것이 좋습니다.

docs.aws.amazon.com

 

2. Redshift Specturm 외부테이블로 사용한다.  ( Reshift <-> S3 )

자 이제 s3에 날짜기준으로 사용자 로그가 저장되어 있다. 그러면 이 저장된 데이터를 어떻게 효율적으로 사용할 수 있는가?

보통 s3에 있는 데이터를 불러와서 redshift에서 쿼리를 실행하여 분석하려고 한다면, 추가적인 데이터 로딩작업이 필요하다.

하지만 지금 위에 저장한 것처럼 몇주간의 사용자 로그 데이터도 이렇게 계속 불러오는건가..? No..

심지어 주기적으로 불러와야하는 작업인데, 이렇게 용량이 큰 데이터를 redshift가 계속해서 가지고온다? 

벌써부터 redshift가 힘들어하는게 느껴진다.... 그래서 redshift specturm이라는 기능을 사용해보았다!

 

redshift specturm은 데이터로딩이나 ETL없이, s3에 있는 데이터소스를 '직접' 읽을 수 있는 기능이다. 

reshift docs에 따르면, Redshift Spectrum 테이블이 정의된 후 다른 Amazon Redshift 테이블과 똑같이 테이블을 쿼리하고 조인할 수 있습니다. Redshift Spectrum은 외부 테이블에 대한 업데이트 작업을 지원하지 않습니다. 라고 한다.

결국 추가적인 데이터 로딩없이 바로 s3에 있는 데이터가 redshift에서 쿼리할 수 있는 테이블 즉, 외부테이블 로 만들어지는 것이다! 

 

이게 가능한 이유는 aws glue와 athena가 파일구조를 정의하고 외부 데이터 카탈로그에 테이블로 등록해주기 때문이다.

데이터 카탈로그는 원본 데이터와 변환 데이터의 스키마정보, 파티션정보, 데이터위치 등 메타데이터를 저장한다. 

redshift docs에 따르면, 외부 데이터 카탈로그에 연결된 다른 도구(AWS Glue, Amazon Athena)를 사용하여 Amazon Redshift에서 외부 테이블을 생성하고 관리할 수 있습니다.

즉, 외부 데이터 카탈로그에 연결되면 redshift에서 외부테이블을 생성하고 관리할 수 있는 것이다.

 

뿐만 아니라 redshift docs에 따르면,  Redshift Spectrum은 외부 테이블에 대한 업데이트 작업을 지원하지 않습니다. Redshift Spectrum 테이블을 여러 Amazon Redshift 클러스터에 추가하여 같은 AWS 리전의 어느 클러스터에서나 Amazon S3에 있는 동일한 데이터를 쿼리할 수 있습니다. Amazon S3 데이터 파일을 업데이트하면 어느 Amazon Redshift 클러스터에서나 해당 데이터를 즉시 사용할 수 있습니다.

즉, reshift 외부테이블이 바라보고 있는 s3 데이터파일이 변경되면 자동으로 redshift 테이블도 즉시 업데이트 된다는 이야기이다

 

참고 : Amazon Redshift Spectrum 개요

https://docs.aws.amazon.com/ko_kr/redshift/latest/dg/c-using-spectrum.html#c-spectrum-overview

 

Amazon Redshift Spectrum을 사용하여 외부 데이터 쿼리 - Amazon Redshift

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

 

그래서 아래처럼 외부테이블을 생성했다.

CREATE EXTERNAL TABLE schema_name.table_name
(
    user_id VARCHAR(20),
    content_id VARCHAR(20),
    event_time DOUBLE,
    event_type VARCHAR(20)
)
STORED AS PARQUET
LOCATION 's3://{s3_bucket_name}/{S3_PREFIX}/

CREATE EXTERNAL TABLE 구문을 보면, LOCATION 키워드가 있다.

이 키워드 이후에 s3저장경로를 지정해주면 된다(뒤에 / 로 끝나도록)

위의 요구사항에 따라 매 시간 수집하는 유저로그들을 저장하는 s3경로로 지정했다. 

 

참고 : create external table구문

https://docs.aws.amazon.com/ko_kr/redshift/latest/dg/r_CREATE_EXTERNAL_TABLE.html

 

CREATE EXTERNAL TABLE - Amazon Redshift

CREATE EXTERNAL TABLE 지정된 스키마에서 새 외부 테이블을 생성합니다. 모든 외부 테이블은 외부 스키마에 생성해야 합니다. 외부 스키마와 외부 테이블에 대해서는 검색 경로가 지원되지 않습니다.

docs.aws.amazon.com

 

그러면 아래처럼 glue에서 해당 테이블의 메타정보를 알려주는 데이터카탈로그 테이블에서 확인해볼수있다! 

 

3. copy하여 redshift에 insert한다.  ( S3 -> Redshift )

redshift에서 외부테이블과 조인을 하던, 어떤 쿼리로 쿵짝쿵짝 데이터 분석해서 결국 최종 결과를 만들어놧다고 치자. 

보통은 최종적으로 서빙해야하는 결과는 따로 보관을 하는 저장소에 저장을 한다. 

그런데 이번 케이스같은 경우는 그 결과가 약 600만 Row수를 가지며 너무 컸다... 

이렇게 큰 결과를 한번에 insert하면 될까..? 어떻게 하면 효율적으로 저장할수 있을까?

 

사실 그래서 챗GPT한테 물어보기도 했다. 

 

챗지피티가 알려준 5가지 방법 중에서 가장 쉬운 방법은 batch insert였다.

그래서 처음에는 배치사이즈를 1000개로 해서 분할해서 Insert해보려고 했다.

그런데 거의 10분이상 소요되었고, insert하는 동안 cpu와 io사용량도 계속 올라가서 불안불안 했다...!

 

그래서 두번째로 copy명령어를 시도해서 Insert 했다. 

대신 최종결과를 insert하기 위해 s3에 추가로 업로드를 해야했고, s3에 업로드한 파일과 스키마를 맞춘 테이블 생성 DDL문이 필요했다.

"""
CREATE TABLE table_name (
        content_id VARCHAR(20),
        cluster_index BIGINT,
        distance FLOAT,
        create_date VARCHAR(10)
    )
 """,
f"""
   COPY table_name
   FROM 's3://{s3_bucket_name}/{S3_PREFIX}/{file_name}'
   IAM_ROLE ''
   PARQUET
 """

그랬더니 batch로 insert할때는 10분이나 걸렸던게 거의 10초만에 insert 됐다! 

 

참고: copy 명령어

https://docs.aws.amazon.com/ko_kr/redshift/latest/dg/r_COPY.html

 

COPY - Amazon Redshift

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

 

 

대용량 데이터에 대한 고민 ? 해결! 

자자 그럼 글 초반에 의문을 가졌던 고민사항에 대해 정리해보면 아래와 같다! 

1. 수집한 대용량 로그 데이터를 어디에 어떻게 저장할 것인가?  날짜기준으로 파티셔닝하여 redshift에서 s3로 unload하여 저장한다.

2. 분석하기 위해 대용량 데이터를 불러오는 가장 효율적인 방법은?

redshift specturm 기능을 사용해서 데이터로딩없이 데이터를 불러와서 redshift에 external table을 만든다. 

이때 이 외부테이블은 s3경로를 바라보고 있어서 s3데이터가 바뀌면 자동으로 외부테이블도 업데이트 된다.

3. 최종 분석결과를 어디에 어떻게 저장할 것인가? 

대용량일 경우 바로 Insert하기 보다, batch insert 하기 보다,  s3에 결과를 업로드한 뒤 이를 copy해서 reshift에 insert한다.

 

 

뭐랄까..마치 짱구가 흰둥이로 변해버린것 같은 그런기분..?  

 

반응형

$(document).ready(function() { var $toc = $("#toc"); $toc.toc({content: ".tt_article_useless_p_margin", headings: "h2,h3,h4"}); });