Dostrajanie wydajności przekazywania i pobierania za pomocą platformy .NET

Gdy aplikacja przesyła dane przy użyciu biblioteki klienta usługi Azure Storage dla platformy .NET, istnieje kilka czynników, które mogą mieć wpływ na szybkość, użycie pamięci, a nawet powodzenie lub niepowodzenie żądania. Aby zmaksymalizować wydajność i niezawodność transferów danych, ważne jest, aby aktywnie konfigurować opcje transferu biblioteki klienta w oparciu o środowisko, w których działa aplikacja.

W tym artykule przedstawiono kilka zagadnień dotyczących dostrajania opcji transferu danych, a wskazówki dotyczą dowolnego interfejsu API, który akceptuje StorageTransferOptions jako parametr. Odpowiednio dostrojona biblioteka klienta może efektywnie dystrybuować dane między wieloma żądaniami, co może spowodować zwiększenie szybkości działania, użycia pamięci i stabilności sieci.

Dostrajanie wydajności za pomocą polecenia StorageTransferOptions

Prawidłowe dostrajanie wartości w usłudze StorageTransferOptions jest kluczem do niezawodnej wydajności operacji transferu danych. Transfery magazynu są podzielone na kilka podtransferów na podstawie wartości właściwości zdefiniowanych w wystąpieniu tej struktury. Maksymalny obsługiwany rozmiar transferu różni się w zależności od wersji operacji i usługi, dlatego zapoznaj się z dokumentacją, aby określić limity. Aby uzyskać więcej informacji na temat limitów rozmiaru transferu dla usługi Blob Storage, zobacz Skalowanie obiektów docelowych dla usługi Blob Storage.

Na podstawie potrzeb aplikacji można dostroić StorageTransferOptions następujące właściwości:

Uwaga

StorageTransferOptions Chociaż struktura zawiera wartości dopuszczane wartości null, biblioteki klienckie będą używać wartości domyślnych dla każdej pojedynczej wartości, jeśli nie zostanie podana. Te wartości domyślne są zwykle wykonywane w środowisku centrum danych, ale prawdopodobnie nie będą odpowiednie dla środowisk użytkownika domowego. Źle dostrojone StorageTransferOptions może spowodować zbyt długie operacje, a nawet przekroczenie limitu czasu żądania. Najlepiej proaktywnie testować wartości w StorageTransferOptionsprogramie i dostrajać je na podstawie potrzeb aplikacji i środowiska.

InitialTransferSize

InitialTransferSize to rozmiar pierwszego żądania zakresu w bajtach. Żądanie zakresu HTTP jest żądaniem częściowym z rozmiarem zdefiniowanym InitialTransferSize w tym przypadku. Obiekty blob mniejsze niż ten rozmiar są przenoszone w jednym żądaniu. Obiekty blob większe niż ten rozmiar nadal są przenoszone we fragmentach o rozmiarze MaximumTransferSize.

Należy pamiętać, że określona MaximumTransferSizewartość nie ogranicza wartości zdefiniowanej dla elementu InitialTransferSize. InitialTransferSize Definiuje oddzielne ograniczenie rozmiaru dla początkowego żądania do wykonania całej operacji jednocześnie bez podtransferów. Często zdarza się, że chcesz InitialTransferSize być co najmniej tak duża, jak wartość zdefiniowana dla MaximumTransferSizeparametru , jeśli nie jest większa. W zależności od rozmiaru transferu danych takie podejście może być bardziej wydajne, ponieważ transfer jest wykonywany przy użyciu jednego żądania i pozwala uniknąć narzutów na wiele żądań.

Jeśli nie masz pewności, jaka wartość jest najlepsza dla twojej sytuacji, bezpieczna opcja to ustawienie InitialTransferSize tej samej wartości używanej dla elementu MaximumTransferSize.

Uwaga

W przypadku korzystania z BlobClient obiektu przekazywanie obiektu blob mniejszego niż InitialTransferSize zostanie wykonane przy użyciu funkcji Put Blob, a nie put block.

MaximumConcurrency

MaximumConcurrency to maksymalna liczba procesów roboczych, które mogą być używane w transferze równoległym. Obecnie tylko operacje asynchroniczne mogą zrównać transfery. Operacje synchroniczne ignorują tę wartość i działają w sekwencji.

