샤딩

사용 가능

1.1 샤딩이란?

지속적으로 Google을 검색하면 소위 파티셔닝과 소위 샤딩 사이에 다소 모호한 경계가 있음이 밝혀졌습니다. 누구나 원하는 대로, 원하는 대로 부릅니다. 어떤 사람들은 수평 분할과 샤딩을 구별합니다. 다른 사람들은 샤딩이 일종의 수평 분할이라고 말합니다.

건국의 아버지가 승인하고 ISO에서 인증할 단일 용어 표준을 찾지 못했습니다. 개인적인 내적 신념은 다음과 같습니다. 평균적으로 분할하는 것은 임의로 취한 방식으로 "기본을 조각내는 것"입니다.

  • 세로 분할 - 열 기준. 예를 들어, 60개의 열에 20억 개의 레코드가 있는 거대한 테이블이 있습니다. 거대한 테이블 하나를 유지하는 대신 각각 20억 개의 레코드가 포함된 최소 60개의 거대한 테이블을 유지합니다. 이것은 열 기반이 아니라 수직 분할(용어의 예)입니다.
  • 수평 파티셔닝 - 서버 내부에서 한 줄씩 자릅니다.

여기서 어색한 순간은 수평 분할과 샤딩의 미묘한 차이입니다. 나는 조각으로 잘릴 수 있지만 그것이 무엇인지 확실히 말할 수는 없습니다. 샤딩과 수평 파티셔닝이 거의 같은 것이라는 느낌이 있습니다.

샤딩은 일반적으로 데이터베이스 또는 문서, 객체의 프로콜렉션 측면에서 큰 테이블이 데이터베이스가 없지만 문서 저장소가 객체에 의해 정확하게 절단되는 경우입니다. 즉, 20억 개의 개체 중에서 크기에 관계없이 조각을 선택합니다. 각 개체 내부의 개체 자체는 조각으로 잘리지 않으며 별도의 열에 배치하지 않습니다. 즉, 다른 위치에 배치로 배치합니다.

미묘한 용어 차이가 있습니다. 예를 들어 상대적으로 Postgres 개발자는 수평 파티셔닝이 기본 테이블이 분할된 모든 테이블이 동일한 스키마에 있는 경우이고 다른 시스템에 있는 경우 이미 샤딩이라고 말할 수 있습니다.

일반적으로 특정 데이터베이스 및 특정 데이터 관리 시스템의 용어에 얽매이지 않고 샤딩은 라인별로 / 문서 별로 조각화 하는 것 등의 느낌이 있습니다 .

나는 전형적인 것을 강조한다. 우리가 이 모든 작업을 수행하는 이유는 20억 개의 문서를 각각 더 관리하기 쉬운 20개의 테이블로 자르는 것이 아니라 많은 코어, 많은 디스크 또는 여러 물리적 또는 가상 서버에 배포하기 위해서입니다.

1.2 불가분의 분할

이렇게 하면 각 샤드(각 데이터 조각)가 여러 번 복제됩니다. 하지만 정말 아닙니다.

INSERT INTO docs00 
SELECT * FROM documents WHERE (id%16)=0 
... 
 
INSERT INTO docs15 
SELECT * FROM documents WHERE (id%16)=15 

실제로 이러한 데이터 분할을 수행하고 용감한 노트북의 MySQL에 있는 하나의 거대한 SQL 테이블에서 하나의 노트북, 단일 스키마, 단일 데이터베이스 등을 넘지 않고 16개의 작은 테이블을 생성하게 됩니다. . 등등. - 그게 다야, 이미 샤딩이 있습니다.

결과는 다음과 같습니다.

  • 대역폭이 증가합니다.
  • 대기 시간은 변경되지 않습니다. 즉, 이 경우 작업자 또는 소비자는 각각 자신의 것을 얻습니다. 서로 다른 요청이 거의 동시에 처리됩니다.
  • 또는 둘 다, 다른 것, 또한 고가용성(복제).

왜 대역폭인가? 우리는 때때로 적합하지 않은 그러한 양의 데이터를 가질 수 있습니다 - 어디에 있는지는 명확하지 않지만 적합하지 않습니다 - on 1 {kernel | 디스크 | 서버 | ...}. 리소스가 충분하지 않습니다. 이 큰 데이터 세트로 작업하려면 잘라야 합니다.

대기 시간이 필요한 이유는 무엇입니까? 하나의 코어에서 20억 행의 테이블을 스캔하는 것은 20개의 코어에서 20개의 테이블을 병렬로 스캔하는 것보다 20배 느립니다. 데이터가 단일 리소스에서 너무 느리게 처리됩니다.

