이 페이지에서는 대용량 데이터를 Spanner에 효율적으로 일괄 로드하기 위한 가이드라인을 설명합니다.
다음과 같은 여러 가지 방법으로 데이터를 Spanner에 일괄 로드할 수 있습니다.
- DML(Data Manipulation Language)을 사용하여 행을 삽입
- 변형을 사용하여 행 삽입
- Dataflow 커넥터를 사용하여 데이터 가져오기
- Avro 파일을 사용하여 데이터베이스 가져오기
- 데이터를 CSV 형식으로 가져오기
Google Cloud CLI를 사용하여 행을 삽입할 수도 있지만 일괄 로드에는 gcloud CLI를 사용하지 않는 것이 좋습니다.
일괄 로드 성능 가이드라인
최적의 일괄 로드 성능을 얻으려면 파티션 나누기를 최대한 사용하여 작업자 태스크에 데이터 쓰기를 분산합니다.
Spanner는 부하 기반 분할을 사용해서 인스턴스의 컴퓨팅 리소스에 데이터 부하를 균등하게 분배합니다. 몇 분간 부하가 높으면 Spanner는 행 사이에 분할 경계를 적용합니다. 일반적으로 데이터 부하가 잘 분산되어 있고 스키마 설계 및 일괄 로드 권장사항을 따르면 인스턴스에서 사용 가능한 CPU 리소스가 포화될 때까지 쓰기 처리량은 몇 분마다 두 배씩 증가합니다.
기본 키로 데이터 파티션 나누기
Spanner는 테이블을 더 작은 범위로 동적으로 분할합니다. 행의 기본 키는 파티션의 위치를 결정합니다.
일괄 로드 쓰기 처리량을 최적화하려면 다음 패턴을 사용하여 기본 키로 데이터 파티션을 나눕니다.
- 각 파티션에는 키 열에 지정된 연속 행 범위가 있습니다.
- 각 커밋에는 단일 파티션의 데이터만 있습니다.
파티션 수는 Spanner 인스턴스에 있는 노드 수의 10배가 되도록 하는 것이 좋습니다. 행을 파티션에 할당하려면 다음을 수행합니다.
- 기본 키로 데이터를 정렬합니다.
- 데이터를 10 * (노드 수)개의 크기가 동일한 개별 파티션으로 나눕니다.
- 개별 작업자 태스크를 만들어 각 파티션에 할당합니다. 애플리케이션에서 작업자 태스크를 만들 수 있으나 Spanner 기능은 아닙니다.
이 패턴을 따르면 대용량 부하의 전체 일괄 쓰기 처리량은 노드당 최대 10~20MB/초가 됩니다.
데이터를 로드하면 Spanner는 분할을 만들고 업데이트하여 인스턴스의 노드 부하를 분산합니다. 이 프로세스 중에 처리량이 일시적으로 감소할 수 있습니다.
예
노드가 3개 있는 리전 구성이 있습니다. 인터리브 처리되지 않은 테이블에 행이 90,000개 있습니다. 테이블의 기본 키 범위는 1~90000입니다.
- 행: 90,000개 행
- 노드: 3
- 파티션: 10 * 3 = 30개
- 파티션당 행 수: 90000 / 30 = 3000개
첫 번째 파티션의 키 범위는 1~3000입니다. 두 번째 파티션의 키 범위는 3001~6000입니다. 30번째 파티션의 키 범위는 87001~90000입니다. (대형 테이블에 순차 키를 사용해서는 안 됩니다. 이 예는 데모용입니다.)
각 작업자 태스크는 단일 파티션의 쓰기를 보냅니다. 각 파티션 내에서는 기본 키를 기준으로 행을 순차적으로 써야 합니다. 또한 기본 키를 기준으로 임의로 행을 쓰면 합당하게 높은 처리량이 제공됩니다. 측정 테스트를 실행하면 데이터 세트에 최고의 성능을 제공하는 방법을 확인할 수 있습니다.
파티션을 사용하지 않기로 결정한 경우
커밋 내에서 임의의 행 쓰기는 커밋에 연속된 행 집합을 작성하는 것보다 느릴 수 있으며 다른 파티션의 데이터를 터치하는 경우가 많습니다. 커밋에 더 많은 분할이 기록되면 서버 간 조정 증가로 인해 커밋 지연 시간과 오버헤드가 증가합니다. 임의의 각 행이 다른 분할에 속하여 여러 분할이 관련될 수 있습니다. 최악의 경우 각 쓰기에 Spanner 인스턴스의 모든 분할이 관련될 수 있습니다. 위에서 언급한 대로 분할 처리량이 많을수록 쓰기 처리량이 줄어듭니다.
파티션 나누기 없이 일괄 로드
커밋에 연속된 행 집합을 쓰는 것이 무작위 행을 쓰는 것보다 빠를 수 있습니다. 임의의 행에는 서로 다른 파티션의 데이터도 포함될 수 있습니다.
커밋에 더 많은 파티션이 기록되면 서버 간의 조정이 더 많이 필요하므로 커밋 지연 시간과 오버헤드가 증가합니다.
임의의 각 행이 다른 파티션에 속할 수 있으므로 여러 파티션이 관련될 수 있습니다. 최악의 경우 각 쓰기에 Spanner 인스턴스의 모든 파티션이 포함됩니다. 위에서 언급한 대로 파티션이 더 많이 포함되면 쓰기 처리량이 줄어듭니다.
과부하 방지
Spanner에서 처리할 수 있는 요청보다 더 많은 쓰기 요청을 보낼 수 있습니다. 이러한 경우 Spanner는 트랜잭션을 취소하여 과부하를 처리하며, 이를 푸시백이라고 합니다. 쓰기 전용 트랜잭션에서는 Spanner가 자동으로 트랜잭션을 다시 시도합니다. 이 경우 푸시백으로 인해 지연 시간이 증가합니다. 부하가 높으면 푸시백이 최대 1분까지 지속될 수 있습니다. 부하가 심각하게 높으면 푸시백이 몇 분 동안 지속될 수 있습니다. 푸시백을 방지하려면 쓰기 요청을 제한하여 CPU 사용률을 적당한 한도 이내로 유지시켜야 합니다. 또는 CPU 사용률이 한도를 초과하지 않도록 노드 수를 늘릴 수 있습니다.
한 번에 1~5MB의 변형 커밋
쓰기 양에 관계없이 Spanner에 대한 각 쓰기에는 약간의 오버헤드가 있습니다. 처리량을 극대화하려면 쓰기당 저장되는 데이터 양을 극대화합니다. 쓰기 용량이 커질수록 쓰기당 오버헤드 비율이 낮아집니다. 각 커밋에 수백 개의 행을 변형하는 것이 좋습니다. 일반적으로 용량이 상대적으로 큰 행을 쓰는 경우 커밋 크기가 1~5MB일 때 최고의 성능이 발휘됩니다. 작은 값이나 색인이 생성된 값을 쓸 때는 일반적으로 단일 커밋에서 최대 수백 개의 행을 쓰는 것이 가장 좋습니다. 커밋 크기 및 행 수와는 별개로 커밋당 변형 수는 80,000개로 제한됩니다. 최적의 성능을 확인하려면 처리량을 테스트하고 측정해야 합니다.
커밋 크기가 5MB보다 크거나 행이 수백 개 이상이면 추가 이점이 없으며, 커밋 크기 및 커밋당 변형 수에 대한 Spanner 제한을 초과할 수 있습니다.
보조 색인 가이드라인
데이터베이스에 보조 색인이 있으면 테이블 데이터를 로드하기 전/후 중에서 데이터베이스 스키마에 색인을 추가할 시기를 선택해야 합니다.
데이터가 로드되기 전에 색인을 추가하면 스키마 변경을 즉시 완료할 수 있습니다. 그러나 색인 업데이트도 필요하기 때문에 색인에 영향을 주는 각 쓰기 작업이 더 오래 걸립니다. 데이터 로드가 완료되면 배치된 모든 색인에 데이터베이스가 즉시 사용 가능하게 됩니다. 테이블과 테이블 색인을 동시에 만들려면 새 테이블과 새 색인에 대한 DDL 문을 Spanner에 단일 요청으로 전송합니다.
데이터 로드 후 색인을 추가하면 각 쓰기가 효율적으로 처리됩니다. 하지만 각 색인 백필에 대한 스키마 변경에 시간이 오래 걸릴 수 있습니다. 데이터베이스를 완전히 사용할 수 없으며 모든 스키마 변경이 완료되기 전에는 쿼리가 색인을 사용할 수 없습니다. 데이터베이스는 여전히 쓰기와 쿼리를 제공할 수 있지만 속도가 느립니다.
데이터를 로드하기 전에 비즈니스 애플리케이션에 중요한 색인을 추가하는 것이 좋습니다. 중요하지 않은 모든 색인은 데이터가 마이그레이션된 후에 추가합니다.
처리량 테스트 및 측정
처리량을 예측하기 어려울 수 있습니다. 최종 로드를 실행하기 전에 일괄 로드 계획을 테스트하는 것이 좋습니다. 파티션 나누기 및 성능 모니터링을 사용하는 자세한 예는 데이터 부하 처리량 극대화를 참조하세요.
기존 데이터베이스에 정기적으로 일괄 로드할 때의 권장사항
이러한 권장사항은 데이터는 있지만 보조 색인이 없는 기존 데이터베이스를 업데이트할 때에도 계속 적용됩니다.
보조 색인이 있는 경우에도 이 안내를 따르면 합당한 성능을 얻을 수 있습니다. 성능은 트랜잭션에서 평균적으로 얼마나 많은 분할이 관련되는지에 따라 달라집니다. 처리량이 너무 감소하면 다음을 시도해 보세요.
- 각 커밋에 포함된 변형 수를 줄이면 처리량이 증가할 수 있습니다.
- 업로드 크기가 업데이트 중인 테이블의 현재 전체 크기보다 큰 경우, 보조 색인을 삭제하고 데이터를 업로드한 후 보조 색인을 다시 추가합니다. 일반적으로 이 단계는 필요하지 않지만 처리량을 향상시킬 수 있습니다.