개발독서/데이터

[고투런1기] 데이터 중심 애플리케이션 설계 (6장 파티셔닝)

보리시스템 2024. 6. 9.

[2부 분산 데이터]

06장: 파티셔닝
1. 파티셔닝과 복제

2. 키-값 데이터 파티셔닝
2.1 키 범위 기준 파티셔닝
2.2 키의 해시값 기준 파티셔닝
2.3 쏠린 작업부하와 핫스팟 완화

3. 파티셔닝과 보조 색인
3.1 문서 기준 보조 색인 파티셔닝
3.2 용어 기준 보조 색인 파티셔닝

4. 파티션 재균형화
4.1 재균형화 전략
4.2 운영: 자동 재균형화와 수동 재균형화

5. 요청 라우팅
5.1 병렬 질의 실행

 

[정리: 여러 장비로 분산해 저장하는 데이터]

- 파티셔닝
=> 대용량 데이터셋을 더 작은 데이터셋으로 쪼개는 것
=> 저장/처리할 데이터가 너무 많아 장비 한 대로 처리하는 게 불가능해지면 파티셔닝이 필요
=> 핫스팟이 생기지 않게 하면서 데이터와 질의 부하를 여러 장비에 균일하게 분배하도록 해야 함
* 핫스팟? 불균형적으로 높은 부하를 받는 노드
 
- 2가지 주요 파티셔닝 기법
1) 키 범위 파티셔닝
=> 키가 정렬돼 있고 개별 파티션은 어떤 최소값과 최댓값 사이에 속하는 모든 키를 담당
=> 한 파티션이 너무 커지면 키 범위를 2개로 쪼개 동적으로 재균형화 실행
=> 장점? 키가 정렬돼 있어 범위 질의가 효율적
=> 단점? 애플리케이션에서 정렬 순서가 서로 가까운 키에 자주 접근하면 핫스팟이 생길 위험이 있음

2) 해시 파티셔닝
=> 각 키에 해시 함수를 적용하고 개별 파티션은 특정 범위의 해시값을 담당
=> 고정된 개수의 파티션을 미리 만들어 각 노드에 몇 개씩의 파티션을 활당하며 노드가 추가되거나 제거되면 파티션을 통째로 노드 사이에서 이동
=> 동적 파티셔닝을 쓸 수도 있음
=> 키의 일부분은 파티션 식별용으로, 나머지는 정렬 순서용으로 만든 복합 키를 사용할 수도 있음
=> 장점? 부하를 더욱 균일하게 분산할 수 있음
=> 단점? 키 순서가 보장되지 않아 범위 질의가 비효율적

- 보조 색인 파티셔닝 2가지 방법
1) 문서 파티셔닝 색인(지역 색인)
=> 보조 색인을 기본키와 값이 저장된 파티션에 저장
=> 문서 쓰기 시 파티션 하나만 갱신
=> 보조 색인 읽기 시 모든 파티션에 걸쳐서 스캐터/개더 실행해야 함

2) 용어 파티셔닝 색인(전역 색인)
=> 색인된 값을 사용해서 보조 색인을 별도로 파티셔닝
=> 보조 색인 항목은 기본키 파티션에 있는 레코드를 포함할 수 있음
=> 문서 쓰기 시 보조 색인 여러 개를 갱신해야 함
=> 보조 색인 읽기 시 단일 파티션에서 실행될 수 있음

- 파티션 인지 로드 밸런서에서 복잡한 병렬 질의 처리 엔진까지 질의를 올바른 파티션으로 라우팅하는 기법
1) 쓰면 안되는 방법: 해시값에 모드 N 연산을 실행
2) 파티션 개수 고정
3) 동적 파티셔닝
4) 노드 비례 파티셔닝

 


 

6장 파티셔닝

- 샤딩?
=> 데이터셋이 너무 크거나 질의 처리량이 매우 높다면 복제만으로 부족함
=> 데이터를 파티션으로 쪼갤 필요가 있음

- 파티션
=> 파티션이라는 용어로 가장 많이 사용함
=> 다른 용어로 사용하는 경우?
1) 샤드(shard): 몽고DB, 엘라스틱서치, 솔라클라우드
2) 리전(region): HBase
3) 태블릿(tablet): 빅테이블
4) 브이노드(vnode): 카산드라, 리악
5) 브이버켓(vBucket): 카우치베이스

