Armazenamento de Blobs não estruturado (criando aplicativos de nuvem Real-World com o Azure)

por Rick Anderson, Tom Dykstra

Baixar Corrigir Projeto ou Baixar Livro Eletrônico

O livro eletrônico Building Real World Cloud Apps with Azure é baseado em uma apresentação desenvolvida por Scott Guthrie. Ele explica 13 padrões e práticas que podem ajudá-lo a desenvolver aplicativos Web para a nuvem com êxito. Para obter informações sobre o livro eletrônico, consulte o primeiro capítulo.

No capítulo anterior, examinamos os esquemas de particionamento e explicamos como o aplicativo Fix It armazena imagens no serviço Blob de Armazenamento do Azure e outros dados de tarefa no banco de dados SQL do Azure. Neste capítulo, nos aprofundamos no serviço Blob e mostramos como ele é implementado no código do projeto Corrigir.

O que é Armazenamento de Blobs?

O serviço Blob de Armazenamento do Azure fornece uma maneira de armazenar arquivos na nuvem. O serviço Blob tem várias vantagens em relação ao armazenamento de arquivos em um sistema de arquivos de rede local:

  • É altamente escalonável. Uma única conta de armazenamento pode armazenar centenas de terabytes e você pode ter várias contas de armazenamento. Alguns dos maiores clientes do Azure armazenam centenas de petabytes. O Microsoft SkyDrive usa o armazenamento de blobs.
  • É durável. Todos os arquivos armazenados no serviço Blob são copiados em backup automaticamente.
  • Ele fornece alta disponibilidade. O SLA para Armazenamento promete 99,9% ou 99,99% de tempo de atividade, dependendo da opção de redundância geográfica escolhida.
  • É um recurso de PaaS (plataforma como serviço) do Azure, o que significa que você apenas armazena e recupera arquivos, pagando apenas pela quantidade real de armazenamento usada e o Azure cuida automaticamente da configuração e do gerenciamento de todas as VMs e unidades de disco necessárias para o serviço.
  • Você pode acessar o serviço Blob usando uma API REST ou usando uma API de linguagem de programação. Os SDKs estão disponíveis para .NET, Java, Ruby e outros.
  • Ao armazenar um arquivo no serviço Blob, você pode disponibilizá-lo publicamente facilmente pela Internet.
  • Você pode proteger arquivos no serviço Blob para que eles possam ser acessados somente por usuários autorizados ou fornecer tokens de acesso temporários que os disponibilizam para alguém apenas por um período limitado.

Sempre que você estiver criando um aplicativo para o Azure e quiser armazenar muitos dados que, em um ambiente local, entrariam em arquivos , como imagens, vídeos, PDFs, planilhas etc. – considere o serviço Blob.

Criando uma conta de armazenamento

Para começar a usar o serviço Blob, crie uma conta de Armazenamento no Azure. No portal, clique em CriaçãoRápida do Novo -- Armazenamento -- deServiços -- de Dados e insira uma URL e um local de data center. O local do data center deve ser o mesmo que seu aplicativo Web.

Criar um acct de armazenamento

Você escolhe a região primária em que deseja armazenar o conteúdo e, se escolher a opção de replicação geográfica , o Azure criará réplicas de todos os seus dados em um data center diferente em outra parte do país/região. Por exemplo, se você escolher o data center oeste dos EUA, ao armazenar um arquivo, ele irá para o data center oeste dos EUA, mas em segundo plano o Azure também o copiará para um dos outros data centers dos EUA. Se ocorrer um desastre em uma parte do país/região, seus dados ainda estarão seguros.

O Azure não replicará dados entre limites geopolíticos: se sua localização primária estiver nos EUA, seus arquivos serão replicados apenas para outra região nos EUA; se o local principal for a Austrália, seus arquivos serão replicados apenas para outro data center na Austrália.

É claro que você também pode criar uma conta de Armazenamento executando comandos de um script, como vimos anteriormente. Aqui está um comando Windows PowerShell para criar uma conta de armazenamento:

# Create a new storage account
New-AzureStorageAccount -StorageAccountName $Name -Location $Location -Verbose

Depois de ter uma conta de Armazenamento, você poderá iniciar imediatamente o armazenamento de arquivos no serviço Blob.

Usando o Armazenamento de Blobs no aplicativo Corrigir

O aplicativo Corrigir permite que você carregue fotos.

Criar uma tarefa Corrigir

Quando você clica em Criar o FixIt, o aplicativo carrega o arquivo de imagem especificado e o armazena no serviço Blob.

Configurar o contêiner de Blob

Para armazenar um arquivo no serviço Blob, você precisa de um contêiner para armazená-lo. Um contêiner do serviço Blob corresponde a uma pasta do sistema de arquivos. Os scripts de criação de ambiente que examinamos no capítulo Automatizar Tudo criam a conta de Armazenamento, mas não criam um contêiner. Portanto, a finalidade do CreateAndConfigure método da PhotoService classe é criar um contêiner se ele ainda não existir. Esse método é chamado do Application_Start método em Global.asax.