Skuteczność tej wartości podlega limitom puli połączeń na platformie .NET, które mogą domyślnie ograniczać wydajność w niektórych scenariuszach. Aby dowiedzieć się więcej na temat limitów puli połączeń na platformie .NET, zobacz .NET Framework Połączenie ion Pool Limits (Limity puli połączeń) i new Azure SDK for .NET (Limity puli połączeń dla platformy .NET).

MaximumTransferSize

MaximumTransferSize to maksymalna długość transferu w bajtach. Jak wspomniano wcześniej, ta wartość nie ogranicza InitialTransferSizewartości , która może być większa niż MaximumTransferSize.

Aby wydajnie przenosić dane, biblioteki klienckie mogą nie zawsze osiągać MaximumTransferSize wartość dla każdego transferu. W zależności od operacji maksymalna obsługiwana wartość rozmiaru transferu może się różnić. Na przykład blokowe obiekty blob wywołujące operację Put Block z usługą w wersji 2019-12-12 lub nowszej mają maksymalny rozmiar bloku 4000 MiB. Aby uzyskać więcej informacji na temat limitów rozmiaru transferu dla usługi Blob Storage, zobacz wykres w temacie Skalowanie obiektów docelowych dla usługi Blob Storage.

Przykład kodu

Biblioteka klienta zawiera przeciążenia dla Upload metod i UploadAsync , które akceptują wystąpienie StorageTransferOptions w ramach parametru BlobUploadOptions . Podobne przeciążenia istnieją również dla DownloadTo metod i DownloadToAsync przy użyciu parametru BlobDownloadToOptions .

Poniższy przykład kodu pokazuje, jak zdefiniować wartości dla StorageTransferOptions wystąpienia i przekazać te opcje konfiguracji jako parametr do UploadAsync. Wartości podane w tym przykładzie nie są przeznaczone do zalecenia. Aby prawidłowo dostosować te wartości, należy wziąć pod uwagę konkretne potrzeby aplikacji.

// 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);

W tym przykładzie ustawiliśmy liczbę równoległych procesów roboczych transferu na 2 przy użyciu MaximumConcurrency właściwości . Ta konfiguracja otwiera maksymalnie dwa połączenia jednocześnie, co pozwala na równoległe przekazywanie. Początkowe żądanie zakresu HTTP próbuje przekazać do 8 MiB danych zgodnie z definicją InitialTransferSize właściwości . Należy pamiętać, że InitialTransferSize dotyczy tylko przekazywania w przypadku korzystania ze strumienia możliwego do wyszukiwania. Jeśli rozmiar obiektu blob jest mniejszy niż 8 MiB, tylko jedno żądanie jest niezbędne do ukończenia operacji. Jeśli rozmiar obiektu blob jest większy niż 8 MiB, wszystkie kolejne żądania transferu mają maksymalny rozmiar 4 MiB, który ustawiliśmy za pomocą MaximumTransferSize właściwości .

Zagadnienia dotyczące wydajności przekazywania

Podczas przekazywania biblioteki klienta usługi Storage dzielą dany strumień przekazywania na wiele podwyżek na podstawie wartości zdefiniowanych w wystąpieniu StorageTransferOptions . Każdy podładunek ma własne dedykowane wywołanie operacji REST. BlobClient W przypadku obiektu lub BlockBlobClient obiektu ta operacja to Put Block. DataLakeFileClient W przypadku obiektu ta operacja to Dołączanie danych. Biblioteka klienta usługi Storage zarządza tymi operacjami REST równolegle (w zależności od opcji transferu), aby ukończyć pełne przekazywanie.

W zależności od tego, czy strumień przekazywania można wyszukiwać, czy nie można go znaleźć, biblioteka klienta obsługuje buforowanie i InitialTransferSize inaczej, zgodnie z opisem w poniższych sekcjach. Strumień z możliwością wyszukiwania to strumień, który obsługuje wykonywanie zapytań i modyfikowanie bieżącego położenia w strumieniu. Aby dowiedzieć się więcej o strumieniach na platformie .NET, zobacz dokumentację klasy usługi Stream.

Uwaga

Blokowe obiekty blob mają maksymalną liczbę bloków wynoszącą 50 000 bloków. Maksymalny rozmiar blokowego obiektu blob to 50 000 razy MaximumTransferSize.

