6. Partitioning

데이터를 파티셔닝(샤딩)하는 것은 데이터를 여러 저장소에 분산 배치하여 각 데이터가 하나의 파티션에 속하도록 하는 것이다. 이의 주 목적은 확장성이다. 각 노드는 자체 파티션에 대해 쿼리를 수행할 수 있으므로 노드를 추가하면 쿼리 대역폭이 높아진다. 이는 1980년대부터 도입되었다. 파티셔닝에 대한 여러 접근법들을 알아보자.

Partitioning and Replication

파티셔닝은 복제와 결합해 각 파티션이 복수의 노드에 속하도록 할 수도 있다. 각 노드는 복수의 파티션을 저장할 수 있다. 데이터베이스의 복제에 적용되는 이론들은 파티션의 복제에 적용 가능하다.

Partitioning of Key-Value Data

어떤 기록을 어떤 노드에 담아야 할지는 어떻게 결정할까? 파티셔닝의 목적은 데이터와 쿼리 부하를 노드에 균일하게 분배하는 것이다. 이 분배가 불균형적이면 파티셔닝의 효율이 적어진다. 이를 피하는 가장 간단한 방법은 노드에 기록을 무작위로 분배하는 것이지만 어떤 노드가 특정 기록을 갖고 있는지 모르게 된다. 대신에 키의 범위를 이용할 수 있다.

Partitioning by Key Range

파티셔닝의 한 방법은 연속된 범위의 키를 각 파티션에 할당하는 것이다. 이 범위는 동등하게 부여될 필요는 없다. 파티션 경계는 데이터베이스가 자동적으로 결정할 수도 있고 관리자가 수동으로 결정할 수도 있다. 각 파티션 내에서 키는 정렬된 순서로 저장해야 한다. 이것의 단점은 어떤 접근 패턴은 핫 스팟을 불러일으킨다는 것이다. 민감한 데이터베이스에서 이를 피하기 위해서는 키의 첫 번째 원소로 타임스탬프 이외의 것을 사용해야 한다.

Partitioning by Hash of Key

불균형과 핫스팟 문제를 피하기 위해 많은 분산형 데이터베이스는 키의 파티션을 결정하기 위해 해시 함수를 사용한다. 좋은 해시 함수는 불균형한 데이터를 균등 분포하게 만들 수 있다. 파티션할 때 쓰이는 해시 함수는 암호학적으로 강해야 할 필요는 없다. 키에 대해 적당한 해시 함수를 찾았다면 각 파티션에 해시의 범위를 부여하면 된다. 이는 상당히 좋은 성능을 낸다. 하지만 키의 범위 쿼리를 수행하는 데는 비효율적이 된다. 그래서 두 가지 방법을 복합하는 방법도 있다. 이는 단일-다수 관계에 대한 좋은 데이터 모델이 된다.

Skewed Workloads and Relieving Hot Spots

키를 해싱해 파티션을 하는 것은 핫 스팟을 줄이지만 완전히 피할 순 없다. 같은 키에 쿼리가 몰리는 경우가 있기 때문이다. 데이터 시스템에서 이를 대처하는 건 어려우므로 애플리케이션에서 대처해야 한다. 같은 키를 여러 키로 쪼갤 수도 있지만 어떤 키가 쪼개지는지를 추적해야 한다. 미래에는 이 문제에 데이터베이스가 대처할 수 있게 될지도 모른다.

Partitioning and Secondary Indexes

지금까지 다룬 파티셔닝은 키-값 데이터 모델에 의존한다. 이차 인덱스가 포함되면 문제는 더 복잡해진다. 이는 관계형 데이터베이스에는 흔하고 문서형 데이터베이스에서도 그렇다. 이의 문제는 파티션하기 어려워진다는 점이다.

Partitioning Secondary Indexes by Document

문서 ID로 데이터베이스를 파티셔닝하는 예를 알아보자. 사용자가 이차 인덱스로 쿼리를 하면 어떻게 될까? 이 경우 여러 파티션에 쿼리해서 가져오는 데이터가 분산된다. 같은 이차 인덱스의 행이 같은 파티션에 있다는 보장이 없기 때문이다. 그래서 모든 파티션에 쿼리를 보낸 뒤 이 결과를 모아야 한다.

Partitioning Secondary Indexes by Term