왜 고가용성입니까? 또는 두 가지 작업을 동시에 수행하기 위해 데이터를 자르고 각 샤드의 여러 복사본을 동시에 수행합니다. 복제는 고가용성을 보장합니다.

1.3 "손으로 하는 방법"의 간단한 예

조건부 샤딩은 32개 문서에 대한 테스트 테이블 test.documents를 사용하고 이 테이블에서 16개의 테스트 테이블(각 test.docs00, 01, 02, ..., 15 문서 2개)을 생성하여 잘라낼 수 있습니다.

INSERT INTO docs00 
SELECT * FROM documents WHERE (id%16)=0 
... 
 
INSERT INTO docs15 
SELECT * FROM documents WHERE (id%16)=15 

왜? 선험적으로 우리는 id가 어떻게 배포되는지 알지 못하기 때문에 1에서 32까지 포함하면 각각 정확히 2개의 문서가 있을 것이고 그렇지 않으면 그렇지 않을 것입니다.

우리는 왜 여기에서 그것을 합니다. 16개의 테이블을 만든 후에 필요한 것 중 16개를 "잡을" 수 있습니다. 우리가 적중한 것과 관계없이 이러한 리소스를 병렬화할 수 있습니다. 예를 들어 디스크 공간이 충분하지 않은 경우 이러한 테이블을 별도의 디스크에 분해하는 것이 좋습니다.

불행히도 이 모든 것은 무료가 아닙니다. 정식 SQL 표준의 경우(오랫동안 SQL 표준을 다시 읽지 않았거나 오랫동안 업데이트되지 않았을 수 있음) SQL 서버에 말할 공식 표준화된 구문이 없다고 생각합니다. : "친애하는 SQL 서버여, 32개의 샤드를 만들어 4개의 디스크로 나눕니다. 그러나 개별 구현에는 기본적으로 동일한 작업을 수행하기 위한 특정 구문이 있는 경우가 많습니다. PostgreSQL에는 파티셔닝 메커니즘이 있고, MySQL에는 MariaDB가 있으며, Oracle은 아마도 오래 전에 이 모든 작업을 수행했을 것입니다.

그럼에도 불구하고 데이터베이스 지원 없이 표준 프레임워크 내에서 수작업으로 수행하는 경우 데이터 액세스의 복잡성으로 조건부로 비용을 지불합니다 . 간단한 SELECT * FROM 문서 WHERE id=123이 있던 곳에서 이제 16 x SELECT * FROM docsXX. 키로 레코드를 얻으려고 하면 좋습니다. 초기 범위의 레코드를 얻으려고 한다면 훨씬 더 흥미로울 것입니다. 이제 (우리가 바보이고 표준의 틀 안에 남아 있다고 강조한다면) 이러한 16 SELECT * FROM의 결과는 응용 프로그램에서 결합되어야 합니다.

어떤 성능 변화를 기대할 수 있습니까?

  • 직관적으로 - 선형.
  • 이론적으로 - Amdahl 법칙 때문에 하위 선형입니다.
  • 실질적으로 거의 선형일 수도 있고 아닐 수도 있습니다.

사실 정답은 알 수 없습니다. 샤딩 기술을 영리하게 적용하면 애플리케이션 성능에서 상당한 초선형 저하를 달성할 수 있으며 DBA도 열광적인 포커를 하게 될 것입니다.

이것이 어떻게 달성될 수 있는지 봅시다. 설정을 PostgreSQL shards=16으로 설정한 다음 저절로 이륙하는 것은 흥미롭지 않습니다. 샤딩 속도를 16배, 32배로 늦추는 방법에 대해 생각해 봅시다. 이렇게 하지 않는 방법의 관점에서 보면 흥미롭습니다.

속도를 높이거나 낮추려는 우리의 시도는 항상 고전적인 것, 즉 요청의 완벽한 병렬화는 없으며 항상 일관된 부분이 있다는 좋은 오래된 Amdahl 법칙에 부딪힐 것입니다.

1.4 암달 법칙

항상 직렬화된 부분이 있습니다.

쿼리 실행에는 항상 병렬화된 부분이 있고 항상 병렬화되지 않은 부분이 있습니다. 완벽하게 병렬 쿼리인 것처럼 보이더라도 적어도 각 샤드에서 받은 행에서 클라이언트로 보낼 결과 행의 컬렉션은 항상 존재하며 항상 순차적입니다.

항상 일관된 부분이 있습니다. 그것은 작을 수 있고 일반적인 배경에 대해 완전히 보이지 않을 수 있으며 거대 할 수 있으므로 병렬화에 큰 영향을 미치지 만 항상 존재합니다.