public async void CreateAndConfigureAsync()
{
    try
    {
        CloudStorageAccount storageAccount = StorageUtils.StorageAccount;

        // Create a blob client and retrieve reference to images container
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference("images");

        // Create the "images" container if it doesn't already exist.
        if (await container.CreateIfNotExistsAsync())
        {
            // Enable public access on the newly created "images" container
            await container.SetPermissionsAsync(
                new BlobContainerPermissions
                {
                    PublicAccess =
                        BlobContainerPublicAccessType.Blob
                });

            log.Information("Successfully created Blob Storage Images Container and made it public");
        }
    }
    catch (Exception ex)
    {
        log.Error(ex, "Failure to Create or Configure images container in Blob Storage Service");
    }
}

O nome da conta de armazenamento e a appSettings chave de acesso são armazenados na coleção do arquivo Web.config e o StorageUtils.StorageAccount código no método usa esses valores para criar uma cadeia de conexão e estabelecer uma conexão:

string account = CloudConfigurationManager.GetSetting("StorageAccountName");
string key = CloudConfigurationManager.GetSetting("StorageAccountAccessKey");
string connectionString = String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", account, key);
return CloudStorageAccount.Parse(connectionString);

Em CreateAndConfigureAsync seguida, o método cria um objeto que representa o serviço Blob e um objeto que representa um contêiner (pasta) chamado "imagens" no serviço Blob:

CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("images");

Se um contêiner chamado "imagens" ainda não existir , o que será verdadeiro na primeira vez que você executar o aplicativo em uma nova conta de armazenamento , o código criará o contêiner e definirá permissões para torná-lo público. (Por padrão, novos contêineres de blob são privados e podem ser acessados somente para usuários que têm permissão para acessar sua conta de armazenamento.)

if (await container.CreateIfNotExistsAsync())
{
    // Enable public access on the newly created "images" container
    await container.SetPermissionsAsync(
        new BlobContainerPermissions
        {
            PublicAccess =
                BlobContainerPublicAccessType.Blob
        });

    log.Information("Successfully created Blob Storage Images Container and made it public");
}

Armazenar a foto carregada no Armazenamento de Blobs

Para carregar e salvar o arquivo de imagem, o aplicativo usa uma IPhotoService interface e uma implementação da interface na PhotoService classe . O arquivo PhotoService.cs contém todo o código no aplicativo Fix It que se comunica com o serviço Blob.

O método do controlador MVC a seguir é chamado quando o usuário clica em Criar o FixIt. Nesse código, photoService refere-se a uma instância da PhotoService classe e fixittask refere-se a uma instância da classe de FixItTask entidade que armazena dados para uma nova tarefa.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "FixItTaskId,CreatedBy,Owner,Title,Notes,PhotoUrl,IsDone")]FixItTask fixittask, HttpPostedFileBase photo)
{
    if (ModelState.IsValid)
    {
        fixittask.CreatedBy = User.Identity.Name;
        fixittask.PhotoUrl = await photoService.UploadPhotoAsync(photo);
        await fixItRepository.CreateAsync(fixittask);
        return RedirectToAction("Success");
    }

    return View(fixittask);
}

O UploadPhotoAsync método na PhotoService classe armazena o arquivo carregado no serviço Blob e retorna uma URL que aponta para o novo blob.

public async Task<string> UploadPhotoAsync(HttpPostedFileBase photoToUpload)
{            
    if (photoToUpload == null || photoToUpload.ContentLength == 0)
    {
        return null;
    }

    string fullPath = null;
    Stopwatch timespan = Stopwatch.StartNew();

    try
    {
        CloudStorageAccount storageAccount = StorageUtils.StorageAccount;

        // Create the blob client and reference the container
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference("images");

        // Create a unique name for the images we are about to upload
        string imageName = String.Format("task-photo-{0}{1}",
            Guid.NewGuid().ToString(),
            Path.GetExtension(photoToUpload.FileName));

        // Upload image to Blob Storage
        CloudBlockBlob blockBlob = container.GetBlockBlobReference(imageName);
        blockBlob.Properties.ContentType = photoToUpload.ContentType;
        await blockBlob.UploadFromStreamAsync(photoToUpload.InputStream);

        // Convert to be HTTP based URI (default storage path is HTTPS)
        var uriBuilder = new UriBuilder(blockBlob.Uri);
        uriBuilder.Scheme = "http";
        fullPath = uriBuilder.ToString();

        timespan.Stop();
        log.TraceApi("Blob Service", "PhotoService.UploadPhoto", timespan.Elapsed, "imagepath={0}", fullPath);
    }
    catch (Exception ex)
    {
        log.Error(ex, "Error upload photo blob to storage");
    }

    return fullPath;
}

