데이터 엔지니어링

[데이터 중심 애플리케이션 설계] 6장 파티셔닝

* 이 글은 [데이터 중심 애플리케이션 설계]를 공부하며 기록을 남긴 것입니다.


파티셔닝==샤딩

샤딩: 데이터셋이 매우 크거나 질의 처리량이 매우 높을 때, 데이터를 파티션으로 쪼개어 저장하는 방법

  • 레코드, 로우, 문서 등을 단위로 삼아 여러 파티션에 나눠 저장한다.
  • 목적: 데이터와 질의 부하를 노드 사이에 고르게 분산시키는 것. 파티셔닝을 하면 대용량 데이터셋이 여러 저장소에 분산되고, 질의 또한 여러 프로세스로 분산되어 병렬 처리까지 가능해진다. 즉, 확장에 용이해진다.
  • 복제와 파티셔닝을 함께 적용 -> 각 파티션의 복사본을 여러 노드에 저장함으로써 내결함성 보장

 

파티셔닝을 하는 방법

파티셔닝은 데이터와 질의 부하를 고르게 분산시킨다는 목적이 있는데, 그렇지 못하고 특정 파티션에 작업이 몰리면 파티셔닝의 효과가 매우 떨어진다. 이런 상황을 쏠렸다(skewed)고 하며, 부하가 높은 파티션을 핫스팟이라고 한다.

key-value 모델을 사용한다고 했을 때 해결 방법은 아래와 같다.

1) 범위 기준 파티셔닝

  • 연속된 범위 내의 키를 할당
  • 데이터의 분포를 고려하여 각 범위의 크기를 조정
  • 파티션 안에서 키를 기준으로 정렬, 효율적인 범위 질의
  • but, 특정한 접근 패턴이 핫스팟 유발(타임스탬프를 키로 사용할 경우, 특정 시간대에 몰릴 가능성)

2) 해시값 기준 파티셔닝

  • 해시 함수를 사용하여 키를 지정, 특정 범위의 해시값들을 모아 한 파티션에 할당
  • 해시 함수를 사용하면, 쏠린 데이터를 고르게 분산시킨다!
  • but, 해시를 거친 값은 원래의 의미를 잃어버리므로 정렬이 의미 없게 된다.
  • 카산드라는 복합 기본키를 사용하여, 효율적인 해싱과 색인이 되도록 함
  • 해싱만으로 부족한 경우도 많음 → 너무 많이 쏠리는 경우, 키에 임의의 숫자를 부여하여 다시 한번 분산될 수 있도록 한다. 하지만 읽기를 할 때 추가적인 작업이 필요하고, 저장해야 할 정보도 늘어나는 단점.

 

보조 색인

기본키의 목적이 레코드를 유일하게 식별하기 위함이라면, 보조 색인은 검색을 보조하는 것이 목적이다. 기본키를 기준으로 하는 파티션에는 깔끔하게 대응되지 않는다는 문제점이 있다. 보조 색인이 있는 경우 파티셔닝을 하는 방법은 아래와 같다.

1) 문서 기반 파티셔닝(지역 색인)

  • 문서 고유 ID를 기준으로 파티셔닝 → 각 파티션이 독립적으로 동작
  • 모든 파티션에 동일한 보조 색인을 구현하고, 각 파티션에 할당된 문서들만 파티션 내에서 관리한다.
  • scatter/gather 방식
    • 특정 문서는 하나의 파티션 내에만 존재하고 보조 색인은 모든 파티션에 구현되어 있으므로, 특정 보조 색인으로 검색을 하려면 모든 파티션으로 질의를 보내서 결과를 모아야 한다.
    • 따라서 큰 비용이 들 수 있고, 꼬리 지연 시간 증폭이 발생할 수 있다.
    • 그럼에도 쓰는 이유? 뭘까..

