Share via


.NET을 사용하여 업로드 및 다운로드에 대한 성능 튜닝

애플리케이션이 .NET용 Azure Storage 클라이언트 라이브러리를 사용하여 데이터를 전송하는 경우 속도, 메모리 사용량, 요청의 성공 또는 실패에도 영향을 줄 수 있는 몇 가지 요인이 있습니다. 데이터 전송 성능과 안정성을 극대화하려면 앱이 실행되는 환경에 따라 클라이언트 라이브러리 전송 옵션을 사전에 구성하는 것이 중요합니다.

이 문서에서는 데이터 전송 옵션을 조정하기 위한 몇 가지 고려 사항을 안내하며, 이 지침은 매개 변수로 StorageTransferOptions를 허용하는 모든 API에 적용됩니다. 제대로 조정되면 클라이언트 라이브러리는 여러 요청에 데이터를 효율적으로 분산할 수 있으므로 작업 속도, 메모리 사용량, 네트워크 안정성이 향상될 수 있습니다.

StorageTransferOptions를 사용하여 성능 조정

StorageTransferOptions의 값을 올바르게 조정하는 것은 안정적인 데이터 전송 작업 성능의 핵심입니다. 스토리지 전송은 이 구조체의 인스턴스에 정의된 속성 값에 따라 여러 하위 전송으로 분할됩니다. 지원되는 최대 전송 크기는 작업 및 서비스 버전에 따라 다르므로 설명서를 확인하여 한도를 결정해야 합니다. Blob 스토리지 전송 크기 제한에 대한 자세한 내용은 Blob 스토리지의 스케일링 대상을 참조하세요.

StorageTransferOptions의 다음 속성은 앱의 요구 사항에 따라 조정할 수 있습니다.

참고 항목

StorageTransferOptions 구조체에 nullable 값이 포함되어 있지만 클라이언트 라이브러리에서 제공되지 않은 경우 각 개별 값에 대해 기본값을 사용합니다. 이러한 기본값은 일반적으로 데이터 센터 환경에서 수행되지만 일반 소비자 환경에는 적합하지 않을 수 있습니다. StorageTransferOptions가 제대로 조정되지 않으면 작업이 지나치게 길어지고 요청 시간 제한도 발생할 수 있습니다. StorageTransferOptions에서 값을 테스트하고 애플리케이션 및 환경 요구 사항에 따라 조정하는 것이 가장 좋습니다.

InitialTransferSize

InitialTransferSize는 첫 번째 범위 요청의 크기(바이트)입니다. HTTP 범위 요청은 부분 요청이며, 이 경우 InitialTransferSize에서 정의된 크기입니다. 이 크기보다 작은 Blob은 단일 요청으로 전송됩니다. 이 크기보다 큰 Blob은 MaximumTransferSize 크기의 청크로 계속 전송됩니다.

MaximumTransferSize에 대해 지정하는 값이 InitialTransferSize에 대해 정의하는 값을 제한하지 않는다는 점에 유의해야 합니다. InitialTransferSize는 초기 요청이 전체 작업을 한 번에 수행하도록 하위 전송 없이 별도의 크기 제한을 정의합니다. InitialTransferSize적어도MaximumTransferSize에 대해 정의한 값만큼 크도록 하려는 경우가 많습니다(더 크지 않은 경우). 데이터 전송 크기에 따라 단일 요청으로 전송이 완료되고 여러 요청의 오버헤드를 방지하므로 이 방법은 더 우수한 성능을 발휘할 수 있습니다.

상황에 가장 적합한 값이 무엇인지 잘 모르는 경우 안전한 옵션은 InitialTransferSizeMaximumTransferSize에 사용되는 값과 동일한 값으로 설정하는 것입니다.

참고 항목

BlobClient 개체를 사용하는 경우 블록 배치가 아닌 Blob 배치를 사용하여 InitialTransferSize보다 작은 Blob을 업로드합니다.

MaximumConcurrency

MaximumConcurrency는 병렬 전송에 사용할 수 있는 최대 작업자 수입니다. 현재 비동기 작업만 전송을 병렬화할 수 있습니다. 동기 작업은 이 값을 무시하고 순서대로 작동합니다.

이 값의 효과는 .NET의 연결 풀 제한에 따라 달라질 수 있으며, 이는 특정 시나리오에서 기본적으로 성능을 제한할 수 있습니다. .NET의 연결 풀 제한에 대한 자세한 내용은 .NET Framework 연결 풀 제한 및 .NET용 새 Azure SDK를 참조하세요.