Como no CreateAndConfigure método , o código se conecta à conta de armazenamento e cria um objeto que representa o contêiner de blob "imagens", exceto que aqui ele pressupõe que o contêiner já existe.

Em seguida, ele cria um identificador exclusivo para a imagem prestes a ser carregada, concatenando um novo valor guid com a extensão de arquivo:

string imageName = String.Format("task-photo-{0}{1}",
    Guid.NewGuid().ToString(),
    Path.GetExtension(photoToUpload.FileName));

Em seguida, o código usa o objeto de contêiner de blob e o novo identificador exclusivo para criar um objeto de blob, define um atributo nesse objeto indicando que tipo de arquivo ele é e, em seguida, usa o objeto blob para armazenar o arquivo no armazenamento de blobs.

CloudBlockBlob blockBlob = container.GetBlockBlobReference(imageName);
blockBlob.Properties.ContentType = photoToUpload.ContentType;
blockBlob.UploadFromStream(photoToUpload.InputStream);

Por fim, ele obtém uma URL que faz referência ao blob. Essa URL será armazenada no banco de dados e poderá ser usada nas páginas da Web Corrigir para exibir a imagem carregada.

fullPath = String.Format("http://{0}{1}", blockBlob.Uri.DnsSafeHost, blockBlob.Uri.AbsolutePath);

Essa URL é armazenada no banco de dados como uma das colunas da tabela FixItTask.

public class FixItTask
{
    public int FixItTaskId  { get; set; }
    public string CreatedBy { get; set; }
    [Required]
    public string Owner     { get; set; }
    [Required]
    public string Title     { get; set; }
    public string Notes     { get; set; }
    public string PhotoUrl  { get; set; }
    public bool IsDone      { get; set; } 
}

Com apenas a URL no banco de dados e as imagens no Armazenamento de Blobs, o aplicativo Fix It mantém o banco de dados pequeno, escalonável e barato, enquanto as imagens são armazenadas onde o armazenamento é barato e capaz de lidar com terabytes ou petabytes. Uma conta de armazenamento pode armazenar centenas de terabytes de fotos corrigir e você paga apenas pelo que usa. Assim, você pode começar pequeno pagando 9 centavos para o primeiro gigabyte, e adicionar mais imagens para centavos por gigabyte adicional.

Exibir o arquivo carregado

O aplicativo Corrigir exibe o arquivo de imagem carregado quando exibe detalhes de uma tarefa.

Corrigir detalhes da tarefa com a foto

Para exibir a imagem, tudo o que o modo de exibição MVC precisa fazer é incluir o PhotoUrl valor no HTML enviado ao navegador. O servidor Web e o banco de dados não estão usando ciclos para exibir a imagem, eles estão apenas servindo alguns bytes para a URL da imagem. No código Razor a seguir, Model refere-se a uma instância da FixItTask classe de entidade.

<fieldset>
<legend>@Html.DisplayFor(model => model.Title)</legend>
<dl>
    <dt>Opened By</dt>
    <dd>@Html.DisplayFor(model => model.CreatedBy)</dd>
                <br />
    <dt>@Html.DisplayNameFor(model => model.Notes)</dt>
    <dd>@Html.DisplayFor(model => model.Notes)</dd>
                <br />
                @if(Model.PhotoUrl != null) {
        <dd><img src="@Model.PhotoUrl" title="@Model.Title" /></dd>
                }
</dl>
</fieldset>

Se você examinar o HTML da página exibida, verá a URL apontando diretamente para a imagem no armazenamento de blobs, algo assim:

<fieldset>
<legend>Brush the dog again</legend>
<dl>
    <dt>Opened By</dt>
    <dd>Tom</dd>
                <br />
    <dt>Notes</dt>
    <dd>Another dog brushing task</dd>
                <br />
    <dd>
<img src="http://storageaccountname.blob.core.windows.net/images/task-photo-312dd635-ba87-4542-8b15-767032c55f4e.jpg" 
           title="Brush the dog again" />
    </dd>
</dl>
</fieldset>

Resumo

Você viu como o aplicativo Fix It armazena imagens no serviço Blob e apenas URLs de imagem no banco de dados SQL. O uso do serviço Blob mantém o banco de dados SQL muito menor do que seria de outra forma, possibilita escalar verticalmente para um número quase ilimitado de tarefas e pode ser feito sem escrever muito código.

Você pode ter centenas de terabytes em uma conta de armazenamento e o custo de armazenamento é muito menos caro do que Banco de Dados SQL armazenamento, começando em cerca de 3 centavos por gigabyte por mês mais uma pequena taxa de transação. E tenha em mente que você não está pagando pela capacidade máxima, mas apenas pelo valor que realmente armazena, para que seu aplicativo esteja pronto para ser dimensionado, mas você não está pagando por toda essa capacidade extra.

No próximo capítulo , falaremos sobre a importância de tornar um aplicativo de nuvem capaz de lidar normalmente com falhas.

Recursos

Para obter mais informações, consulte os seguintes recursos: