Gridwich Azure Storage Service인 Gridwich.SagaParticipants.Storage.AzureStorage는 Gridwich에 구성된 Azure Storage 계정의 Blob 작업과 컨테이너 작업을 제공합니다. 스토리지 작업의 예로는 Blob 만들기, 컨테이너 삭제, Blob 복사 또는 저장소 계층 변경이 있습니다.
Gridwich가 Azure Storage 블록 Blob과 컨테이너 모두에서 작동하려면 스토리지 메커니즘이 필요합니다. Blob 및 컨테이너에 고유한 클래스와 Storage Service 작업을 사용하면 지정된 스토리지 작업이 Blob 또는 컨테이너와 관련이 있는지 여부가 명확해집니다. 이 문서는 언급된 경우를 제외하고 Blob 및 컨테이너 모두에 적용됩니다.
Gridwich는 Storage.AzureStorage
saga 참가자 내 외부 시스템에 대부분의 스토리지 작업을 노출합니다. 다른 saga 참가자는 인코딩 워크플로를 설정할 때 다른 컨테이너나 계정 간에 Blob 복사와 같은 작업에 스토리지 서비스를 사용합니다.
이 문서에서는 Gridwich Azure Storage Service가 솔루션 요구 사항을 충족하고 이벤트 처리기와 같은 메커니즘과 통합되는 방법을 설명합니다. 링크는 컨테이너, 클래스 및 메커니즘에 대한 보다 광범위한 설명이 포함된 해당 소스 코드를 가리킵니다.
Azure Storage SDK
Gridwich는 REST 요청을 직접 작업하는 대신 Azure Storage SDK의 클래스를 사용하여 Azure Storage와 상호 작용합니다. 스토리지 공급자 내에서 SDK BlobBaseClient 및 BlobContainerClient 클래스는 스토리지 요청을 관리합니다.
이러한 SDK 클라이언트 클래스는 Gridwich에서 현재 작업 컨텍스트에 x-ms-client-request-id
, 개체 버전에 ETag
를 조작해야 하는 HTTP 헤더 두 개에 대한 간접 액세스만 허용합니다.
Gridwich에서 공급자 클래스 쌍은 BlobBaseClientProvider 및 BlobContainerClientProvider 기능을 슬리브라는 단위로 분배합니다. 슬리브에 대한 자세한 내용은 스토리지 슬리브를 참조하세요.
다음 다이어그램에서는 SDK 및 Gridwich 클래스의 구조와 인스턴스가 서로 어떻게 관련되는지를 보여 줍니다. 화살표는 "참조 있음"을 나타냅니다.
파이프라인 정책
클라이언트 인스턴스를 만들 때 HTTP 헤더를 파이프라인 정책 인스턴스로 조작하도록 후크를 설정합니다. 클라이언트 인스턴스를 만들 때만 이 정책을 설정할 수 있으며 정책을 변경할 수는 없습니다. 클라이언트를 사용하는 스토리지 공급자 코드는 실행 중에 헤더 값을 조작할 수 있어야 합니다. 문제는 스토리지 공급자와 파이프라인이 원활하게 상호 작용하도록 하는 것입니다.
Gridwich 파이프라인 정책은 BlobClientPipelinePolicy 클래스를 참조하세요.
Storage Service 캐싱
TCP 연결 설정 및 인증은 SDK 클라이언트 개체 인스턴스에서 Azure Storage에 첫 번째 요청을 보낼 때 오버헤드를 만듭니다. 외부 시스템 요청에서 동일한 Blob을 여러 번 호출(예: 메타데이터 가져오기 다음, Blob 삭제, 오버헤드 복합).
오버헤드를 완화하기 위해 Gridwich는 작업 컨텍스트에서 사용하는 SDK 클래스에 따라 스토리지 Blob 또는 컨테이너마다 클라이언트 인스턴스 하나의 캐시를 유지합니다. Gridwich는 이 클라이언트 인스턴스를 유지하고 외부 시스템 요청 기간 동안 같은 Blob 또는 컨테이너에 대해 여러 Azure Storage 작업의 인스턴스를 사용할 수 있습니다.
Azure SDK에서 제공하는 클라이언트 클래스를 사용하려면 만들 때 SDK 클라이언트 개체 인스턴스가 단일 Blob 또는 컨테이너와 관련되어야 합니다. 또한 인스턴스는 서로 다른 스레드에서 동시에 사용하기에 안전하지 않습니다. 작업 컨텍스트는 단일 요청을 나타내므로 Gridwich는 Blob 또는 컨테이너 이름과 작업 컨텍스트의 조합에서 캐싱을 기반으로 합니다.
Azure Storage SDK 클라이언트 구조와 결합된 이 인스턴스를 다시 사용하려면 효율성과 코드 선명도의 균형을 맞출 수 있는 추가 지원 코드가 필요합니다.
컨텍스트 인수
거의 모든 Gridwidh Storage Service 작업을 사용하려면 StorageClientProviderContext 형식의 특별 컨텍스트 인수가 필요합니다. 이 컨텍스트 인수는 다음 요구 사항을 충족합니다.
외부 시스템에 응답을 제공합니다. 여기에는 Gridwich 요청에서 외부 시스템이 지정한 요청별 고유한 JSON 기반 작업 컨텍스트 값이 포함됩니다. 자세한 내용은 작업 컨텍스트를 참조하세요.
Gridwich 이벤트 처리기와 같은 Storage Service 호출자가 외부 시스템에 표시되는 응답을 제어할 수 있습니다. 이 컨트롤을 통해 서비스는 외부 시스템에 관련 없는 알림 이벤트가 넘치지 않도록 방지합니다. 자세한 내용은 컨텍스트 음소거를 참조하세요.
Azure Storage 규칙을 준수하여 병렬 판독기와 작성기를 혼합할 수 있는 환경에서 일관된 요청 및 응답을 보장합니다. 예를 들어 ETag 추적을 지원합니다. 자세한 내용은 ETag를 참조하세요.
스토리지 컨텍스트
Blob 및 컨테이너 스토리지 형식 모두에 대한 컨텍스트는 다음과 같은 StorageClientProviderContext입니다.
string ClientRequestID { get; }
JObject ClientRequestIdAsJObject { get; }
bool IsMuted { get; set; }
string ETag { get; set; }
bool TrackingETag { get; set; }
첫 두 속성은 StorageClientProviderContext 인스턴스를 초기화하는 데 사용했던 작업 컨텍스트와 다르게 표시됩니다. 복사 생성자를 포함하는 다양한 생성자가 클래스에 존재합니다. 추가 메서드에는 현재 위치 상태 중복을 허용하는 ResetTo
와 문제가 있는 초기화에서 예외를 발생하지 않게 하는 정적 CreateSafe
메서드가 포함됩니다.
또한 이 클래스에는 GUID 및 빈 문자열을 기반으로 컨텍스트를 만들 수 있도록 특수 처리가 포함되어 있습니다. Created 및 Deleted BLOB에 대한 Azure Storage 알림 처리기는 외부 에이전트에서 발생한 알림도 처리하며 GUID 양식을 요구합니다.
컨텍스트 음소거
이 IsMuted
속성은 애플리케이션이 결과 알림을 호출자(예: 외부 시스템)에게 다시 게시할 것으로 예상하는지 여부를 제어합니다. 음소거된 작업에서 서비스는 결과 이벤트를 게시하지 않습니다.
예로는 인코더를 실행하여 Azure Storage의 Blob을 인코딩 작업에 대한 입력으로 정렬하는 Blob 복사본이 있습니다. 외부 시스템은 이러한 세부 정보를 무시하지만 인코딩 작업 상태와 인코딩된 출력을 검색할 수 있는 위치에만 관심을 둡니다. 이러한 문제가 반영되도록 인코더는 다음을 수행합니다.
요청 작업 컨텍스트에 따라 음소거되지 않은 스토리지 컨텍스트를 만듭니다(예:
ctxNotMuted
).컨텍스트 클래스 복사 생성자를 사용하거나 새 인스턴스를 만들어,
ctxMuted
같이 약화된 스토리지 컨텍스트를 만듭니다. 두 옵션 모두에서 작업 컨텍스트 값은 동일합니다.인코딩 설정과 관련된 스토리지 작업에
ctxMuted
를 지정합니다. 외부 시스템에는 이러한 작업이 발생했음이 표시되지 않습니다.인코딩 완료를 반영하는 스토리지 작업에
ctxNotMuted
컨텍스트를 지정합니다(예: 출력 파일을 대상 컨테이너에 복사). Gridwich 처리기에서 결과 Azure Storage 알림 이벤트를 외부 시스템에 게시합니다.
호출자는 작업의 최종 가시성을 제어합니다. 음소거된 작업과 음소거되지 않은 작업 모두 동등한 operationContext
값을 기반으로 합니다. 컨텍스트 음소거의 목적은 이벤트 추적 로그에서 문제를 보다 간편하게 진단할 수 있도록 하는 것입니다. 작업 음소거 상태에 관계없이 요청과 관련된 스토리지 작업을 볼 수 있기 때문입니다.
ResponseBaseDTO에는 이벤트 디스패치에서 게시 여부에 대한 최종 결정을 지시하는 데 사용하는 부울 속성 DoNotPublish
가 있습니다. 따라서 이벤트 디스패치에서 컨텍스트의 IsMuted
속성에 따라 DoNotPublish
속성을 설정합니다.
이 서비스는 약화 설정을 Azure Storage에 전송한 다음, 두 Gridwich 처리기 Created 및 Deleted에 제시할 스토리지 알림 이벤트에서 clientRequestId
를 설정합니다. 해당 두 처리기는 호출자 요청 음소거가 반영되도록 DoNotPublish
를 설정합니다.
대상 일관성에 대한 ETag
Azure Storage는 대상 일관성이 있어야 하는 요청 시퀀스에 HTTP ETag
헤더를 사용합니다. 예를 들면 메타데이터 검색 및 메타데이터 업데이트 스토리지 작업 간에 Blob이 변경되지 않았는지 확인하는 것입니다.
표준 HTTP 사용량에 맞추기 위해 이 헤더에는 헤더 값이 변경되면 기본 개체도 변경된다고 해석하는 불투명 값이 있습니다. 요청이 개체의 현재 ETag
값을 보내고 현재 Storage Service ETag
값과 일치하지 않으면 요청이 즉시 실패합니다. 요청에 ETag
값이 포함되지 않으면 Azure Storage는 해당 검사를 건너뛰고 요청을 차단하지 않습니다.
Storage Service의 ETag
Gridwich의 경우 ETag
는 Gridwich Storage Service와 Azure Storage 간의 내부 세부 정보입니다. ETag
를 인식하는 데 다른 코드는 필요 없습니다. Storage Service는 BlobDelete Event
요청을 처리할 수 있도록 Blob 메타데이터 가져오기, Blob 삭제 작업과 같은 시퀀스에 ETag
를 사용합니다. ETag
를 사용하면 Blob 삭제 작업은 정확하게 메타데이터 가져오기 작업과 동일한 버전의 Blob을 대상으로 합니다.
앞의 예제에 ETag
를 사용하려면 다음을 수행합니다.
- 빈
ETag
를 사용하여 메타데이터 가져오기 요청을 보냅니다. - 응답에서
ETag
값을 저장합니다. - 저장된
ETag
값을 Blob 삭제 요청에 추가합니다.
두 ETag
값이 다르면 삭제 작업이 실패합니다. 이 실패는 다른 작업에서 2단계와 3단계 간에 Blob을 변경했음을 의미합니다. 1단계부터 프로세스를 반복합니다.
ETag
는 생성자 매개 변수이며 StorageClientProviderContext 클래스의 문자열 속성입니다. Gridwich별 BlobClientPipelinePolicy에서만 ETag
값을 조작합니다.
ETag 사용 제어
TrackingETag
속성은 다음 요청에 ETag
값을 보낼지 여부를 제어합니다. true
값은 서비스를 사용할 수 있는 경우 서비스에서 ETag
를 전송한다는 것을 의미합니다.
Azure Storage 요청에 주체 Blob 또는 컨테이너와 일치하지 않는 ETag
값이 있으면 작업이 실패합니다. 이 실패는 ETag
가 "요청이 대상으로 하는 정확한 버전"을 표현하는 표준 HTTP 방법이므로 의도적으로 발생합니다. 요청에는 ETags
가 일치해야 함을 나타내는 TrackingETag
속성이 포함되거나 ETag
값이 중요하지 않음을 나타내는 TrackingETag
속성이 포함되지 않을 수 있습니다.
파이프라인은 해당 REST 응답에 ETag
값이 있으면 항상 Azure Storage 작업에서 이 값을 검색합니다. 파이프라인은 가능한 경우 마지막 작업을 기준으로 항상 컨텍스트 ETag
속성을 업데이트합니다. TrackingETag
플래그는 동일한 클라이언트 인스턴스의 다음 요청에서 ETag
속성 값을 보내는지 여부만 제어합니다. ETag
값이 null이거나 비어 있으면 현재 요청은 TrackingETag
값에 관계없이 HTTP ETag
값을 설정하지 않습니다.
스토리지 슬리브
Gridwich가 Azure Storage 블록 Blob과 컨테이너 모두에서 작동하려면 스토리지 메커니즘이 필요합니다. Blob 및 컨테이너에 고유한 클래스와 Storage Service 작업이 있으므로 지정된 스토리지 작업이 Blob 또는 컨테이너와 관련이 있는지 여부가 명확합니다.
BLOB용 하나와 컨테이너용 하나로 구성된 공급자 클래스 쌍은 슬리브라는 단위로 두 가지 기능 집합을 분배합니다. 슬리브에는 Azure SDK의 일부인 스토리지 도우미 클래스 인스턴스가 있습니다. Storage Service를 초기화하면 공급자가 생성되고 Storage Service 메서드에서 직접 사용할 수 있게 됩니다.
슬리브 구조체
슬리브는 SDK 클라이언트 개체 인스턴스와 스토리지 컨텍스트에 대한 컨테이너입니다. 스토리지 공급자 함수는 두 가지 속성 Client
및 Context
를 통해 슬리브를 참조합니다. BLOB에 관한 슬리브 유형 및 컨테이너에 관한 슬리브 유형이 있으며, 각각 형식이 BlobBaseClient
및 BlobContainerClient
인 Client
속성을 가집니다.
Blob의 일반 슬리브 구조체는 다음과 같습니다.
BlobBaseClient Client { get; }
BlobServiceClient Service { get; }
StorageClientProviderContext Context { get; }
슬리브의 Service
속성은 편리합니다. Storage 계정 자격 증명은 SDK BlobServiceClient 클래스를 사용하는 일부 최종 인코더 관련 작업을 사용하기 위해 필요합니다. 이 요구 사항으로 인해 별도의 공급자를 생성하는 대신 기존 슬리브 유형 두 개에 Service 클라이언트 인스턴스를 추가했습니다.
슬리브 사용량
클라이언트 스토리지 공급자는 슬리브 인스턴스를 분배합니다. 스토리지 서비스 코드는 형식이 명확하게 설명된 다음 주석이 추가된 코드 시퀀스와 비슷합니다.
public bool DeleteBlob(Uri sourceUri, StorageClientProviderContext context)
{
. . .
StorageBlobClientSleeve sleeve = _blobBaseClientProvider.GetBlobBaseClientForUri(sourceUri, context); // Line A
BlobProperties propsIncludingMetadata = sleeve.Client.GetProperties(); // Line B
sleeve.Context.TrackingETag = true; // Send ETag from GetProperties()
var wasDeleted = sleeve.Client.DeleteBlob(); // Line C
sleeve.Context.TrackingETag = false;
var someResult = sleeve.Client.AnotherOperation(); // Line D
. . .
}
- Gridwich는 작업 컨텍스트를 A 줄의 슬리브 컨텍스트에 자동으로 채웁니다.
TrackingETag
기본값은 false입니다. - B 줄 다음의
sleeve.Context
는 A 줄의ETag
를 포함하고 같은ClientRequestID
값을 유지합니다. - C 줄은 줄 B의
ETag
값과ClientRequestId
를 모두 보냅니다. - C 줄 다음의 컨텍스트에는
Delete()
응답에 반환된 대로 새ETag
값이 있습니다. - D 줄은
AnotherOperation()
요청에 대한ETag
값을 보내지 않습니다. - D 줄 다음의 컨텍스트에는
AnotherOperation()
응답에 반환된 대로 새ETag
값이 있습니다.
Storage Service는 현재 종속성 주입 구성에서 Transient
로 설정되어 있으며 이는 슬리브 기반 캐싱이 요청별 기준에 따른다는 의미입니다. 자세한 내용은 Storage Service 및 종속성 주입을 참조하세요.
Storage Service 대안
다음 섹션에서는 현재 Gridwich 스토리지 솔루션에 속하지 않는 대체 방법을 설명합니다.
서브클래싱을 통해 파이프라인 정책 숨기기
SDK 클라이언트 형식을 서브클래싱하면 클라이언트에 간단한 속성 두 개(각 HTTP 헤더 값에 하나씩)가 추가되어 파이프라인 정책과의 상호 작용이 완전히 숨겨집니다. 그러나 Moq 버그가 심각하므로 이러한 파생 형식의 mock
를 통해 단위 테스트를 만들 수 없습니다. Gridwich는 Moq를 사용하므로 이 서브클래싱 방법을 사용하지 않았습니다.
Moq 버그는 내부 범위 가상 함수가 있는 상태에서 어셈블리 간 서브클래싱을 잘못 처리한 것과 관련이 있습니다. SDK 클라이언트 클래스는 일반 외부 사용자에게 표시되지 않는 내부 범위 형식과 관련된 내부 범위 가상 함수를 사용합니다. Moq가 Gridwich 어셈블리 중 하나에 있는 서브클래스 mock
를 만들려고 하면 Gridwich 클래스가 파생된 SDK 클라이언트 클래스에서 내부 범위 가상을 찾을 수 없으므로 테스트를 실행하면 실패합니다. Moq Castle 프록시 생성을 변경하는 것이 유일한 해결 방법입니다.
Storage Service 및 종속성 주입
Gridwich는 현재 Storage Service를 Transient
종속성 주입 서비스로 등록합니다. 즉, 종속성 주입이 서비스에 요청될 때마다 새 인스턴스를 만듭니다. 등록이 Scoped
로 변경되면 현재 코드도 올바르게 작동해야 합니다. 이는 요청당 인스턴스 하나(예: 외부 시스템 요청)를 의미합니다.
그러나 등록이 Singleton
으로 변경되면 Gridwich 함수 앱에서 인스턴스 하나에 문제가 발생합니다. 그러면 슬리브와 데이터 바이트 범위에 대한 Gridwich 캐싱 메커니즘이 서로 다른 요청을 구분하지 않습니다. 또한 캐시 모델은 체크 아웃 모델이 아니므로 Gridwich는 사용 중인 동안 캐시에서 인스턴스를 제거하지 않습니다. SDK 클라이언트 클래스는 조정 시 많은 부분을 변경해야 하며, 이는 스레드로부터 안전하도록 보장되지 않기 때문입니다.
이러한 이유로 인해 Gridwich Storage Service를 Singleton
종속성 주입 등록으로 변경하지 마세요. Gridwich는 종속성 주입 등록에서 이 규칙을 따르고, 시행을 위해 단위 테스트인 CheckThatStorageServiceIsNotASingleton을 포함합니다.
다음 단계
제품 설명서:
Microsoft Learn 모듈: