본문 바로가기

data engineering/data warehouse

Amazon Redshift -3 (최적화 기법 - 분산, 정렬, 캐싱)

 

https://nani-log.tistory.com/162

 

Amazon Redshift -2 (아키텍처)

https://nani-log.tistory.com/161 Amazon Redshift -1 (설계적 특성 - OLAP, Columnar Storage, MPP)Amazon Redshift는 직접 하둡 클러스터를 운영하지 않아도 클라우드상에서 데이터 웨어하우스를 운영할 수 있게 해준다.

nani-log.tistory.com

 

 

앞선 포스트에선 Redshift의 아키텍처에 대해 살펴봤다. Redshift가 가지고 있는 리소스로 병렬성과 효율을 극대화하려면 사실 테이블을 생성해 데이터를 각 노드에 저장하는 것부터 정말 중요하다. 이번 포스트에선 Redshift가 최적화하는 방법인 분산과 정렬, 그리고 캐싱에 대해 살펴보자

 

 

분산(Distribution)

데이터를 여러 노드와 슬라이스에 나누어 저장하고 처리하는 방식을 분산이라고 한다. 데이터가 잘 분산되면 해당하는 데이터를 각 슬라이스의 리소스를 통해 처리할 수 있기 때문에 병렬성을 극대화하고 데이터 이동을 최소화해 네트워크 대역폭을 아껴줄 수 있다

 

Redshift에서는 크게 4가지 분산 스타일을 선택할 수 있다

  1. EVEN
    • 라운드-로빈 방식으로 슬라이스 전체에 데이터를 분산한다
    • 테이블이 조인에 참여하지 않는 경우, 혹은 KEY/ALL 스타일 중 명확한 선택지가 없는 경우 적합하다
  2. KEY
    • 한 컬럼을 키로 지정하면 그 컬럼을 기준으로 데이터를 분산한다
    • 동일한 노드 슬라이스에 같은 값을 가지는 데이터를 배치하기 때문에 주로 조인에 참여하는 키를 설정하는 것이 좋다
  3. ALL
    • 전체 테이블의 복제본이 모든 노드에 복제된다
    • 조인이나 CTE에 자주 참조되는 작은 디멘젼 테이블에 대해 설정하는 것이 좋다 (작다의 기준 = 50~100만 행)
    • 노드 수에 따라 사용되는 스토리지가 증가하므로 로드, 수정, 삽입 등에 시간이 오래 걸린다
  4. AUTO
    • 테이블 크기를 기반으로 최적의 분산 스타일을 자동으로 지정해준다
    • 초기 작은 테이블엔 ALL 스타일을 지정하다가, 테이블이 커지면 PK를 분산 키로 지정한다
    • 테이블이 커졌지만 적합한 컬럼이 없으면 EVEN 스타일로 균등하게 분산한다

각 분산 스타일에 대한 정답이 존재하진 않는다. 다만 상황에 따라 적합한 스타일이 있을 뿐이다. 그럼 분산 스타일을 어떻게 선택하는 것이 현명할까? 바로 Redshift에서 실행되는 쿼리 패턴을 파악하는 것이 중요하다

 

방법론적으로 간단하게 설명하면, 시스템에서 가장 비용이 비싼 쿼리들을 식별하고 이 쿼리의 수요를 기반으로 데이터베이스를 설계할 수 있다. 쿼리의 총 비용은 쿼리를 실행하는 시간 + 실행 빈도 + 쿼리가 소비하는 컴퓨팅 리소스 + 데이터베이스 작업에 미치는 부정적인 영향으로 설명할 수 있는데 이를 감안해 설정하는 것이 좋다

 

 

 

정렬키(Sort key)

테이블 생성시 컬럼을 지정해 데이터를 정렬한 형태로 블록에 저장할 수 있다. 특히 정렬키를 사용하면 조건절을 처리할때 필요한 블록만을 검색하면 되기에 더 효율이 높아지는데, 블록의 최대/최소값을 메타데이터로 저장하고 필요한 블록만을 검색하는 것을 zone mapping이라고 한다

 