MaximumTransferSize

MaximumTransferSize는 최대 전송 길이(바이트)입니다. 앞에서 설명한 것처럼 이 값은 MaximumTransferSize보다 클 수 있는 InitialTransferSize를 제한하지 않습니다.

데이터를 효율적으로 이동하기 위해 클라이언트 라이브러리가 전송할 때마다 항상 MaximumTransferSize 값에 도달할 수 있는 것은 아닙니다. 작업에 따라 전송 크기에 지원되는 최대 값이 다를 수 있습니다. 예를 들어 서비스 버전이 2019-12-12 이상인 블록 배치 작업을 호출하는 블록 Blob의 최대 블록 크기는 4000MiB입니다. Blob 스토리지 전송 크기 제한에 대한 자세한 내용은 Blob 스토리지의 스케일링 대상의 차트를 참조하세요.

코드 예

클라이언트 라이브러리에는 BlobUploadOptions 매개 변수의 일부로 StorageTransferOptions 인스턴스를 허용하는 UploadUploadAsync 메서드에 대한 오버로드가 포함됩니다. BlobDownloadToOptions 매개 변수를 사용하는 DownloadToDownloadToAsync 메서드에도 유사한 오버로드가 있습니다.

다음 코드 예제에서는 StorageTransferOptions 인스턴스에 대한 값을 정의하고 이러한 구성 옵션을 UploadAsync 매개 변수로 전달하는 방법을 보여 줍니다. 이 샘플에 제공된 값은 권장 사항이 아닙니다. 이러한 값을 올바르게 조정하려면 앱의 특정 요구 사항을 고려해야 합니다.

// Specify the StorageTransferOptions
BlobUploadOptions options = new BlobUploadOptions
{
    TransferOptions = new StorageTransferOptions
    {
        // Set the maximum number of parallel transfer workers
        MaximumConcurrency = 2,

        // Set the initial transfer length to 8 MiB
        InitialTransferSize = 8 * 1024 * 1024,

        // Set the maximum length of a transfer to 4 MiB
        MaximumTransferSize = 4 * 1024 * 1024
    }
};

// Upload data from a stream
await blobClient.UploadAsync(stream, options);

이 예제에서는 MaximumConcurrency 속성을 사용하여 병렬 전송 작업자 수를 2로 설정합니다. 이 구성은 최대 2개의 연결을 동시에 열어 업로드가 병렬로 수행되도록 합니다. 초기 HTTP 범위 요청은 InitialTransferSize 속성을 통해 정의된 대로 최대 8MiB의 데이터를 업로드하려고 시도합니다. InitialTransferSize검색 가능한 스트림을 사용하는 경우에만 업로드에 적용됩니다. Blob 크기가 8MiB보다 작은 경우 작업을 완료하려면 단일 요청만 필요합니다. Blob 크기가 8MiB보다 큰 경우 모든 후속 전송 요청의 최대 크기는4MiB이며, MaximumTransferSize 속성을 사용하여 설정합니다.

업로드 성능 고려 사항

업로드하는 동안 Storage 클라이언트 라이브러리는 지정된 업로드 스트림을 StorageTransferOptions 인스턴스에서 정의된 값에 따라 여러 하위 업로드로 분할합니다. 각 하위 업로드에는 REST 작업에 대한 자체 전용 호출이 있습니다. BlobClient 개체 또는 BlockBlobClient 개체의 경우 이 작업은 블록 배치입니다. DataLakeFileClient 개체의 경우 이 작업은 데이터 추가입니다. Storage 클라이언트 라이브러리는 전송 옵션에 따라 이러한 REST 작업을 병렬로 관리하여 전체 업로드를 완료합니다.

업로드 스트림을 검색할 수 있는지 또는 검색할 수 없는지에 따라 클라이언트 라이브러리는 다음 섹션에 설명된 대로 버퍼링 및 InitialTransferSize를 다르게 처리합니다. 검색 가능한 스트림은 스트림 내에서 현재 위치 쿼리 및 수정을 지원하는 스트림입니다. .NET의 스트림에 대한 자세한 내용은 Stream 클래스 참조를 참조하세요.

참고 항목