Buforowanie podczas przekazywania

Warstwa REST magazynu nie obsługuje wybierania operacji przekazywania REST, w której została przerwana; indywidualne transfery są ukończone lub utracone. Aby zapewnić odporność na przekazywanie strumienia bez możliwości wyszukiwania, przed rozpoczęciem przekazywania buforowane są dane bibliotek klienckich usługi Storage dla każdego pojedynczego wywołania REST. Oprócz ograniczeń szybkości sieci zachowanie buforowania jest powodem, dla którego należy wziąć pod uwagę mniejszą wartość MaximumTransferSize, nawet w przypadku przekazywania w sekwencji. Zmniejszenie wartości MaximumTransferSize zmniejsza maksymalną ilość danych buforowanych dla każdego żądania i ponawianie próby żądania, które zakończyło się niepowodzeniem. Jeśli występują częste przekroczenia limitu czasu podczas transferów danych o określonym rozmiarze, zmniejszenie wartości MaximumTransferSize skraca czas buforowania i może spowodować lepszą wydajność.

Innym scenariuszem, w którym buforowanie występuje, jest przekazanie danych z równoległymi wywołaniami REST w celu zmaksymalizowania przepływności sieci. Biblioteki klienckie potrzebują źródeł, które mogą odczytywać równolegle, a ponieważ strumienie są sekwencyjne, biblioteki klienta usługi Storage buforują dane dla każdego wywołania REST przed rozpoczęciem przekazywania. To zachowanie buforowania występuje nawet wtedy, gdy podany strumień jest możliwy do wyszukiwania.

Aby uniknąć buforowania podczas asynchronicznego wywołania przekazywania, należy podać strumień z możliwością wyszukiwania i ustawić wartość MaximumConcurrency 1. Chociaż ta strategia powinna działać w większości sytuacji, nadal jest możliwe buforowanie, jeśli kod korzysta z innych funkcji biblioteki klienta, które wymagają buforowania.

InitialTransferSize podczas przekazywania

Gdy do przekazania jest udostępniany strumień możliwy do wyszukiwania, długość strumienia jest sprawdzana względem wartości InitialTransferSize. Jeśli długość strumienia jest mniejsza niż ta wartość, cały strumień jest przekazywany jako pojedyncze wywołanie REST, niezależnie od innych StorageTransferOptions wartości. W przeciwnym razie przekazywanie odbywa się w wielu częściach zgodnie z wcześniejszym opisem. InitialTransferSize nie ma wpływu na strumień bez możliwości wyszukiwania i jest ignorowany.

Zagadnienia dotyczące wydajności pobierania

Podczas pobierania biblioteki klienckie usługi Storage dzielą dane żądanie pobierania na wiele podpobierze na podstawie wartości zdefiniowanych w wystąpieniu StorageTransferOptions . Każde podpobierz ma własne dedykowane wywołanie operacji REST. W zależności od opcji transferu biblioteki klienckie zarządzają tymi operacjami REST równolegle w celu ukończenia pełnego pobierania.

Buforowanie podczas pobierania

Odbieranie wielu odpowiedzi HTTP jednocześnie z zawartością treści ma wpływ na użycie pamięci. Jednak biblioteki klienckie usługi Storage nie dodają jawnie kroku buforu dla pobranej zawartości. Odpowiedzi przychodzące są przetwarzane w kolejności. Biblioteki klienckie konfigurują bufor 16-kilobajtowy na potrzeby kopiowania strumieni z strumienia odpowiedzi HTTP do strumienia docelowego dostarczanego przez obiekt wywołujący lub ścieżkę pliku.

InitialTransferSize podczas pobierania

Podczas pobierania biblioteki klienckie usługi Storage tworzą jedno żądanie zakresu pobierania przy użyciu InitialTransferSize przed wykonaniem czegokolwiek innego. Podczas tego początkowego żądania pobierania biblioteki klienckie znają całkowity rozmiar zasobu. Jeśli początkowe żądanie pomyślnie pobrało całą zawartość, operacja zostanie ukończona. W przeciwnym razie biblioteki klienckie nadal wysyłają żądania zakresu do MaximumTransferSize momentu ukończenia pełnego pobierania.

Następne kroki