2) 용어 기반 파티셔닝(전역 색인)

  • 용어(또는 해시값) 기준 파티셔닝
  • 각 파티션에 독립된 보조 색인 + 전역 색인으로 구성
  • 읽기가 효율적이지만 느리고 복잡함
  • 색인을 항상 최신 상태로 유지 → 색인을 사용할 때 모든 파티션에 걸친 분산 트랜잭션 필요 → 현실적으로 어렵기 때문에 대부분의 색인은 비동기로 갱신됨

 

파티션 재균형화

질의 처리량 증가, 데이터셋 증가, 장애 발생 등의 이유로 데이터를 다른 노드로 옮겨야 하는 상황이 생기며 이를 재균형화라고 한다. 재균형화를 위한 전략은 3가지가 있다.

0) 해시값에 모드(%) N 연산

  • % 연산을 하게 되면 재균형화 시 대부분의 노드가 옮겨져야 하기 때문에 쓰면 안 되는 방법이다.

1) 파티션 개수 고정

  • 파티션을 노드 개수보다 많이 만들고 각 노드에 여러 파티션을 할당하는 방식
  • 파티션을 재설정해서 분배하는 것이 아니라 기존 노드가 가지고 있던 파티션을 새로운 노드에 할당
  • 파티션 개수에 변화가 없기 때문에 운영이 쉽지만, 적절한 파티션 개수를 정하기 어렵다.
    • 너무 크면 재균형화/장애 복구 비용이 커지고, 작으면 오버헤드가 커짐
  • 파티션 크기가 데이터셋 크기에 비례

2) 동적 파티셔닝

  • 범위 기준 파티셔닝을 사용하는 경우, 데이터가 쏠릴 수 있어 파티션이 고정되어 있는 것이 안 좋다.
  • 파티셔닝을 동적으로 → 파티션 크기가 일정 이상 커지면 두 개로 쪼개고 반대 과정도 한다.
  • 파티션 개수가 전체 데이터 크기에 맞춰 조정됨 → 1번의 단점 x
  • 초기 데이터베이스에서는 파티션이 하나로 시작할 수도 있다.
  • 파티션 개수가 데이터셋 크기에 비례

3) 노드 비례 파티셔닝

  • 노드당 할당되는 파티션의 개수를 고정(n) → 노드 대수가 일정하면 파티션의 크기가 커지고, 많아지면 작아진다
  • 새 노드가 추가되면, 기존 파티션 중 n개를 무작위로 선택하여 반으로 분할하고 반을 새 노드에 할당해준다
    • 균등하지 않은 분할이 생길 수 있지만 전체적으로 보면 기존 노드의 부하를 균등하게 나눠 받는 효과가 있다
    • 무작위 선택에는 '해시 기반 파티셔닝'이 사용됨
    • 카산드라 3.0 → 불균등한 분할 회피를 위한 재균형화 알고리즘
  • 파티션 개수가 노드 대수에 비례

 

요청 라우팅

이제 데이터를 여러 노드로 파티셔닝 할 수 있다! 그런데..

  • 클라이언트에서 어떤 노드로 요청을 보내지?
    1. RR 등으로 아무 노드에 접속 → 첫 노드가 요청을 올바른 노드로 전달(일종의 라우팅) → 응답을 받고 클라이언트에게 전달
      • 이런 방법은 노드에 복잡성을 더하지만 외부 코디네이션 서비스에 의존하지 않을 수 있다.
    2. 모든 요청이 '라우팅 계층'을 통과하도록 함
    3. 클라이언트가 파티셔닝 방법/노드를 알고있어 직접 접근한다
  • 라우팅 계층에서 모든 파티션의 변경사항을 알고 있어야 문제가 안생긴다.
    • 9장 참고
    • 많은 분산 시스템은 이를 해결하기 위해 Zookeeper같은 코디네이션 서비스를 사용한다.
    • 모든 노드는 주키퍼에 정보를 등록, 파티션과 노드 사이의 할당 정보를 관리하고 최신으로 유지하는 역할