블록 Blob의 최대 블록 수는 50,000개입니다. 블록 Blob의 최대 크기는 MaximumTransferSize의 50,000배입니다.

업로드 중 버퍼링

Storage REST 계층은 중단한 REST 업로드 작업을 선택하지 않습니다. 개별 전송은 완료되거나 손실됩니다. 검색할 수 없는 스트림 업로드에 대한 복원력을 보장하기 위해 Storage 클라이언트 라이브러리는 업로드를 시작하기 전에 각 개별 REST 호출에 대한 데이터를 버퍼링합니다. 네트워크 속도 제한 외에도 이 버퍼링 동작은 순서대로 업로드하는 경우에도 더 작은 MaximumTransferSize 값을 고려해야 하는 이유입니다. MaximumTransferSize 값을 줄이면 각 요청 및 실패한 요청의 각 재시도에서 버퍼링되는 최대 데이터 양이 줄어듭니다. 특정 크기의 데이터를 전송하는 동안 시간 제한이 자주 발생하는 경우 MaximumTransferSize 값을 줄이면 버퍼링 시간이 줄어들고 성능이 향상될 수 있습니다.

버퍼링이 발생하는 또 다른 시나리오는 병렬 REST 호출을 통해 데이터를 업로드하여 네트워크 처리량을 최대화하는 경우입니다. 클라이언트 라이브러리에는 병렬로 읽을 수 있는 원본이 필요하며 스트림은 순차적으로 진행되므로 Storage 클라이언트 라이브러리는 업로드를 시작하기 전에 각 개별 REST 호출에 대한 데이터를 버퍼링합니다. 이 버퍼링 동작은 제공된 스트림을 검색할 수 있는 경우에도 발생합니다.

비동기 업로드 호출 중에 버퍼링을 방지하려면 검색 가능한 스트림을 제공하고 MaximumConcurrency를 1로 설정해야 합니다. 대부분의 경우에서 이 전략이 통하지만, 코드에서 버퍼링이 필요한 다른 클라이언트 라이브러리 기능을 사용하는 경우에도 버퍼링이 발생할 수 있습니다.

업로드 시 InitialTransferSize

업로드를 위해 검색 가능한 스트림이 제공되면 InitialTransferSize 값 대비 스트림 길이를 확인합니다. 스트림 길이가 이 값보다 작으면 다른 StorageTransferOptions 값에 관계없이 전체 스트림이 단일 REST 호출로 업로드됩니다. 그렇지 않으면, 앞에서 설명한 대로 업로드가 여러 부분으로 수행됩니다. InitialTransferSize는 검색할 수 없는 스트림에 영향을 주지 않기 때문에 무시됩니다.

다운로드 성능 고려 사항

다운로드하는 동안 Storage 클라이언트 라이브러리는 지정된 다운로드 요청을 StorageTransferOptions 인스턴스에서 정의된 값에 따라 여러 하위 다운로드로 분할합니다. 각 하위 다운로드에는 REST 작업에 대한 자체 전용 호출이 있습니다. 전송 옵션에 따라 클라이언트 라이브러리는 이러한 REST 작업을 병렬로 관리하여 전체 다운로드를 완료합니다.

다운로드 중 버퍼링

본문 콘텐츠와 동시에 여러 HTTP 응답을 수신하면 메모리 사용에 영향을 줍니다. 그러나 Storage 클라이언트 라이브러리는 다운로드한 콘텐츠에 대한 버퍼 단계를 명시적으로 추가하지 않습니다. 들어오는 응답은 순서대로 처리됩니다. 클라이언트 라이브러리는 HTTP 응답 스트림에서 호출자가 제공한 대상 스트림 또는 파일 경로로 스트림을 복사하기 위해 16KB 버퍼를 구성합니다.

다운로드 시 InitialTransferSize

다운로드하는 동안 Storage 클라이언트 라이브러리는 다른 작업을 수행하기 전에 InitialTransferSize를 사용하여 단일 다운로드 범위 요청을 수행합니다. 이 초기 다운로드 요청 중에 클라이언트 라이브러리는 총 리소스 크기를 알 수 있습니다. 초기 요청이 모든 콘텐츠를 성공적으로 다운로드하면 작업이 완료됩니다. 그렇지 않으면, 클라이언트 라이브러리는 전체 다운로드가 완료되는 MaximumTransferSize까지 범위 요청을 계속 수행합니다.

다음 단계