각 파티션이 고유의 이차 인덱스를 가지는 대신 모든 파티션의 데이터를 커버하는 전역 인덱스를 가질 수 있다. 이 전역 인덱스 또한 파티션되어야 한다. 이를 항-파티션이라 한다. 이 파티션은 항 자체로 또는 항의 해시로 할 수 있다. 이의 장점은 읽기가 더 효율적이 된다는 것이다. 단 쓰기 시에는 모든 파티션에 대한 분산 트랜잭션이 요구된다. 실제로 전역 이차 인덱스에 대한 업데이트는 대개 비동기적이다. 어떤 데이터베이스에서는 로컬 인덱싱과 전역 인덱싱을 선택할 수 있다.

Rebalancing Partitions

데이터베이스는 시간에 따라 변화한다. 이 과정에서 데이터가 재균형되기도 한다. 재균형 중 데이터베이스 작동이 중단되어서는 안 되며, 클러스터 노드간 부하가 균형이 맞춰져야 하고, 필요 없는 데이터 이동이 발생해서는 안 된다.

Strategies for Rebalancing

재균형의 전략을 알아보자.

How not to do it: hash mod N

해시의 모드값을 사용할 수도 있다. 쉬워 보이지만 이렇게 해서는 안 된다. 불필요한 이동이 너무 많아지기 때문이다.

Fixed number of partitions

간단한 해결책은 노드보다 많은 파티션 수를 만들고 각 노드에 여러 파티션을 부여하는 것이다. 노드가 추가되면 새 노드는 각 노드로부터 파티션을 훔쳐올 수 있다. 이 때 노드간 완전한 파티션만 이동한다. 이론적으론 클러스터 내 매칭되지 못한 하드웨어를 처리할 수도 있다. 이 때 대개 파티션의 수는 고정되어 있다. 데이터셋의 전체 크기가 크게 가변적일 때는 파티션의 적절한 수를 결정하기는 어렵다.

Dynamic partitioning

키 범위 파티셔닝을 사용하는 데이터베이스에서 고정 경계의 고정 수 파티셔닝은 매우 불편하다. 이 때문에 파티션을 동적으로 구성할 수도 있다. 이 경우 파티션이 분할되면 그 절반이 다른 노드로 이동되어 균형을 맞춘다. 동적 파티셔닝의 이점은 파티션의 수가 전체 데이터 크기에 적응할 수 있다는 것이다. 주의할 점은 빈 데이터베이스는 단일 파티션에서 시작하므로 파티션 경계를 정할 사전 정보가 없다는 것이다. 동적 파티셔닝은 키 범위 파티션 데이터뿐만 아니라 해시 파티션 데이터에 쓰기도 좋다.

Partitioning proportionally to nodes

파티션의 수를 고정으로 할 수도 있고 동적으로 할 수도 있다. 아니면 파티션의 수를 노드의 수에 비례하도록 할 수도 있다. 새 노드가 클러스터에 추가되면 존재하는 파티션 수 중 일부를 쪼개 그 반을 가져간다. 파티션 경계를 정하기 위해서는 해시 기반 파티션을 써야 한다.

Operations: Automatic and Manual Rebalancing

재균형이 수동적으로 아니면 자동적으로 이루어져야 하나? 이에 대한 트레이드오프가 존재한다. 완전 자동 재균형은 편리하지만 예측하기 어렵다. 이는 자동 고장 감지와 결합되면 예측되지 못한 성능 저하나 고장을 일으킬 수 있다. 그래서 재균형에는 사람이 참가하는 것이 좋다.

Request Routing

클라이언트가 요청을 하면 어떤 노드로 연결시킬지는 어떻게 알까? 이는 서비스 발견이라 불리며 데이터베이스로 한정되지는 않는다. 여러 방법이 있는데 클라이언트가 아무 노드에나 연결하게 하는 것, 라우팅 티어에 연결시키고 이로부터 분산시키는 것, 클라이언트에게 직접 파티셔닝을 공지하고 선택하게 하는 것 등이 있다. 어떤 경우든 핵심 문제는 컴포넌트가 라우팅을 어떻게 하느냐이다. 이는 까다로운 문제이다. 많은 분산형 데이터 시스템은 독립된 조정 서비스를 이용해 이 클러스터 메타데이터를 추적한다. 이의 예로는 설정 서비스, 가십 프로토콜, 목시 등이 있다. 클라이언트는 여전히 IP 주소가 필요하지만 이는 자주 바뀌지는 않기 때문에 DNS로 충분하다.

