ZIP 파일을 이용한 Windows Azure Storage의 저장 공간 효율 극대화하기

Windows Azure Storage는 익히 잘 알려져 있는대로 Object Storage의 역할을 충실히 잘 수행할 수 있는 매우 높은 기능 수준을 가진 Cloud 기반 BLOB Storage입니다. 단순히 웹 기반의 파일 업로드와 다운로드만을 하는 컨테이너들의 집합으로 생각하기 쉽지만, 잘 활용하면 어렵지 않게 전송 보안과 간단한 DRM까지 한번에 달성할 수 있습니다. 그리고 이런 고급 기능 외에도 저수준의 입출력도 지원합니다.


덕분에 매우 유용한 조합을 이용할 수 있는데, 바로 SharpZipLib의 ZipFile 클래스와 Windows Azure Storage Library의 CloudBlobStream 클래스를 결합하는 것입니다. 방금 이야기한 저수준의 입출력을 위해서는 HTTP의 Byte Range Request와 비슷한 입출력 방법이 가능해야 하고 이를 지원하는 Stream 클래스가 있어야 하는데 이를 구현하는 것이 바로 http://msdn.microsoft.com/ko-kr/library/windowsazure/dd179440.aspx 에서 소개하는 x-ms-range 요청 헤더 (http://msdn.microsoft.com/ko-kr/library/windowsazure/ee691967.aspx)와 이를 사용하는 CloudBlobStream 클래스입니다.


우선 Windows Azure SDK Storage Library의 버전이 최신 버전으로 업그레이드가 되어야 합니다. NuGet 패키지 관리자를 최신 버전으로 업그레이드한 다음, 아래 그림과 같이 시험해보려는 프로젝트에 대해서 Windows Azure Storage 라이브러리 패키지를 설치합니다. 단, 이 작업을 하기에 앞서서 해당 프로젝트의 기준 .NET Framework 버전을 적어도 .NET Framework 4 Client Profile 이상으로 설정해야 합니다.


 



패키지를 설치한 다음, 아래와 같이 간단한 코드를 작성해보도록 하겠습니다. 강조표시한 부분은 환경에 맞게 변경해주셔야 하는 부분들입니다.


CloudStorageAccount account = new CloudStorageAccount(
    new StorageCredentials(“accountName“, “accessKey“),
    false);


var client = account.CreateCloudBlobClient();
var containerRef = client.GetContainerReference(“example“);


var blobRef = containerRef.GetBlockBlobReference(“SampleDoc.docx“);
var blobStreamAsync = blobRef.OpenReadAsync();
blobStreamAsync.Wait();


using (Stream srcStream = blobStreamAsync.Result)
using (ZipFile file = new ZipFile(srcStream))
{
    foreach (ZipEntry entry in file)
    {
        if (!entry.Name.StartsWith(“word/media“, StringComparison.OrdinalIgnoreCase))
            continue;


        Console.WriteLine(“Extracting {0}…”, entry.Name);


        using (Stream innerFile = file.GetInputStream(entry))
        using (Stream localFile = File.OpenWrite(Path.GetFileName(entry.Name)))
        {
            innerFile.CopyTo(localFile);
        }
    }
}


위의 코드는 Windows Azure Storage에 올라가있는 Microsoft Word 문서 파일 안에 들어있는 미디어 파일들의 목록을 조회하여 전체 Word 문서를 다운로드하지 않고 즉시 미디어 파일들을 추출하는 예제 프로그램 코드입니다. 여기서 중요한 것은 최소한의 I/O 요청만을 이용하여 ZIP 파일을 마치 로컬 하드 디스크에서 다루던 것과 동일하게 그 안에 압축되어있던 파일을 자유롭게 액세스할 수 있다는 점입니다.


아래는 실행 결과입니다.


 



 



그렇다면 궁금한 것이 있습니다. 실제 네트워크 트래픽은 어떻게 주고 받는 것일까요? Fiddler를 통하여 실제 네트워크 트래픽 상태를 확인해보도록 하겠습니다.


 



예상대로 Windows Azure BLOB Storage 서버에서 우리가 다루려는 BLOB 객체에 대한 요청이 이루어지고 있으며, 최초에는 파일에 대한 정보 확인을 위하여 보낸 요청에 대한 응답으로 200 코드를 반환하였습니다. 



그리고 후속 요청으로 특정 Byte Range에 대한 데이터만을 보내는 요청이 SharpZipLib의 ZipFile 클래스가 내부 스트림에게 Seek/Read 요청을 보내게 되어 발생하게 되고, 이것은 다시 Windows Azure Storage REST API에 맞게 번역되어 실제 HTTP 요청으로 바뀌어 전달됩니다. 그 결과 여기에 대한 응답으로 HTTP 206 응답 코드와 함께 특정 구간의 데이터에 대한 정보와 함께 바이너리 데이터가 다운로드됩니다.


뒤이어 나오는 요청들은 전부 이와 같은 형태로 Partial Request와 Partial Response로 구성되어있으며, BLOB 데이터가 변경되지 않는 한 계속 유효하므로 이렇게 수신한 데이터는 내부적으로 계속 재사용됩니다. 또한, 일정 단위의 Chunk를 내려받는 것이므로 너무 빈번하게 요청이 발생하지 않도록 트래픽에 대한 조절도 잘 되고 있다는 것을 알 수 있습니다.


결론


이 기법은 HTTP 표준을 기반으로 동작하는 것이므로, 제대로 구현이 되어있기만 하다면, Dependency Injection이나 Inversion of Control 등의 기법을 통하여 여러 Cloud Object Storage 상의 파일들을 마치 로컬에 있는 자원을 가져다 사용하는 것과 같이 투명하게 관리할 수 있습니다. 저수준의 I/O가 가능하므로 여기서 예로 든 ZIP 파일에 대한 부분 요청 이외에도 동영상이나 미디어 스트리밍 등에서도 활용할 수 있는 여지가 많고, 무엇보다도 중요한 것은 이 모든 요청이 REST API 이기 때문에 여전히 Windows Azure Storage의 컨테이너나 BLOB에 대한 보안 정책이나 Shared Access Signature 등의 요소와 유연하게 연동되므로, 리소스에 대한 시간 제한을 통하여 인프라의 능력을 이용한 DRM을 자연스럽게 구현할 수 있고, 중간 전송 매개체로 HTTPS를 사용하도록 결정하면 송수신 보안도 자동으로 해결되므로 유용한 면이 있습니다.


여기서 예로 든 Microsoft Word 문서의 활용은 기본이고, 만약 여러분이 필요로 하시는 ZIP 컨테이너 기반의 파일 I/O 작업을 지금 여기에서처럼 클라우드 상의 object storage 상으로 옮겨가서 작업하는 것도 가능하니 많이 활용하셔서 도움을 얻으시기를 바랍니다.

댓글 남기기