
В прошлой статье из облачного цикла я законспектировал всю основную теорию по облакам: их типы, преимущества и недостатки. Теперь пора переходить к облачным хранилищам.
Типы облачных хранилищ
Рассмотрю все три типа хранилищ: 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