- 파티션을 나눌 때는 보통 각 데이터 단위(레코드, 로우, 문서)가 하나의 파티션에 속함
=> 각 파티션은 그 자체로 작은 DB가 됨

- 데이터 파티셔닝의 목적은 확장성
=> 비공유 클러스터(shared-nothing cluster)에서 다른 파티션은 다른 노드에 저장될 수 있음
=> 대용량 데이터셋이 여러 디스크에 분산될 수 있고 질의 부하는 여러 프로세서에 분산될 수 있음

- 파티셔닝 지원 DB
=> 1980년대 테라데이터(Teradata), 탠덤 논스톱 SQL(Tandem Nonstop SQL)
=> 최근 NoSQL DB, 하둡 기반 데이터 웨어하우스
=> 어떤 시스템은 트랜잭션 작업부하용으로 어떤 시스템은 분석용으로 설계됨

 


 

1. 파티셔닝과 복제

- 보통 복제와 파티셔닝을 함께 적용해 각 파티션의 복사본을 여러 노드에 저장함
=> 각 레코드는 정확히 한 파티션에 속하더라도 여러 다른 노드에 저장해 내결합성을 보장할 수 있음

- 한 노드에 여러 파티션을 저장할 수도 있음
=> 각 파티션의 리더는 하나의 노드에 할당되고 팔로워들은 다른 노드에 할당
=> 각 노드는 어떤 파티션에게는 리더이면서 다른 파티션에게는 팔로워가 될 수 있음

 



2. 키-값 데이터 파티셔닝

- 파티셔닝의 목적?
=> 데이터와 질의 부하를 노드 사이에 고르게 분산시키는 것

- 쏠림(skew partition)
=> 파티셔닝이 고르게 이뤄지지 않아 다른 파티션 보다 데이터가 많거나 질의를 많이 받는 파티션이 있는 경우
=> 쏠림이 있으면 파티셔닝의 효과는 매우 떨어짐

- 핫스팟 방지 방법
* 핫스팟? 불균형하게 부하가 높은 파티션

1) 레코드를 할당할 노드를 무작위로 선택하기
=> 가장 간단한 방법임
=> 하지만 모든 노드에서 병렬적으로 질의해야 하는 단점이 있음
* 어떤 레코드를 읽을 때 해당 레코드가 어느 노드에 저장됐는지 알 수 없기 때문임

2) 키 범위 기준 파티셔닝
=> 각 파티션에 연속된 범위(최솟값~최댓값)의 키를 할당하는 것
=> 각 범위들 사이의 경계를 알면 어떤 키가 어느 파티션에 속하는지 쉽게 찾을 수 있음
=> 어떤 파티션이 어느 노드에 할당됐는지 알면 적절한 노드로 요청을 직접 보낼 수 있음

3) 키의 해시값 기준 파티셔닝
=> 쏠림, 핫스팟의 위험 때문에 키의 파티션을 정하는 데 해시 함수를 사용함

 


 

2.1 키 범위 기준 파티셔닝

- 키 범위 크기는 반드시 동일할 필요는 없음
=> 데이터가 고르게 분포하지 않을 수도 있기 때문임

- 데이터를 고르게 분산시키기 위해서는 파티션 경계를 데이터에 맞춰 조정해야 함
=> 파티션 경계는 관리자가 수동으로 선택하거나 DB에서 자동으로 선택되게 할 수 있음
=> 빅테이블, 빅테이블의 오픈소스 구현체인 HBase, RethinkDB, 버전 2.4 이전의 몽고 DB에서 사용됨

- 각 파티션 내에서는 키를 정렬된 순서로 저장할 수 있음
=> 장점? 범위 스캔이 쉬워짐 / 키를 연쇄된 색인으로 간주해 질의 하나로 관련 레코드 여러 개를 읽어오는 데 사용할 수 있음
* 데이터 저장하는 애플리케이션에서 측정값의 타임스탬프를 키로 사용하는 경우 범위 스캔이 매우 쉬워짐

=> 단점? 특정한 접근 패턴이 핫스팟을 유발함
* 타임스탬프가 키라면 파티션은 시간 범위에 대응되어 센서에서 값이 측정될 때마다 데이터를 DB에 기록해 쓰기 연산이 모두 동일한 파티션(오늘 날짜)으로 전달돼 해당 파티션만 과부하가 걸리고 나머지 파티션은 유휴 상태로 남을 수 있음

