Udostępnij przez


Bezpieczeństwo wątków i zarządzanie okresem istnienia klienta dla obiektów zestawu Azure SDK

Ten artykuł ułatwia zrozumienie problemów z bezpieczeństwem wątków podczas korzystania z zestawu Azure SDK. W tym artykule omówiono również, jak projekt zestawu SDK ma wpływ na zarządzanie okresem istnienia klienta. Dowiesz się, dlaczego nie jest konieczne usuwanie obiektów klienta zestawu Azure SDK.

Bezpieczeństwo wątków

Wszystkie obiekty klienta zestawu Azure SDK są bezpieczne wątkowo i niezależne od siebie. Konstrukcja zapewnia, że ponowne użycie instancji klienta jest zawsze bezpieczne, nawet w różnych wątkach. Na przykład poniższy kod uruchamia wiele zadań, ale jest bezpieczny dla wątków.

var client = new SecretClient(
    new Uri("<secrets_endpoint>"), new DefaultAzureCredential());

foreach (var secretName in secretNames)
{
    // Using clients from parallel threads
    Task.Run(() => Console.WriteLine(client.GetSecret(secretName).Value));
}

Obiekty modelu używane przez klientów zestawu SDK, niezależnie od tego, czy modele wejściowe, czy wyjściowe, nie są domyślnie bezpieczne wątkowo. Większość przypadków użycia obejmujących obiekty modelu używa tylko jednego wątku. W związku z tym koszt implementacji synchronizacji jako domyślne zachowanie jest zbyt wysoki dla tych obiektów. Poniższy kod ilustruje usterkę, w której uzyskiwanie dostępu do modelu z wielu wątków może spowodować niezdefiniowane zachowanie:

KeyVaultSecret newSecret = client.SetSecret("secret", "value");

foreach (var tag in tags)
{
    // Don't use model type from parallel threads
    Task.Run(() => newSecret.Properties.Tags[tag] = CalculateTagValue(tag));
}

client.UpdateSecretProperties(newSecret.Properties);

Aby uzyskać dostęp do modelu z różnych wątków, musisz zaimplementować własny kod synchronizacji. Przykład:

KeyVaultSecret newSecret = client.SetSecret("secret", "value");

// Code omitted for brevity

foreach (var tag in tags)
{
    Task.Run(() =>
    {
        lock (newSecret)
        {
            newSecret.Properties.Tags[tag] = CalculateTagValue(tag);
        }
    );
}

client.UpdateSecretProperties(newSecret.Properties);

Okres istnienia klienta

Ponieważ klienci Azure SDK są wątkowo bezpieczni, nie ma potrzeby tworzenia wielu obiektów klienta SDK dla określonego zestawu parametrów konstruktora. Traktuj obiekty klienta Azure SDK jako singletony po utworzeniu. To zalecenie jest często implementowane poprzez zarejestrowanie obiektów klienta zestawu Azure SDK jako singletony w kontenerze Inversion of Control (IoC) w aplikacji. Wstrzykiwanie zależności (DI) służy do uzyskiwania odwołań do obiektu klienta zestawu SDK. W poniższym przykładzie pokazano rejestrację pojedynczego obiektu klienta:

var builder = Host.CreateApplicationBuilder(args);

var endpoint = builder.Configuration["SecretsEndpoint"];
var blobServiceClient = new BlobServiceClient(
    new Uri(endpoint), new DefaultAzureCredential());

builder.Services.AddSingleton(blobServiceClient);

Aby uzyskać więcej informacji na temat implementowania di za pomocą zestawu Azure SDK, zobacz Wstrzykiwanie zależności za pomocą zestawu Azure SDK dla platformy .NET.

Alternatywnie możesz utworzyć wystąpienie klienta SDK i następnie udostępnić je metodom, które tego wymagają. Chodzi o uniknięcie niepotrzebnych wystąpień tego samego obiektu klienta zestawu SDK z tymi samymi parametrami. To zarówno niepotrzebne, jak i marnudne.

Klienci nie są jednorazowi

Dwa ostatnie pytania, które często pojawiają się:

  • Czy muszę usunąć obiekty klienta zestawu Azure SDK po zakończeniu korzystania z nich?
  • Dlaczego obiekty klienta zestawu Azure SDK oparte na protokole HTTP nie są jednorazowe?

Wszystkie klienty Azure SDK używają wewnętrznie jednego współdzielonego HttpClient wystąpienia. Klienci nie tworzą żadnych innych zasobów, które muszą być aktywnie zwalniane. Udostępnione wystąpienie HttpClient trwa przez cały okres działania aplikacji.

// Both clients reuse the shared HttpClient and don't need to be disposed
var blobClient = new BlobClient(new Uri(sasUri));
var blobClient2 = new BlobClient(new Uri(sasUri2));

Istnieje możliwość przekazania niestandardowego wystąpienia HttpClient do obiektu klienta Azure SDK. W takim przypadku stajesz się odpowiedzialny za zarządzanie HttpClient okresem istnienia i prawidłowe jego usuwanie w odpowiednim czasie.

var httpClient = new HttpClient();

var clientOptions = new BlobClientOptions()
{
    Transport = new HttpClientTransport(httpClient)
};

// Both clients would use the HttpClient instance provided in clientOptions
var blobClient = new BlobClient(new Uri(sasUri), clientOptions);
var blobClient2 = new BlobClient(new Uri(sasUri2), clientOptions);

// Code omitted for brevity

// You're responsible for properly disposing httpClient some time later
httpClient.Dispose();

Dalsze wskazówki dotyczące prawidłowego HttpClient zarządzania wystąpieniami i ich dysponowania można znaleźć w HttpClient dokumentacji.

Zobacz także