또한 그 영향력은 변화하고 있으며 크게 성장할 수 있습니다. 예를 들어 테이블을 64개 레코드에서 4개 레코드의 16개 테이블로 잘라내면 이 부분이 변경됩니다. 물론 엄청난 양의 데이터로 판단할 때 우리는 휴대폰과 2MHz 86 프로세서를 작업하고 있으며 동시에 열어 둘 수 있는 파일이 충분하지 않습니다. 분명히 이러한 입력을 사용하여 한 번에 하나의 파일을 엽니다.

  • Total = Serial + Parallel 이었습니다 . 예를 들어 병렬은 DB 내부의 모든 작업이고 직렬은 결과를 클라이언트로 보내는 것입니다.
  • Total2 = Serial + Parallel/N + Xserial이 되었습니다 . 예를 들어, 전체 ORDER BY, Xserial>0인 경우.

이 간단한 예를 통해 일부 Xserial이 나타나는 것을 보여주려고 합니다. 항상 직렬화된 부분이 있고 데이터를 병렬로 작업하려고 한다는 사실 외에도 이 데이터 슬라이싱을 제공하는 추가 부분이 있습니다. 대략적으로 말하면 다음이 필요할 수 있습니다.

  • 데이터베이스의 내부 사전에서 이 16개 테이블을 찾으십시오.
  • 열린 파일;
  • 메모리 할당;
  • 메모리 할당 해제;
  • 병합 결과;
  • 코어 간 동기화.

일부 동기화되지 않은 효과가 여전히 나타납니다. 그것들은 중요하지 않고 총 시간의 10억분의 1을 차지할 수 있지만 항상 0이 아니며 항상 거기에 있습니다. 그들의 도움으로 샤딩 후 성능이 크게 저하될 수 있습니다.

이것은 Amdahl의 법칙에 대한 표준 그림입니다. 여기서 중요한 것은 이상적으로는 직선이어야 하고 선형으로 성장해야 하는 선이 점근선에 도달한다는 것입니다. 그러나 인터넷의 그래프를 읽을 수 없기 때문에 제 생각에는 숫자가 있는 더 많은 시각적 테이블을 만들었습니다.

5%만 차지하는 요청 처리의 일부 직렬화된 부분이 있다고 가정해 보겠습니다: serial = 0.05 = 1 / 20 .

직관적으로 보면 요청 처리의 1/20만 차지하는 직렬화 부분으로 20코어에 대한 요청 처리를 병렬화하면 약 20배, 최악의 경우 18배 빨라질 것 같다.

사실 수학은 무자비한 것입니다 .

벽 = 0.05 + 0.95/num_cores, 속도 증가 = 1 / (0.05 + 0.95/num_cores)

조심스럽게 계산하면 직렬화된 부분을 5%로 하면 속도가 10배(10.3) 증가하여 이론적 이상에 비해 51% 증가하는 것으로 나타났습니다.

8코어 = 5.9 = 74%
10코어 = 6.9 = 69%
20코어 = 10.3 = 51%
40코어 = 13.6 = 34%
128코어 = 17.4 = 14%

작업에 사용했던 작업에 20개의 코어(원하는 경우 디스크 20개)를 사용하면 이론적으로는 20배 이상의 가속도를 얻을 수 없지만 실제로는 훨씬 적습니다. 또한, 병렬 수가 증가함에 따라 비효율성이 크게 증가합니다.

직렬화 작업의 1%만 남아 있고 99%가 병렬화되면 속도 향상 값이 다소 향상됩니다.

8코어 = 7.5 = 93%
16코어 = 13.9 = 87%
32코어 = 24.4 = 76%
64코어 = 39.3 = 61%

자연적으로 완료하는 데 몇 시간이 걸리는 완벽한 열핵 쿼리와 결과의 준비 작업 및 조립에 거의 시간이 걸리지 않는 경우(직렬 = 0.001), 우리는 이미 좋은 효율성을 볼 수 있습니다.

8코어 = 7.94 = 99%
16코어 = 15.76 = 99%
32코어 = 31.04 = 97%
64코어 = 60.20 = 94%

우리는 결코 100%를 볼 수 없다는 점에 유의하십시오 . 특히 좋은 경우 예를 들어 99.999%를 볼 수 있지만 정확히 100%는 아닙니다.

코멘트
  • 인기
  • 신규
  • 이전
코멘트를 남기려면 로그인 해야 합니다
이 페이지에는 아직 코멘트가 없습니다