Bootiful Azure:对象存储服务 (5/6)

工程 | Josh Long | 2019年1月17日 | ...

这是关于面向 Spring 开发人员的 Microsoft Azure 的一个 6 部分系列的第 5 部分,每周一和周四发布新文章。如果没有微软的 Asir Vedamuthu Selvasingh、Yitao Dong、Bruno Borges、Brian Benz 和 Theresa Nguyen 的投入,我将无法完成此项工作。您可以在 Github 上找到本系列的代码。在您阅读这些内容时,可以通过 Twitter (@starbuxman)向我提出任何反馈或问题。您还可以在我的 Spring Tips (@SpringTipsLive) 系列文章 Bootiful Azure 中了解有关 Microsoft Azure 的更多信息。

以下是所有部分

现在让我们转向一些更……普通的东西。理想情况下,您甚至不必经常考虑这些东西。应用程序通常有存储需求:它们可能需要存储上传的用户内容(如图片或文档等二进制数据)、生成的工件(如 PDF 文件、视频、音乐等)。它们可能希望存储日志。不难想到应用程序可能想要持久存储的东西。

这些应用程序可以使用文件系统,例如本地计算机上的文件系统或网络附加文件系统,例如 NFS(网络文件系统)。我将使用 NFS 来泛指任何网络附加文件系统,例如 Samba、NFS(使用 NFS 协议挂载的文件系统)本身,或旧版选项(如 DAC、FAL 等)。NFS 选项为文件提供类似文件系统的接口,通常采用分层格式。NFS 选项很有趣,因为它们类似于我们都熟悉的文件系统,而且每个人都知道如何使用文件系统,对吧?当然,所有内容都看起来像 Windows 资源管理器中表达的层次结构?或者 macOS Finder?除了,它们看起来完全不一样……

仔细想想,当我说 NFS 选项类似于文件系统时,我不得不加上“类似”。有些支持比其他更细致的权限模型。有些支持对附加到树中文件和目录的元数据进行编码和复制。支持为不同的操作提供不同的速度保证;某些文件系统可能会针对读取或写入进行优化。有些可能会针对目录遍历进行优化。根据使用的客户端,客户端对文件读取或写入的看法是不同的。(写入是否立即在所有复制节点上保持一致?)

即使我们假设我们想要写入的所有文件系统都与 POSIX 兼容 - 您可以使用int open(const char *path, int flags)java.io.File - 对于我们的客户端来说,情况可能并非如此。如果客户端不“理解”文件系统,而希望以其他方式操作数据怎么办?如果客户端只能使用 HTTP 协议呢?或者如果它希望使用 Bittorrent 通过对等网络更有效地合并下载呢?

出于这些原因以及更多其他原因,Amazon Web Services 引入了 S3,即简单云存储服务(明白了吗?“S”乘以 3?“S3”?)它已成为所有其他云供应商都需要支持的一种普遍标准。对于 Microsoft Azure,对象存储服务 (OSS) 是提供类似 S3 体验的事物。它不是 POSIX 文件系统。您可以直接使用其 API,就像我们在这里一样,但您也可以使用 S3Proxy 使用 AWS S3 客户端代理写入 OSS,其中有无数个!Azure 的对象存储服务确实很无聊,这正是您在处理像文件式数据的持久卷这样基础事物时所希望的。它甚至提供了一个名为 Microsoft Azure 存储资源管理器 的独立浏览器,它(没错!)可以在 Linux、Macintosh 和 Windows 上运行。该独立浏览器允许您以及 CosmosDB 数据一起查询 OSS 存储。这是否足够方便?您当然可以使用az CLI 或 API 本身。我们将使用 Spring 集成来使用 Java API。

配置 Azure 对象存储服务

您必须创建一个分配给现有资源组bootiful 的 Azure 对象存储服务帐户 (bootiful)。然后,创建一个分配给刚刚创建的存储帐户的存储容器 (files)。以下是一个示例脚本。

#!/usr/bin/env bash

rg=$1
accountname=bootiful

az storage account create --name ${accountname} --resource-group ${rg}
az storage container create -n files --account-name ${accountname}

使用以下命令确定连接到应用程序所需的连接字符串。

az storage account show-connection-string --resource-group bootiful --name bootiful

请注意以后要使用的连接字符串。

将 Azure 对象存储服务引入您的 Spring 应用程序

com.microsoft.azure: azure-storage-spring-boot-starter 添加到应用程序的构建文件中。确保您已为azure.storage.connection-string 属性指定了 OSS 连接字符串。

我们将读取应用程序src/main/resources 目录中猫的图像的字节,然后将这些字节作为“块 Blob”写入对象存储服务。您可以通过其他接口与 OSS 交互,但出于我们的目的,将其视为“容器”(事物的逻辑分组,几乎类似于 S3 中的目录或存储桶)和“Blob”的集合非常自然。Blob 本质上是一个文件,具有与其关联的名称和元数据。以下示例所做的全部工作就是将猫的照片的字节存储到名为files 的容器中,其名称以cat- 为前缀,以.jpg 为后缀。

package com.example.bootifulazure;

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.UUID;

@Log4j2
@Component
class ObjectStorageServiceDemo {

    private final CloudStorageAccount cloudStorageAccount;
    private final Resource resource;
    private final CloudBlobContainer files;

    ObjectStorageServiceDemo(
        CloudStorageAccount csa,
        @Value("classpath:/cat.jpg") Resource cat) throws URISyntaxException, StorageException {
        this.resource = cat;
        this.cloudStorageAccount = csa;
        this.files = this.cloudStorageAccount
            .createCloudBlobClient()
            .getContainerReference("files");
    }

    @EventListener(ApplicationReadyEvent.class)
    public void demo() throws Exception {
        CloudBlockBlob blockBlobReference = this.files.getBlockBlobReference("cat-" + UUID.randomUUID().toString() + ".jpg");
        try (InputStream in = this.resource.getInputStream()) {
            blockBlobReference.upload(in, this.resource.contentLength());
            log.info("uploaded blockblob to " + blockBlobReference.getStorageUri());
        }

    }
}

Microsoft Azure 特定的部分并非微不足道。我们获取对容器的引用,然后写入它,然后记录资源的可寻址 URI。多么普通!这正是您在像文件系统这样的计算系统原语中想要的。它应该是普通的。说实话,我更高兴能够使用 Java 7 的 try-with-resources 语法来处理Autocloseable InputStream 引用!

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部