Parallel Query Execution

지금까지는 단일 키를 읽고 쓰는 쿼리에 대해 알아보았다. 대용량 병렬 프로세싱 관계형 데이터베이스에서는 쿼리들이 더 복잡하다. 이에 대한 빠른 병렬 실행은 별개의 복잡한 토픽이다.

Summary

이 장에서는 큰 데이터셋을 작은 부분집합으로 파티셔닝하는 다른 방법들을 알아보았다. 파티셔닝은 저장할 데이터가 많아서 단일 기기에서 이를 처리하는 것이 불가능할 때 필요해진다. 파티셔닝의 목적은 데이터와 쿼리 부하를 복수의 기기에 균등하게 분산하여 핫 스팟 (불균형적으로 과부하가 걸린 노드)를 피하는 것이다. 이는 데이터에 적합한 파티셔닝 기법을 선택하는 것이 필요하며 클러스터에 노드가 추가되거나 삭제되었을 때 파티션간 재분배가 필요하다. 파티셔닝에는 두 가지 주된 전략이 있다:

  • 키 범위 파티셔닝. 키가 정렬되고 파티션은 키의 어떤 최소값에서 어떤 최대값까지를 담는다. 정렬은 효율적인 범위 쿼리가 가능하다는 장점이 있으나 애플리케이션이 정렬된 순서로 되어 있는 가까운 키들에 접근하는 경우가 많다면 핫 스팟의 위험성이 있다. 이 접근법에서, 파티션은 파티션이 너무 커진다면 범위를 두 개의 부분 범위로 분할해 동적으로 재분배된다.
  • 해시 파티셔닝. 키에 대해 해시 함수가 적용되고 파티션은 해시값의 범위를 갖는다. 이 방식은 키의 순서화를 깨서 범위 쿼리를 비효율적으로 만드나 부하 분산을 더 균형적으로 할 수 있다. 해시 기반 파티셔닝을 할 때에는 고정 수의 파티션을 미리 만들어놓는 것이 좋다. 이후 각 노드에 여러 파티션을 부여하고 노드가 추가되거나 삭제될 때에는 한 노드로부터 전체 파티션을 다른 노드로 이동시킨다. 동적 파티션 또한 사용 가능하다.

혼합된 접근법 또한 가능하다. 예를 들면 키의 일부분은 파티션을 식별하고 다른 부분은 순서를 정렬하는 복합 키를 쓰는 것. 파티셔닝과 이차 인덱스간 상호 작용도 알아보았다. 이차 인덱스 또한 파티셔닝되어야 하며, 두 가지 방법이 있다:

  • 문서 파티션 인덱스 (로컬 인덱스). 이차 인덱스가 일차 키나 값처럼 같은 파티션에 저장된다. 쓰기 시에는 한 파티션만 업데이트되면 되지만 이차 인덱스에 대한 읽기는 모든 파티션에 대한 분산/모으기를 요구한다.
  • 항목 파티션 인덱스 (전역 인덱스). 이차 인덱스가 인덱스 값을 이용해 독립적으로 파티션된다. 이차 인덱스의 엔트리는 일차 키의 모든 파티션의 기록을 담을 수 있다. 문서가 쓰여지면 이차 인덱스 내 여러 파티션이 업데이트되어야 한다. 하지만 읽기는 단일 파티션에 대해서 수행될 수 있다.

마지막으로, 쿼리를 적절한 파티션으로 라우팅하는 기법들을 알아보았다. 이에는 단순한 파티션 인지 부하 분산으로부터 복잡한 병렬 쿼리 실행 엔진까지 다양하다. 설계상으로, 모든 파티션은 거의 독립적으로 작동된다. 이것이 파티션된 데이터베이스가 복수의 기기로 확장될 수 있게 한다. 하지만 여러 파티션에 대한 쓰기는 더 복잡해진다. 한 파티션에 대한 쓰기가 성공하고 다른 파티션에 대한 쓰기가 실패하면 어떻게 될까? 이에 대해선 다음 챕터들에서 다룬다.

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중