=> 해당 문제를 방지하기 위해서는 키의 첫 번째 요소로 타임스탬프가 아닌 다른 것을 사용해야 함
* 예를 들어 타임스탬프 앞에 센서 이름을 붙여 파티셔닝할 때 센서 이름을 먼저 사용한 후 타임스탬프를 사용하게 하여 센서 이름마다 별개의 범위 질의를 실행할 수 있도록 함

 



2.2 키의 해시값 기준 파티셔닝

- 좋은 해시 함수?
=> 쏠린 데이터를 입력으로 받아 균일하게 분산되게 함

- 파티셔닝용 해시함수는 암호적으로 강력할 필요는 없음

- 키에 적합한 해시함수를 구했다면 각 파티션에(키 범위 대신) 해시값 범위를 할당하고 해시값이 파티션의 범위에 속하는 모든 키를 그 파티션에 할당하면 됨
=> 파티션 경계는 크기가 동일하도록 나눌 수 있음
=> 일관성 해싱 기법으로 무작위에 가깝게 선택할 수도 있지만 DB에서 실제로는 잘 동작하지 않기 때문에 현실에서 거의 사용되지는 않음

- 단점으로는 범위 질의를 효율적으로 실행할 수 있는 키 범위 파티셔닝의 좋은 속성을 잃어 버린다는 것임
=> 카산드라의 경우 테이블 선언 시 복합 기본키로 지정할 수 있도록 함


2.3 쏠린 작업부하와 핫스팟 완화

- 키를 해싱해서 파티션을 정하면 핫스팟을 줄이는 데 도움이 되지만 완벽히 제거할 수는 없음
=> 항상 동일한 키를 읽고 쓰는 극단적인 상황에서는 모든 요청이 동일한 파티션으로 쏠리게 됨

- 애플리케이션에서 쏠림을 완화할 필요가 있음
=> 예를 들어 요청이 많이 쏠리는 키를 발견하면 각 키의 시작 또는 끝에 임의의 숫자를 붙여 키들을 다른 파티션으로 분산할 수 있음
=> 하지만 쓰기 처리량이 낮은 키에 적용하면 불필요한 오버헤드가 생길 수 있으므로 어떤 키가 쪼개졌는지 추적하는 방법이 있어야 함 

 



3. 파티셔닝과 보조 색인

- 보조 색인?
=> 보통 레코드를 유일하게 식별하는 용도가 아닌 특정 값이 발생한 항목을 검색하는 수단임
=> 보조 색인은 관계형 DB의 핵심 요소이며 문서 DB에서도 흔함

- 보조 색인이 있는 DB 파티셔닝 방법 2가지
1) 문서 기준 보조 색인 파티셔닝
2) 용어 기준 보조 색인 파티셔닝

 


 

3.1 문서 기준 보조색인 파티셔닝 (지역 색인, local index)

- 몽고DB, 리악, 카산드라, 엘라스틱 서치, 솔라클라우드, 볼트DB에서 사용함

- 각 항목에는 문서 ID(document ID)라고 부르는 고유 ID가 있고 DB를 문서 ID 기준으로 파티셔닝
=> 각 파티션이 완전히 독립적으로 동작
=> 각 파티션은 자신의 보조 색인을 유지하며 그 파티션에 속하는 문서만 담당
=> 다른 파티션에 어떤 데이터가 저장되는지는 신경쓰지 않음

- 하지만 해당 색인 사용해 읽을 때는 주의 기울여야 함
=> 문서 ID에 어떤 특별한 작업을 하지 않는다면 동일한 파티션에 저장되리라는 보장은 없음

- 스캐터/개더 (scatter / gather)
=> 파티셔닝된 DB에 이런 방식으로 질의를 보내는 방법 
=> 보조색인을 써서 읽는 질의는 큰 비용이 들 수 있음
* 여러 파티션에서 질의를 병렬 실행하더라도 스캐터/개더는 꼬리 지연시간 증폭이 발생하기 쉽기 때문임

 



3.2 용어 기준 보조색인 파티셔닝 (전역 색인, global index)

- 리악의 검색기능, 오라클 데이터웨어하우스에서 사용