정렬키는 다음 3가지 방법으로 지정할 수 있다

  • Sort key
    • 특정 한 컬럼을 기준으로 정렬한다
    • 쿼리에서 자주 사용되는 필터 조건에 맞게 설정하면 쿼리 성능을 최적화할 수 있다
  • Compound Sort key
    • 여러 컬럼을 순차적으로 가중치를 둬 정렬한다
    • 특히 첫번째 지정한 컬럼을 우선으로 정렬하고, 두번째로 지정한 컬럼부턴 성능이 희석되만 그럼에도 성능 향상은 존재한다
  • Interleaved Sort key
    • 모든 정렬키에 동등한 가중치를 부여한다
    • 명확하게 설정할 정렬키가 없는 경우 적합하지만, 모든 컬럼의 가중치가 동일해 데이터가 큰 경우 셔플이 크게 발생할 수 있다

정렬키를 잘 선택하면 필요한 블록만을 읽을 수 있기 때문에, 정렬키를 현명하게 선택하기 위해선 결국 필터 조건으로 쓰이는 컬럼이나 조인에 참여하는 키를 지정하는 것이 좋을 것이다

 

정렬의 숨은(?) 이점으론 압축률이 좋아진다는 것이다. Redshift는 컬럼을 기준으로 저장하기 때문에 정렬된 컬럼이 같은 블록 내에 존재하면 유사한 값이 많아 압축률이 좋아지고, 더 많은 데이터를 적은 스토리지를 사용해 저장할 수 있다. 생각해보면 정말 중요한 지점인데, 컴퓨팅 리소스는 충분하지만 스토리지만 부족해져도 노드를 확장해야하기 때문에 압축률을 높이는 것은 아주 중요한 체크 포인트다

 

 

 

캐싱(Caching)

컴퓨터 구조에서 CPU가 효율성을 높이기 위해 캐시 메모리를 사용하듯이, Redshift는 쿼리 실행 계획과 쿼리 결과에 대한 캐싱 전략을 통해 쿼리 처리의 효율을 높인다

 

  • 쿼리 실행 계획에 대한 캐싱
    • 쿼리를 처음 실행하면, 리더 노드는 데이터가 저장된 위치를 기반으로 최적의 실행 계획을 구상한다
    • 해당 실행 계획은 메타데이터 저장소에 캐싱되어 나중에 같은 쿼리 실행시 캐싱된 실행 계획을 기반으로 실행된다
  • 쿼리 결과에 대한 캐싱
    • 쿼리 결과를 캐싱해 쿼리를 재실행하거나 다른 구성원이 실행할 때 다시 쿼리를 실행하지 않고 캐싱된 결과를 제공한다
    • 매번 데이터베이스를 조회하지 않아 네트워크 트래픽과 디스크 I/O를 줄이고, 빠른 시간 내에 쿼리 결과를 제공한다
    • 하지만 데이터가 변경된 경우엔 캐시가 무효화되고, 쿼리가 다시 실행된다

캐싱으로 인한 장점을 요약하자면 쿼리 처리 시간을 단축하고 컴퓨터 리소스와 네트워크 대역폭을 절약할 수 있다는 점이다. Redshift는 이를 통해 한정된 리소스를 효율적으로 사용할 수 있다

 

 

 

여러 사용자가 동시에 같은 슬라이스에 저장된 데이터를 요청하면 어떻게 처리할까?

여러 최적화 기법을 봤지만, 여전히 남는 궁금증은 '여러 사용자가 동시에  같은 슬라이스에 저장된 데이터를 요청하면 어떻게 처리할까?'라는 측면이다

 

Redshift에서 이런 워크로드를 최적화하기 위해선 원인자로서 먼저 분산, 정렬을 통해 처리를 위한 리소스에 대한 병렬성을 높이고 효율적으로 사용하려고 한다. 그리고 워크로드를 관리하기 위해 캐싱과 쿼리의 우선순위, 리소스 할당 전략, 실행 순서 등을 조정해 최대한 사용자에게 빠르게 결과를 반환해주려 노력한다

 

다음 포스트에선 워크로드를 관리하기 위한 방법에 대해 더 자세히 살펴보고자 한다