이 글은 책 내용을 토대로 작성하였습니다.
목차
Goal
- 파티셔닝 글 시리즈에서는 다음과 같은 부분들을 살펴본다.
-
대용량 데이터셋을 파티셔닝하는 방법
-
인덱싱과 파티셔닝의 상호작용 방법
-
클러스터에 노드 추가/삭제 시 재균형화 과정
-
DB가 어떻게 요청을 올바른 파티션에 전달 및 질의를 하는지 그 실행 과정에 대학 학습
파티셔닝
-
데이터셋이 매우 크거나 질의 처리량이 매우 높다면
복제만으로는 부족하고 데이터를 파티션으로 쪼갤 필요가 있다.
-
파티션을 나눌 때는 보통 각 데이터 단위(레코드, 로우, 문서)가 하나의 파티션에 속하게 한다.
DB가 여러 파티션을 동시에 건드리는 연산을 지원할 수도 있지만
결과적으로 각 파티션은 그 자체로 작은 DB가 된다.
파티셔닝 목적
-
데이터 파티셔닝을 하는 주된 이유는 확장성이다.
-
단일 파티션에 실행되는 질의를 생각해 보면
각 노드에서 자신의 파티션에 해당하는 질의를 독립적으로 실행할 수 있으므로
노드를 추가함으로써 질의 처리량을 늘릴 수 있다.
-
크고 복잡한 질의는 훨씬 더 어렵기는 하지만
여러 노드에서 병렬 실행이 가능하다.
-
또다른 이유로는 데이터와 질의 부하를 노드 사이에 고르게 분산시키는 것이다.
키-값 데이터 파티셔닝
-
대량의 데이터를 파티셔닝한다고 생각해보자.
어떤 레코드를 어느 노드에 저장할지 어떻게 결정해야 할까?
핫스팟 개념
-
파티셔닝이 고르게 이뤄지지 않아 부하가 높은 파티션을 핫스팟이라 부른다.
-
핫스팟을 회피하는 가장 단순한 방법은
레코드를 할당할 노드를 랜덤으로 선택하는 것이다.
-
그러면 데이터가 노드들 사이에 고르게 분산되지만
어떤 레코드를 조회 시 해당 레코드가 어느 노드에 저장됐는지 알 수 없어
모든 노드에 병렬적으로 질의해야 한다는 단점이 생긴다.
-
더 좋은 방법으로는 키-값 데이터 모델을 사용하는 것이다.
이 모델에서는 항상 기본 키를 통해 레코드에 접근한다.
-
예를 들어 종이 백과사전에서는 항목을 찾을 때 제목을 사용한다.
모든 항목이 제목의 알파벳 순으로 정렬돼 있으므로 언제나 찾고자 하는 항목을 빨리 찾을 수 있다.
키 범위 기준 파티셔닝
-
파티셔닝하는 방법 중 하나는 종이 백과사전처럼
각 파티션에 연속된 범위(최솟값 ~ 최댓값)의 키를 할당하는 것이다.
-
각 범위 사이의 경계를 알면
어떤 키가 어느 파티션에 속하는지 쉽게 찾을 수 있다.
-
또 어떤 파티션이 어느 노드에 할당됐는지 알면
적절한 노드로 요청을 직접 보낼 수 있다.
-
데이터가 고르게 분포하지 않을 수도 있으므로
키 범위 크기를 반드시 같게 할 필요는 없고
데이터에 맞춰 파티션 경계를 알맞게 조정해야 한다.
-
파티션 경계를 설정하는 방법으로는
관리자가 수동으로 선택하거나 DB가 자동으로 선택되게 할 수 있다.
그림 6-2에서 1권은 A,B로 시작하는 단어를 포함하지만 12권은 T,U,V,W,X,Y,Z로 시작하는 단어를 포함한다. 만약 알파벳 두 글자마다 1권씩 할당하면 다른 것들보다 훨씬 커지는 권이 생긴다.
-
각 파티션 내에서는 키를 정렬된 순서로 저장할 수 있다.
참고 : SS테이블과 LSM 트리
-
이렇게 하면 범위 스캔이 쉬워지는 이점이 있고
키를 연쇄된 인덱스로 간주해서 질의 하나로 관련 레코드 여러 개를 읽어오는 데 사용할 수 있다.
-
예를 들어 데이터의 타임스탬프를 키로 사용할 경우
범위 스캔을 써서 특정 월의 모든 데이터를 쉽게 읽을 수 있다.
단점
-
키 범위 기준 파티셔닝은 특정한 접근 패턴이 핫스팟을 유발하는 단점이 있다.
-
타임스탬프가 키라면 파티션은 시간 범위에 대응된다.
예를 들어 1일치의 데이터를 파티션 하나가 담당하는 식이다.
-
그래서 특정 날에 쓰기 요청이 많을 경우엔
그 날을 담당하는 파티션으로만 전달되어
해당 파티션만 과부하가 걸리고 나머지 파티션은 유휴 상태로 남아 있을 수 있다.
-
그러므로 이 문제를 회피하려면
키의 첫 번째 요소로 타임스탬프가 아닌 다른 것을 사용해야 한다.
-
예를 들어 특정 이름을 붙여서
파티셔닝할 때 이름을 먼저 사용 후 시간을 사용하게 할 수 있다.
키의 해시값 기준 파티셔닝
-
핫스팟의 위험 때문에
많은 분산 스토리지는 키의 파티션을 정하는 데 해시 함수를 사용한다.
-
파티셔닝용 해시 함수는 암호적으로 강력할 필요가 없다.
예를 들어 카산드라와 몽고DB는 MD5를 사용한다.
-
주의할 점은 많은 프로그래밍 언어에
간단한 해시 함수가 내장돼 있지만 파티셔닝에는 적합하지 않을 수 있다.
-
예를 들어 자바의 Object.hashCode( )와
루비의 Object#hash는 같은 키를 넣어도 다른 프로세스에서는 다른 해시값을 반환할 수 있다.
-
키에 적합한 해시 함수를 구했다면
각 파티션에 키 범위 대신 해시값 범위를 할당하고
해시값이 파티션의 범위에 속하는 모든 키를 그 파티션에 할당하면 된다.
모드(Mod) 연산을 사용하지 않고 해시값 범위를 정하는 이유
-
파티셔닝 범위를 정할 때 모드 연산을 사용하지 않는 이유가 뭘까?
답이 궁금하다면 해시값에 모드 N 연산을 실행하지 않는 이유 글을 참고하자.
일관성 해싱
-
이 기법은 키를 파티션 사이에 균일하게 분산시키는 데 좋다.
파티션 경계는 크기가 동일하도록 나눌 수도 있고 무작위에 가깝게 선택할 수도 있다.
이런 기법을 일관성 해싱이라고 부른다.
일관성 해싱
-
CDN 같은 캐시 시스템에서 부하를 균등하게 분산시키는 방법이다.
중앙 제어나 분산 합의가 필요하지 않도록 파티션 경계를 무작위로 선택한다.
한계
-
파티셔닝에 키의 해시값을 사용하면 키 범위 파티셔닝의 장점을 잃어버린다.
= 범위 질의를 효율적으로 실행할 수 있는 장점을 잃어버린다.
-
전에는 인접했던 키들이 이제는 모든 파티션에 흩어져서 정렬 순서가 유지되지 않는다.
몽고DB에서는 해시 기반 샤딩 모드를 활성화하면 범위 질의가 모든 파티션에 전송된다.
리악, 카우치베이스, 볼드모트에서는 기본키에 대한 범위 질의가 지원되지 않는다.
카산드라
-
2가지 파티셔닝 전략 사이에서 타협한다.
-
카산드라에서 테이블 생성 시 여러 컬럼을 포함하는 복합 기본키를 지정할 수 있다.
키의 첫 부분에만 해싱을 적용해 파티션 결정에 사용하고
남은 컬럼은 카산드라의 SS테이블에서 데이터를 정렬하는 연쇄된 인덱스로 사용한다.
-
따라서 복합 키의 첫 번째 컬럼에 대해서는 값 범위로 검색하는 질의를 할 수 없지만
첫 번째 컬럼에 고정된 값을 지정하면 키의 다른 컬럼에 대해서는 범위 스캔을 효율적으로 할 수 있다.
쏠린 작업부하와 핫스팟 완화
-
키를 해싱해서 파티션을 정하면
핫스팟을 줄이는 데 도움이 되지만 완벽히 제거할 수 없다.
-
항상 같은 키를 읽고 쓰는
극단적인 상황에서는 모든 요청이 같은 파티션으로 쏠리게 되기 때문이다.
-
아마도 이런 작업부하는 드물겠지만 전혀 없진 않다.
예를 들어 SNS에서 유명인이 뭔가를 하게 되면 발생할 수 있다.
-
현대 데이터 시스템은
대부분 크게 쏠린 작업부하를 자동으로 보정하지 못하므로
어플리케이션에서 커버를 해야 한다.
-
예를 들어 요청이 매우 많은 키를 발견했을 때
간단한 해결책은 각 키의 시작이나 끝에 임의의 숫자를 붙여
( 값 하나만 추가해도 해싱의 결과는 달라진다. )
1개의 파티션이 아닌 n개의 키로 쪼개어 분산시킬 수 있다.
-
그런데 이 또한 문제가 있는데
읽기 실행 시 추가적인 작업이 필요해진다.
-
여기서 말하는 추가적인 작업이란
원래 키에 어떤 작업을 했는지 파악 후
같은 작업을 통해 값을 읽는 것을 뜻한다.
-
그러므로 이 기법은 요청이 몰리는 소수의 키에만 적용해야 한다.
쓰기 처리량이 낮은 대다수의 키에도 적용하면 불필요한 오버헤드가 생긴다.