- 각 파티션이 자신만의 보조색인(지역색인)을 갖게하는 대신, 모든 파티션의 데이터를 담당하는 전역 색인을 만들 수도 있음
=> 찾고자 하는 용어에 따라 색인의 파티션이 결정됨
=> 용어? 문서에 등장하는 모든 단어

- 장점?
=> 지역 색인에 비해 읽기가 효율적 
=> 클라이언트는 모든 파티션에 스캐터/개더를 실행할 필요없이 원하는 용어를 포함하는 파티션으로만 요청을 보내면 됨

- 단점?
=> 쓰기가 느리고 복잡

- 대개 비동기로 갱신됨
=> 즉 쓰기를 실행한 후 바로 색인을 읽으면 변경사항이 색인에 반영되지 않았을 수도 있음

 



4. 파티션 재균형화

- 시간이 지남에 따라 DB에 변화가 생기는데 이때 데이터와 요청이 한 노드에서 다른 노드로 옮겨져야 함
=> 재균형화(rebalancing)? 클러스터에서 한 노드가 담당하던 부하를 다른 노드로 옮기는 과정

- 재균형화 실행 시 최소 요구사항
1) 재균형화 후, 부하(데이터 저장소, 읽기 쓰기 요청)가 클러스터 내에 있는 노드들 사이에 균등하게 분배돼야 함
2) 재균형화 도중에도 DB는 읽기 쓰기 요청을 받아들여야 함
3) 재균형화가 빨리 실행되고 네트워크와 디스크 I/O 부하를 최소화할 수 있도록 노드들 사이에 데이터가 필요 이상으로 옮겨져서는 안됨

 


 

4.1 재균형화 전략

  • 쓰면 안되는 방법: 해시값에 모드 N 연산을 실행
- 모드(mod) 연산을 쓰지 않는 이유?
=> 노드 개수 N이 바뀌면 대부분의 키가 노드 사이에 옮겨져야 함
=> 키가 자주 이동하면 재균형화 비용이 지나치게 커짐

 

  • 파티션 개수 고정
- 리악, 엘라스틱서치, 카우치베이스, 볼드모트에서 사용

- 파티션을 노드 대수보다 많이 만들고 각 노드에 여러 파티션을 할당하면 데이터를 필요 이상으로 이동하지 않을 수 있음

=> 클러스터에 노드가 추가되면 새 노드는 파티션이 다시 균일하게 분배될때 까지 기존 노드에서 파티션 몇 개를 뺏어올 수 있음
=> 클러스터에서 노드가 제거되면 이 과정이 반대로 실행됨

- 파티션은 노드 사이에서 통째로 이동하기만 함
=> 파티션 개수, 파티션에 할당된 키는 변경되지 않음
=> 노드에 어떤 파티션이 할당되는지만 변경됨

- 파티션 할당 변경은 즉시 반영되지 않고 네트워크를 통해 대량의 데이터를 전송해야 하므로 시간이 걸림
=> 데이터 전송이 진행 중인 동안에 읽기나 쓰기가 실행되면 기존에 할당된 파티션을 사용함

- 파티션 개수가 고정되면 운영이 단순해지므로 고정 파티션을 사용하는 DB는 파티션 분할을 지원하지 않는 경우가 많음
=> 따라서 처음 설정된 파티션 개수가 사용 가능한 노드대수의 최대치가 되므로 충분히 높은값으로 선택해야 함
=> 그러나 개별 파티션도 관리 오버헤드가 있으므로 너무 큰 수를 선택하면 역효과

 

  • 동적 파티셔닝
- HBase, RethinkDB에서 동적 파티셔닝을 사용

- 파티션 크기가 설정된 값을 넘으면 파티션을 2개로 쪼개 각각에 원래 파티션의 절반 정도의 데이터가 포함되게 함
=> 반대로 데이터가 많이 삭제되어 파티션 크기가 임곗값 아래로 떨어지면 인접한 파티션과 합칠 수 있음

- 장점?
파티션 개수가 전체 데이터 용량에 맞춰 조정됨

- 함정?
빈 DB는 파티션 경계를 어디로 정해야 하는지에 대한 사전 정보가 없으므로 시작할 때는 파티션이 하나
=> 문제 완화를 위해 HBase, 몽고DB에서는 빈 DB에 초기 파티션 집합을 설정할 수 있게 함 (사전 분할, pre-splitting)

 

  • 노드 비례 파티셔닝
- 카산드라, 케타마(Kerama)에서 사용

