Azure SDK 개체에 대한 스레드 보안 및 클라이언트 수명 관리

이 문서는 Azure SDK를 사용할 때 스레드 보안 문제를 이해하는 데 도움이 됩니다. 또한 SDK 디자인이 클라이언트 수명 관리에 미치는 영향에 대해서도 설명합니다. Azure SDK 클라이언트 개체를 삭제할 필요가 없는 이유를 알아봅니다.

스레드로부터의 안전성

모든 Azure SDK 클라이언트 개체는 스레드로부터 안전하며 서로 독립적입니다. 이 디자인을 통해 스레드 간에 클라이언트 인스턴스를 다시 사용하더라도 항상 안전합니다. 예를 들어 다음 코드는 여러 작업을 시작하지만 스레드는 안전합니다.

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

입력 모델이든 출력 모델이든 SDK 클라이언트에서 사용하는 모델 개체는 기본적으로 스레드로부터 안전하지 않습니다. 모델 개체와 관련된 대부분의 사용 사례는 단일 스레드만 사용합니다. 따라서 동기화를 기본 동작으로 구현하는 비용이 이러한 개체에 대해 너무 높습니다. 다음 코드에서는 여러 스레드에서 모델에 액세스하면 정의되지 않은 동작이 발생할 수 있는 버그를 보여 줍니다.

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

다른 스레드에서 모델에 액세스하려면 사용자 고유의 동기화 코드를 구현해야 합니다. 예시:

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

클라이언트 수명

Azure SDK 클라이언트는 스레드로부터 안전하므로 지정된 생성자 매개 변수 집합에 대해 여러 SDK 클라이언트 개체를 생성할 이유가 없습니다. 일단 생성되면 Azure SDK 클라이언트 개체를 단일 항목으로 처리합니다. 이 권장 사항은 일반적으로 Azure SDK 클라이언트 개체를 앱의 IoC(제어 반전) 컨테이너에 단일 항목으로 등록하여 구현됩니다. DI(종속성 주입)는 SDK 클라이언트 개체에 대한 참조를 가져오는 데 사용됩니다. 다음 예에서는 싱글톤 클라이언트 개체 등록을 보여 줍니다.

var builder = Host.CreateApplicationBuilder(args);

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

builder.Services.AddSingleton(blobServiceClient);

Azure SDK를 통해 DI를 구현하는 자세한 내용은 .NET용 Azure SDK를 통해 종속성 주입을 참조하세요.

또는 SDK 클라이언트 인스턴스를 만들어 클라이언트가 필요한 메서드에 제공할 수 있습니다. 중요한 점은 동일한 매개 변수를 사용하여 동일한 SDK 클라이언트 개체의 불필요한 인스턴스화를 방지하는 것입니다. 모두 불필요하고 낭비입니다.

클라이언트는 삭제할 수 없습니다.

자주 제기되는 두 가지 최종 질문은 다음과 같습니다.

  • 사용이 끝나면 Azure SDK 클라이언트 개체를 삭제해야 하나요?
  • HTTP 기반 Azure SDK 클라이언트 개체를 삭제할 수 없는 이유는 무엇인가요?

내부적으로 모든 Azure SDK 클라이언트는 단일 공유 HttpClient 인스턴스를 사용합니다. 클라이언트는 능동적으로 해제해야 하는 다른 리소스를 만들지 않습니다. 공유 HttpClient 인스턴스는 전체 애플리케이션 수명 동안 유지됩니다.

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

HttpClient의 사용자 지정 인스턴스를 Azure SDK 클라이언트 개체에 제공할 수 있습니다. 이 경우 HttpClient 수명을 관리하고 적절한 시간에 적절하게 삭제해야 합니다.

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

HttpClient 인스턴스를 올바르게 관리하고 삭제하기 위한 추가 지침은 HttpClient 설명서에서 확인할 수 있습니다.

참고 항목