Облачные хранилища: основы. Примеры работы с облаками из Java

В прошлой статье из облачного цикла я законспектировал всю основную теорию по облакам: их типы, преимущества и недостатки. Теперь пора переходить к облачным хранилищам.

Типы облачных хранилищ

Рассмотрю все три типа хранилищ: block, object и file и покажу, как с ними работать в программе на джаве.

Block Storage

Примеры: Amazon EBS (Elastic Block Store), Azure Managed Disks, Google Persistent Disks

Самый старый и самый простой способ хранения данных. В таких хранилищах данные находятся в блоках фиксированного размера без метаданных. Похоже на жёсткий диск с кластерами, который управляется из ОС, и такие хранилища так же управляются приложениями.

Приложения имеют доступ к блокам с помощью SCSI («скази») – Small Computer System Interface – это стандарт интерфейса для подключения и обмена данными между компьютером и периферийными устройствами.

Такие хранилища обеспечивают высокую производительность и подходят для баз данных или виртуальных машин.

При работе с блочным хранилищем через приложения администратора или разработчика не интересуют номера блоков, в которых хранятся данные, все эти детали скрыты под капотом. Поэтому для работы с таким диском он просто монтируется в системе, как новый носитель, и джава-разработчик может обращаться к нему, как к любому другому диску:

public class BlockStorageExample {

    public static void main(String[] args) throws IOException {

        Path filePath = Paths.get("/mnt/data/storage.txt");

        // Создание файла
        Files.writeString(filePath, "Hello from Block Storage!");

        // Проверка существования
        if (Files.exists(filePath)) {
            System.out.println("File created on block storage.");
        }

        // Чтение
        String content = Files.readString(filePath);
        System.out.println("Read from block storage: " + content);
    }
}

File Storage

Примеры: Amazon EFS, Azure Files, Google Filestore, Dropbox

Файлы организованы в иерархии каталогов, как в привычной файловой системе. Обращение к файлам производится через файловые протоколы (NFS, SMB), но и эти подробности часто скрыты от пользователя облаков.

Работа в джаве с таким хранилищем ничем не отличается от блочных. Мы также обращаемся с хранилищем, как с обычным диском. Читаем и пишем файлы:

     public class FileStorageExample {
        public static void main(String[] args) throws IOException {
            Path filePath = Paths.get("/mnt/data/storage.txt");

            // Пишем файл
            Files.writeString(filePath, "Hello from file Storage!");

            // Проверка существования
            if (Files.exists(filePath)) {
                System.out.println("File created on file storage.");
            }
            // Читаем файл
            String content = Files.readString(path);
            System.out.println("Read from file storage: " + content);
        }
    }

Object Storage

Примеры: Amazon S3, Azure Blob Storage, Google Cloud Storage

В сравнении с блочным хранилищем, объектное – более новая технология. Такое хранилище связывает данные с настраиваемыми метаданными (идентификатор). Такие системы хорошо масштабируются, и легко будет справиться с ситуацией, если количество объектов будет зашкаливать.

Они хорошо подходят для хранения и чтения данных, поэтому используются для бэкапов или хранения медиа-файлов, по содержимому которых нельзя производить прямой поиск. А вот по их метаданным вполне можно. Пример таких данных:

{
  "ObjectID": "1",
  "Data": "<binary>",
  "Metadata": {
    "Content-Type": "image/jpeg",
    "Created-By": "zimowski",
    "Access-Level": "public"
  }
}

Доступ к данным в таком хранилище идёт через API. Рассмотрим пример работы с амазоновским облаком. В джава-приложении сначала нужно добавить зависимость в Maven:

<dependency>
  <groupId>software.amazon.awssdk</groupId>
  <artifactId>s3</artifactId>
  <version>2.25.0</version> 
</dependency>

После этого можно начинать работу. Запишем и прочитаем изображение example.jpg.

public class ObjectStorageExample {
        public static void main(String[] args) {
            String bucketName = "example-bucket";
            S3Client s3 = S3Client.builder()
                    .region(Region.EU_CENTRAL_1)
                    .credentialsProvider(ProfileCredentialsProvider.create())
                    .build();

            try {
                // Загрузка изображения в S3 с пользовательскими метаданными
                PutObjectRequest putRequest = PutObjectRequest.builder()
                        .bucket(bucketName)
                        .key("images/example.jpg")
                        .contentType("image/jpeg")
                        .metadata(Map.of("hru", "mu"))
                        .build();

                s3.putObject(putRequest, Paths.get("/user/example.jpg"));

                // Получение метаданных
                HeadObjectRequest headRequest = HeadObjectRequest.builder()
                        .bucket(bucketName)
                        .key("images/example.jpg")
                        .build();

                HeadObjectResponse headResponse = s3.headObject(headRequest);
                System.out.println("Content-Type: " + headResponse.contentType());
                headResponse.metadata().forEach((k, v) -> System.out.println(k + ": " + v));

                //Скачивание изображения
                GetObjectRequest getRequest = GetObjectRequest.builder()
                        .bucket(bucketName)
                        .key("images/example.jpg")
                        .build();

                ResponseInputStream<GetObjectResponse> s3Object = s3.getObject(getRequest);
                Files.copy(s3Object, Paths.get("downloaded-example.jpg"));

                // Чтение изображения
                BufferedImage image = ImageIO.read(new File("downloaded-example.jpg"));
                if (image != null) {
                    System.out.println("Image:");
                    System.out.println("Width: " + image.getWidth());
                    System.out.println("Height: " + image.getHeight());
                } else {
                    System.out.println("No image.");
                }

            } catch (Exception e) {
                System.err.println(e.getMessage());
                e.printStackTrace();
            }
        }
}

В этом примере сначала мы загрузили изображение в облако с пользовательскими метаданными (hru: mu). Потом прочитали метаданные с HeadObjectResponse, а после скачали сам файл с GetObjectRequest и прочитали уже с диска.

Здесь используется ImageIO.read, но изображение можно прочитать и как массив байтов:

    ResponseBytes<GetObjectResponse> objectBytes = s3.getObjectAsBytes(request);
    byte[] imageBytes = objectBytes.asByteArray();

Конечно, не обязательно качать файл перед тем, как его прочитать. Можно было сделать это напрямую из облака.

     GetObjectRequest getRequest = GetObjectRequest.builder()
                .bucket(bucketName)
                .key("images/example.jpg")
                .build();

      ResponseInputStream<GetObjectResponse> s3Object = s3.getObject(getRequest);
      BufferedImage image = ImageIO.read(s3Object);

Текстовые файлы тоже можно читать.

      GetObjectRequest request = GetObjectRequest.builder()
               .bucket(bucketName)
               .key("text.txt")
               .build();

      ResponseInputStream<GetObjectResponse> inputStream = s3.getObject(request);

      BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
      String line;
      while ((line = reader.readLine()) != null) {
           System.out.println(line);
      }

Выбор подходящего хранилища обусловлен многими требованиями бизнеса. Но начать стоит начать с понимания, сколько, чего и зачем будете хранить.

Какой требуется объём? Нужно ли его будет увеличивать? Потом, какой тип хранилища требуется (какие данные будут там храниться)? И потом какая требуется производительность?

Ответы на большинство этих вопросов можно дать только проанализировав конкретный проект. Но этот мой конспект явно отвечает на вопрос по типу хранилища:

Block Storage – для БД и системных дисков.
File Storage – для совместной работы с файлами.
Object Storage – для масштабируемого хранения и доступа по API (бэкапы, изображения, логика через метаданные)


Темой следующего облачного конспекта будут сети.

2 Comments

Оставить комментарий