- 파티션 개수가 노드 대수에 비례하게 함 (노드당 할당되는 파티션 개수를 고정)
=> 일반적으로 데이터 용량이 클수록 데이터를 저장할 노드도 많이 필요하므로 이 방법을 쓰면 개별 파티션 크기도 상당히 안정적으로 유지됨
=> 새 노드가 클러스터에 추가되면 고정된 개수의 파티션을 무작위로 선택해 분할하고 각 분할된 파티션의 절반은 그대로 두고 다른 절반은 새 노드에 할당

 



4.2 운영: 자동 재균형화와 수동 재균형화

- 재균형화는 자동으로 실행될까, 아니면 수동으로 실행해야 할까?

- 완전 자동 재균형화
=> 관리자의 개입이 전혀 없이 시스템이 자동으로 언제 파티션을 노드 사이에 이동할지 결정
=> 장점? 일상적인 유지보수에 손이 덜 감
=> 단점? 예측이 어려움
* 주의 깊게 처리하지 않으면 네트워크나 노드에 과부화가 걸릴 수 있고, 재균형화가 진행 중인 동안에 실행되는 다른 요청의 성능이 저하될 수 있음
* 자동 장애 감지와 함께 사용하면 연쇄 장애가 발생하는 등 위험성이 있음

- 완전 수동 재균형화
=> 관리자가 명시적으로 파티션을 노드에 할당하도록 설정하고 관리자가 재설정할 때만 파티션 할당이 변경됨

- 완전 자동 재균형화와 완전 수동 재균형화의 중간 지점으로 하는 것이 좋음
=> 완전 자동 처리보다는 느릴 수 있지만 운영상 예상치 못한 일을 방지하는 데 도움이 될 수 있음
=> 카우치베이스, 리악, 볼드모트는 자동으로 파티션 할당을 제안하지만 반영되려면 관리자가 확정해야 함


5. 요청 라우팅

- 클라이언트에서 요청을 보내려고 할 때 어느 노드로 접속해야 하는지 어떻게 알 수 있을까?
1) 클라이언트가 라운드로빈 로드 밸런서 등을 통해 아무 노드에나 접속하게 하기

=> 만약 해당 노드에 마침 요청을 적용할 파티션이 있다면 거기서 요청을 직접 처리
=> 그렇지 않으면 요청을 올바른 노드로 전달해서 응답을 받고 클라이언트에게 응답을 전달

2) 클라이언트의 모든 요청을 라우팅 계층으로 먼저 보내고, 라우팅 계층에서는 각 요청을 처리할 노드를 알아내고 그에 따라 해당 노드로 요청을 전달
=> 라우팅 계층 자체에서는 아무 요청도 처리하지 않고 파티션 인지(parilion-aware) 로드 밸런서로 동작할 뿐

3) 클라이언트가 파티셔닝 방법과 파티션이 어떤 노드에 할당됐는지를 알고 있게 하기
=> 클라이언트는 중개자 없이 올바른 노드로 직접 접속할 수 있음

- 핵심 문제는 라우팅 결정을 내리는 구성요소가 노드에 할당된 파티션의 변경 사항을 어떻게 아느냐임
=> 구성요소는 노드 중 하나, 라우팅 계층, 클라이언트 등에 해당
=> 참여하는 모든 곳에서 정보가 일치해야 하므로 다루기 어려움

- 분산 데이터 시스템은 클러스터 메타데이터를 추적하기 위해 주키퍼 (ZooKeeper) 같은 별도의 코디네이션 서비스를 사용
=> 각 노드는 주키퍼에 자신을 등록하고 주키퍼는 파티션과 노드 사이의 신뢰성 있는 할당 정보를 관리
=> 다른 구성요소들은 주키퍼에 있는 정보를 구독
=> 주키퍼는 변경사항을 라우팅 계층에 알려서 라우팅 정보를 최신으로 유지

 


 

5.1 병렬 질의 실행

- 분석용으로 자주 사용되는 대규모 병렬 처리(massively parallel processing. MPP) 관계형 DB 제품은 훨씬 더 복잡한 종류의 질의를 지원함
=> MPP 질의 최적화기는 복잡한 질의를 여러 실행 단계와 파티션으로 분해하며 이들 중 다수는 DB 클러스터 내의 서로 다른 노드에서 병렬적으로 실행될 수 있음