Azure Storage와 같은 클라우드 기반 인프라는 데이터 및 애플리케이션을 호스팅하기 위한 고가용성 및 지속성 플랫폼을 제공합니다. 클라우드 기반 애플리케이션 개발자는 이 플랫폼을 활용하여 사용자에게 이러한 이점을 극대화하는 방법을 신중하게 고려해야 합니다. Azure Storage는 지역 가동 중단 시에도 고가용성을 보장하기 위한 지역 중복 옵션을 제공합니다. 지역 중복 복제를 위해 구성된 스토리지 계정은 주 지역에서 동기적으로 복제된 다음 수백 마일 떨어진 보조 지역에 비동기적으로 복제됩니다.
Azure Storage는 지역 중복 복제를 위해 GRS(지역 중복 스토리지) 및 GZRS(지역 영역 중복 스토리지)의 두 가지 옵션을 제공합니다. Azure Storage 지역 중복 옵션을 사용하려면 스토리지 계정이 읽기 액세스 지역 중복 스토리지(RA-GRS) 또는 읽기 액세스 지역 영역 중복 스토리지(RA-GZRS)에 대해 구성되었는지 확인합니다. 그렇지 않은 경우 스토리지 계정 복제 유형을 변경하는 방법에 대해 자세히 알아볼 수 있습니다.
이 문서에서는 주 지역에서 상당한 중단이 발생하더라도 제한된 용량에도 불구하고 계속 작동할 애플리케이션을 디자인하는 방법을 보여 있습니다. 주 지역을 사용할 수 없게 되면 주 지역이 다시 응답할 때까지 애플리케이션이 원활하게 전환하여 보조 지역에 대해 읽기 작업을 수행할 수 있습니다.
애플리케이션 디자인 고려 사항
애플리케이션을 설계하여, 주 지역에서 읽기를 방해하는 문제가 발생할 때 보조 지역에서 읽도록 하여 일시적인 오류나 심각한 중단에 대응할 수 있습니다. 주 지역을 다시 사용할 수 있는 경우 애플리케이션은 주 지역에서 읽기로 돌아갈 수 있습니다.
RA-GRS 또는 RA-GZRS를 사용하여 가용성 및 복원력을 위해 애플리케이션을 디자인할 때 다음 주요 고려 사항에 유의하세요.
주 지역에 저장하는 데이터의 읽기 전용 복사본은 보조 지역에서 비동기적으로 복제됩니다. 이 비동기 복제는 보조 지역의 읽기 전용 복사본이 결국 주 지역의 데이터와 일치 한다는 것을 의미합니다. 스토리지 서비스는 보조 지역의 위치를 결정합니다.
Azure Storage 클라이언트 라이브러리를 사용하여 주 지역 엔드포인트에 대한 읽기 및 업데이트 요청을 수행할 수 있습니다. 주 지역을 사용할 수 없는 경우 읽기 요청을 보조 지역으로 자동으로 리디렉션할 수 있습니다. 원하는 경우 주 지역을 사용할 수 있는 경우에도 읽기 요청을 보조 지역으로 직접 보내도록 앱을 구성할 수도 있습니다.
주 지역을 사용할 수 없게 되면 계정 장애 조치를 시작할 수 있습니다. 보조 지역으로 전환(failover)할 때, 주 지역을 가리키던 DNS 레코드가 보조 지역을 가리키도록 변경됩니다. 장애 조치(failover)가 완료되면 GRS 및 RA-GRS 계정에 대한 쓰기 액세스가 복원됩니다. 자세한 내용은 재해 복구 및 저장소 계정 장애 조치(failover)를 참조하세요.
점진적으로 일관성이 있는 데이터 작업
제안된 솔루션은 잠재적으로 부실한 데이터를 호출 애플리케이션에 반환하는 것이 허용된다고 가정합니다. 보조 지역의 데이터는 결국 일관되므로 보조 지역에 대한 업데이트가 복제를 완료하기 전에 주 지역에 액세스할 수 없게 될 수 있습니다.
예를 들어 고객이 업데이트를 성공적으로 제출하지만 업데이트가 보조 지역으로 전파되기 전에 주 지역이 실패한다고 가정합니다. 고객이 데이터를 다시 읽도록 요청하면 업데이트된 데이터 대신 보조 지역에서 부실 데이터를 받습니다. 애플리케이션을 디자인할 때 이 동작이 허용되는지 여부를 결정해야 합니다. 이 경우 사용자에게 알리는 방법도 고려해야 합니다.
이 문서의 뒷부분에서는 최종적으로 일관된 데이터를 처리하는 방법과 마지막 동기화 시간 속성을 확인하여 주 지역과 보조 지역의 데이터 간 불일치를 평가하는 방법에 대해 자세히 알아봅니다.
개별적으로 또는 모두 함께 서비스 처리
가능성은 낮지만 한 서비스(Blob, 큐, 테이블 또는 파일)를 사용할 수 없는 반면 다른 서비스는 여전히 완벽하게 작동할 수 있습니다. 각 서비스에 대한 재시도를 개별적으로 처리하거나 모든 스토리지 서비스에 대해 일반적으로 재시도를 함께 처리할 수 있습니다.
예를 들어 애플리케이션에서 큐 및 Blob을 사용하는 경우 각 서비스에 대해 재시도 가능한 오류를 처리하기 위해 별도의 코드를 배치하도록 결정할 수 있습니다. 이렇게 하면 Blob 서비스 오류는 Blob을 처리하는 애플리케이션의 일부에만 영향을 미치며 큐는 정상적으로 계속 실행됩니다. 그러나 모든 스토리지 서비스 재시도를 함께 처리하기로 결정한 경우 두 서비스 중 하나가 다시 시도 가능한 오류를 반환하는 경우 Blob 및 큐 서비스 모두에 대한 요청이 영향을 받습니다.
궁극적으로 이 결정은 애플리케이션의 복잡성에 따라 달라집니다. 재시도의 영향을 제한하기 위해 서비스별 오류를 처리하는 것이 좋습니다. 또는 주 지역의 스토리지 서비스에 문제가 발견되면 모든 스토리지 서비스에 대한 읽기 요청을 보조 지역으로 리디렉션할 수 있습니다.
읽기 전용 모드에서 애플리케이션 실행
주 지역에서 중단을 효과적으로 준비하려면 애플리케이션이 실패한 읽기 요청과 실패한 업데이트 요청을 모두 처리할 수 있어야 합니다. 주 지역이 실패하면 읽기 요청을 보조 지역으로 리디렉션할 수 있습니다. 그러나 보조 지역의 복제된 데이터는 읽기 전용이므로 업데이트 요청을 리디렉션할 수 없습니다. 이러한 이유로 읽기 전용 모드에서 실행할 수 있도록 애플리케이션을 디자인해야 합니다.
예를 들어 업데이트 요청이 Azure Storage에 제출되기 전에 확인되는 플래그를 설정할 수 있습니다. 업데이트 요청이 완료되면 요청을 건너뛰고 사용자에게 적절한 응답을 반환할 수 있습니다. 문제가 해결될 때까지 특정 기능을 모두 사용하지 않도록 선택하고 기능을 일시적으로 사용할 수 없음을 사용자에게 알릴 수도 있습니다.
각 서비스에 대한 오류를 개별적으로 처리하기로 결정한 경우 서비스별 읽기 전용 모드에서 애플리케이션을 실행하는 기능도 처리해야 합니다. 예를 들어 각 서비스에 대해 읽기 전용 플래그를 설정할 수 있습니다. 그런 다음 필요에 따라 코드에서 플래그를 사용하거나 사용하지 않도록 설정할 수 있습니다.
또한 읽기 전용 모드에서 애플리케이션을 실행할 수 있으므로 주요 애플리케이션 업그레이드 중에 제한된 기능을 보장할 수 있습니다. 애플리케이션을 트리거하여 읽기 전용 모드로 실행하고 보조 데이터 센터를 가리키면 업그레이드하는 동안 주 지역의 데이터에 아무도 액세스하지 않도록 할 수 있습니다.
읽기 전용 모드에서 실행할 때 업데이트 처리
읽기 전용 모드에서 실행할 때 업데이트 요청을 처리하는 방법에는 여러 가지가 있습니다. 이 섹션에서는 고려해야 할 몇 가지 일반적인 패턴에 중점을 둡니다.
사용자에게 응답하고 업데이트 요청이 현재 처리되고 있지 않다는 것을 알릴 수 있습니다. 예를 들어 연락처 관리 시스템을 사용하면 사용자가 연락처 정보에 액세스할 수 있지만 업데이트할 수는 없습니다.
다른 지역에서 업데이트를 대기열에 추가할 수 있습니다. 이 경우 보류 중인 업데이트 요청을 다른 지역의 큐에 쓴 다음 기본 데이터 센터가 다시 온라인 상태가 되면 해당 요청을 처리합니다. 이 시나리오에서는 업데이트 요청이 나중에 처리하기 위해 대기 중임을 사용자에게 알려야 합니다.
다른 지역의 스토리지 계정에 업데이트를 작성할 수 있습니다. 주 지역이 다시 온라인 상태가 되면 데이터 구조에 따라 해당 업데이트를 기본 데이터로 병합할 수 있습니다. 예를 들어 이름에 날짜/타임스탬프를 사용하여 별도의 파일을 만드는 경우 해당 파일을 주 지역으로 다시 복사할 수 있습니다. 이 솔루션은 로깅 및 IoT 데이터와 같은 워크로드에 적용할 수 있습니다.
재시도 처리
클라우드에서 실행되는 서비스와 통신하는 애플리케이션은 계획되지 않은 이벤트 및 발생할 수 있는 오류에 민감해야 합니다. 이러한 오류는 일시적인 연결 손실부터 자연 재해로 인한 심각한 중단에 이르기까지 일시적 또는 영구적일 수 있습니다. 가용성을 최대화하고 전반적인 애플리케이션 안정성을 개선하기 위해 적절한 재시도 처리를 사용하여 클라우드 애플리케이션을 디자인하는 것이 중요합니다.
읽기 요청
주 지역을 사용할 수 없게 되면 읽기 요청을 보조 스토리지로 리디렉션할 수 있습니다. 앞에서 설명한 것처럼 애플리케이션에서 오래된 데이터를 읽을 수 있어야 합니다. Azure Storage 클라이언트 라이브러리는 재시도를 처리하고 읽기 요청을 보조 지역으로 리디렉션하는 옵션을 제공합니다.
이 예제에서는 Blob Storage에 대한 재시도 처리가 클래스에서 BlobClientOptions
구성되며 이러한 구성 옵션을 사용하여 만든 개체에 BlobServiceClient
적용됩니다. 이 구성은 주 지역에서 읽기 요청 재시도를 보조 지역으로 리디렉션하는 기본 다음 보조 접근 방식입니다. 이 방법은 주 지역의 오류가 일시적일 것으로 예상되는 경우에 가장 적합합니다.
string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");
// Provide the client configuration options for connecting to Azure Blob storage
BlobClientOptions blobClientOptions = new BlobClientOptions()
{
Retry = {
// The delay between retry attempts for a fixed approach or the delay
// on which to base calculations for a backoff-based approach
Delay = TimeSpan.FromSeconds(2),
// The maximum number of retry attempts before giving up
MaxRetries = 5,
// The approach to use for calculating retry delays
Mode = RetryMode.Exponential,
// The maximum permissible delay between retry attempts
MaxDelay = TimeSpan.FromSeconds(10)
},
// If the GeoRedundantSecondaryUri property is set, the secondary Uri will be used for
// GET or HEAD requests during retries.
// If the status of the response from the secondary Uri is a 404, then subsequent retries
// for the request will not use the secondary Uri again, as this indicates that the resource
// may not have propagated there yet.
// Otherwise, subsequent retries will alternate back and forth between primary and secondary Uri.
GeoRedundantSecondaryUri = secondaryAccountUri
};
// Create a BlobServiceClient object using the configuration options above
BlobServiceClient blobServiceClient = new BlobServiceClient(primaryAccountUri, new DefaultAzureCredential(), blobClientOptions);
주 지역을 오랫동안 사용할 수 없는 것으로 확인되면 보조 지역을 가리키도록 모든 읽기 요청을 구성할 수 있습니다. 이 구성은 보조 전용 방법입니다. 앞에서 설명한 것처럼 이 시간 동안 업데이트 요청을 처리하는 전략과 읽기 요청만 처리되고 있음을 사용자에게 알리는 방법이 필요합니다. 이 예제에서는 보조 지역 엔드포인트를 사용하는 새 인스턴스 BlobServiceClient
를 만듭니다.
string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");
// Create a BlobServiceClient object pointed at the secondary Uri
// Use blobServiceClientSecondary only when issuing read requests, as secondary storage is read-only
BlobServiceClient blobServiceClientSecondary = new BlobServiceClient(secondaryAccountUri, new DefaultAzureCredential(), blobClientOptions);
읽기 전용 모드 및 보조 전용 요청으로 전환할 시기를 아는 것은 회로 차단기 패턴이라는 아키텍처 디자인 패턴의 일부이며, 이후 섹션에서 설명합니다.
업데이트 요청
업데이트 요청은 읽기 전용인 보조 스토리지로 리디렉션할 수 없습니다. 앞에서 설명한 대로 주 지역을 사용할 수 없는 경우 애플리케이션에서 업데이트 요청을 처리 할 수 있어야 합니다.
회로 차단기 패턴은 업데이트 요청에도 적용할 수 있습니다. 업데이트 요청 오류를 처리하려면 코드에서 10회 연속 오류와 같은 임계값을 설정하고 주 지역에 대한 요청에 대한 오류 수를 추적할 수 있습니다. 임계값이 충족되면 애플리케이션을 읽기 전용 모드로 전환하여 주 지역에 대한 업데이트 요청이 더 이상 발급되지 않도록 할 수 있습니다.
회로 차단기 패턴을 구현하는 방법
복구하는 데 가변적인 시간이 걸릴 수 있는 오류 처리는 회로 차단기 패턴이라는 아키텍처 디자인 패턴의 일부입니다. 이 패턴의 적절한 구현은 애플리케이션이 실패할 가능성이 있는 작업을 반복적으로 실행하지 못하게 하여 애플리케이션 안정성 및 복원력을 향상시킬 수 있습니다.
회로 차단기 패턴의 한 가지 측면은 기본 엔드포인트에 지속적인 문제가 있는 경우를 식별하는 것입니다. 이 결정을 내리기 위해 클라이언트에서 재시도 가능한 오류가 발생하는 빈도를 모니터링할 수 있습니다. 각 시나리오가 다르기 때문에 보조 엔드포인트로 전환하고 읽기 전용 모드에서 애플리케이션을 실행하는 결정에 사용할 적절한 임계값을 결정해야 합니다.
예를 들어 주 지역에서 10번 연속 실패가 발생하면 전환을 수행하도록 결정할 수 있습니다. 코드에서 오류 수를 유지하여 이를 추적할 수 있습니다. 임계값에 도달하기 전에 성공하면 수를 다시 0으로 설정합니다. 개수가 임계값에 도달하면 읽기 요청에 보조 지역을 사용하도록 애플리케이션을 전환합니다.
다른 방법으로 애플리케이션에서 사용자 지정 모니터링 구성 요소를 구현하도록 결정할 수 있습니다. 이 구성 요소는 간단한 읽기 요청(예: 작은 Blob 읽기)을 사용하여 기본 스토리지 엔드포인트를 지속적으로 ping하여 상태를 확인할 수 있습니다. 이 방법은 일부 리소스를 차지하지만 상당한 양은 차지하지 않습니다. 임계값을 초과하는 문제가 발견되면 보조 읽기 요청만 수행하며, 읽기 전용 모드로 전환합니다. 이 시나리오에서는 주 스토리지 엔드포인트를 ping하는 작업이 다시 성공하면 주 지역으로 다시 전환하고 업데이트를 계속 허용할 수 있습니다.
전환 시기를 결정하는 데 사용되는 오류 임계값은 애플리케이션 내의 서비스마다 다를 수 있으므로 구성 가능한 매개 변수로 만드는 것이 좋습니다.
또 다른 고려 사항은 애플리케이션의 여러 인스턴스를 처리하는 방법과 각 인스턴스에서 재시도 가능한 오류를 감지할 때 수행할 작업입니다. 예를 들어 동일한 애플리케이션이 로드된 상태에서 20개의 VM이 실행 중일 수 있습니다. 각 인스턴스를 개별적으로 처리하나요? 한 인스턴스에 문제가 발생하는 경우 응답을 해당 인스턴스 하나로 제한하시겠습니까? 또는 한 인스턴스에 문제가 있을 때 모든 인스턴스가 동일한 방식으로 응답하도록 하시겠습니까? 인스턴스를 개별적으로 처리하는 것은 전체 응답을 조정하는 것보다 훨씬 간단하지만 애플리케이션의 아키텍처에 따라 접근 방식이 달라집니다.
최종적으로 일관된 데이터 처리
지역 중복 스토리지는 주 지역에서 보조 지역으로 트랜잭션을 복제하여 작동합니다. 복제 프로세스는 보조 지역의 데이터가 결국 일관성을 보장합니다. 즉, 주 지역의 모든 트랜잭션은 결국 보조 지역에 표시되지만 표시되기 전에 지연이 있을 수 있습니다. 또한 트랜잭션이 원래 주 지역에 적용된 순서와 동일한 순서로 보조 지역에 도착한다는 보장은 없습니다. 트랜잭션이 보조 지역에 순서 없이 도착하는 경우, 서비스가 따라잡을 때까지 보조 지역의 데이터가 일관되지 않은 상태에 있을 가능성이 있습니다.
Azure Table Storage에 대한 다음 예제에서는 직원의 세부 정보를 업데이트하여 관리자 역할의 구성원으로 만들 때 발생할 수 있는 작업을 보여 줍니다. 이 예제에서는 직원 엔터티를 업데이트하고 관리자 역할 엔터티를 총 관리자 수로 업데이트해야 합니다. 보조 지역에서 업데이트가 순서대로 적용되지 않는지 확인합니다.
시간 | 트랜잭션 | 복제 | 마지막 동기화 시간 | 결과 |
---|---|---|---|---|
T0 | 트랜잭션 A: 직원 삽입 기본 엔터티 |
트랜잭션 A가 주 데이터베이스에 삽입됨, 아직 복제되지 않았습니다. |
||
T1 | 트랜잭션 A 복제되어 전송됨 부차적인 |
T1 | 트랜잭션 A가 보조 데이터베이스에 복제되었습니다. 마지막 동기화 시간이 업데이트되었습니다. |
|
T2 | 트랜잭션 B: 업데이트 직원 개체 초등학교에서 |
T1 | 주 서버에 기록된 트랜잭션 B, 아직 복제되지 않았습니다. |
|
T3 | 트랜잭션 C: 업데이트 관리자 의 역할 엔터티 주된 |
T1 | 주 데이터베이스에 기록된 트랜잭션 C, 아직 복제되지 않았습니다. |
|
T4 | 트랜잭션 C 복제되어 전송됨 부차적인 |
T1 | 트랜잭션 C가 보조 시스템으로 전송되었습니다. LastSyncTime이 업데이트되지 않음 트랜잭션 B는 아직 복제되지 않았습니다. |
|
T5 | 엔터티 읽기 부차적인 항목에서 |
T1 | 직원의 오래된 값을 받습니다. 트랜잭션 B가 아직 수행되지 않았기 때문에 엔터티가 영향을 받습니다. 아직 복제되지 않았습니다. 에 대한 새 값을 가져옵니다. C가 관리자 역할 엔터티를 가지고 있으므로 재현. 마지막 동기화 시간이 아직 이루어지지 않았습니다. 트랜잭션 B로 인해 업데이트되었습니다. 복제되지 않았습니다. 다음을 알 수 있습니다. 관리자 역할 엔터티가 일관되지 않음 개체의 날짜/시간이 이후이므로 마지막 동기화 시간입니다. |
|
T6 | 트랜잭션 B 복제되어 전송됨 부차적인 |
T6 |
T6 – C를 통한 모든 트랜잭션이 있습니다. 복제 완료, 최근 동기화 시간 업데이트되었습니다. |
이 예제에서는 클라이언트가 T5에서 보조 리전에서 읽기로 전환한다고 가정합니다. 지금은 관리자 역할 엔터티를 성공적으로 읽을 수 있지만 엔터티에는 현재 보조 지역에서 관리자로 표시된 직원 엔터티 수와 일치하지 않는 관리자 수에 대한 값이 포함됩니다. 클라이언트는 정보가 일치하지 않는 위험과 함께 이 값을 표시할 수 있습니다. 또는 클라이언트는 업데이트가 순서가 맞지 않아 관리자 역할이 잠재적으로 일관되지 않은 상태인지 확인한 다음 사용자에게 이 사실을 알릴 수 있습니다.
스토리지 계정에 잠재적으로 일관되지 않은 데이터가 있는지 여부를 확인하기 위해 클라이언트는 마지막 동기화 시간 속성의 값을 확인할 수 있습니다. 마지막 동기화 시간은 보조 지역의 데이터가 마지막으로 일관된 시간과 서비스가 해당 시점 이전에 모든 트랜잭션을 적용한 시간을 알려줍니다. 위에 표시된 예제에서 서비스가 보조 지역에 직원 엔터티를 삽입한 후 마지막 동기화 시간은 T1로 설정됩니다. 서비스가 T6 으로 설정된 경우 보조 지역의 직원 엔터티를 업데이트할 때까지 T1에 유지됩니다. 클라이언트가 T5에서 엔터티를 읽을 때 마지막 동기화 시간을 검색하는 경우 엔터티의 타임스탬프와 비교할 수 있습니다. 엔터티의 타임스탬프가 마지막 동기화 시간보다 늦으면 엔터티가 잠재적으로 일관성이 없는 상태이며 적절한 작업을 수행할 수 있습니다. 이 필드를 사용하려면 주 복제본에 대한 마지막 업데이트가 완료된 시기를 알아야 합니다.
마지막 동기화 시간을 확인하는 방법을 알아보려면 스토리지 계정에 대한 마지막 동기화 시간 속성 확인을 참조하세요.
테스팅
다시 시도할 수 있는 오류가 발생할 때 애플리케이션이 예상대로 작동하는지 테스트하는 것이 중요합니다. 예를 들어 애플리케이션이 문제를 감지할 때 보조 지역으로 전환하는지 테스트한 다음 주 지역을 다시 사용할 수 있게 되면 다시 전환해야 합니다. 이 동작을 제대로 테스트하려면 재시도 가능한 오류를 시뮬레이션하고 발생하는 빈도를 제어하는 방법이 필요합니다.
한 가지 옵션은 Fiddler 를 사용하여 스크립트에서 HTTP 응답을 가로채고 수정하는 것입니다. 이 스크립트는 기본 엔드포인트에서 오는 응답을 식별하고 HTTP 상태 코드를 Storage 클라이언트 라이브러리가 다시 시도할 수 있는 오류로 인식하는 것으로 변경할 수 있습니다. 이 코드 조각은 employeedata 테이블에 대한 읽기 요청에 대한 응답을 가로채 502 상태를 반환하는 Fiddler 스크립트의 간단한 예제를 보여 줍니다.
static function OnBeforeResponse(oSession: Session) {
...
if ((oSession.hostname == "\[YOURSTORAGEACCOUNTNAME\].table.core.windows.net")
&& (oSession.PathAndQuery.StartsWith("/employeedata?$filter"))) {
oSession.responseCode = 502;
}
}
이 예제를 확장하여 더 넓은 범위의 요청을 가로채고 일부 요청의 responseCode 만 변경하여 실제 시나리오를 보다 효율적으로 시뮬레이션할 수 있습니다. Fiddler 스크립트 사용자 지정에 대한 자세한 내용은 Fiddler 설명서에서 요청 또는 응답 수정 을 참조하세요.
애플리케이션을 읽기 전용으로 전환하기 위해 구성 가능한 임계값을 설정한 경우 비프로덕션 트랜잭션 볼륨으로 동작을 테스트하는 것이 더 쉽습니다.
다음 단계
기본 엔드포인트와 보조 엔드포인트 간에 전환하는 방법을 보여 주는 전체 샘플은 Azure 샘플 – RA-GRS 스토리지에서 회로 차단기 패턴 사용)을 참조하세요.