Giter VIP home page Giter VIP logo

storage's Introduction

.NET Core NuGet NuGet codecov CodeFactor

Клиент для S3

Привет! Это обертка над HttpClient для работы с S3 хранилищами. Мотивация создания была простейшей - я не понимал, почему клиенты AWS и Minio едят так много памяти. Результат моих экспериментов: скорость почти как у Minio, а памяти потребляю почти в 200 раз меньше, чем клиент для AWS.

BenchmarkDotNet v0.13.12, Debian GNU/Linux 12 (bookworm) (container)
Unknown processor
.NET SDK 8.0.204
[Host]   : .NET 8.0.4 (8.0.424.16909), Arm64 RyuJIT AdvSIMD
.NET 8.0 : .NET 8.0.4 (8.0.424.16909), Arm64 RyuJIT AdvSIMD

Job=.NET 8.0  Runtime=.NET 8.0
Method Mean Ratio Gen0 Gen1 Allocated Alloc Ratio
Aws 1.497 s 1.45 80 000 6 000 201 728.07 KB 333.24
Minio 1.468 s 1.43 - - 279 532.97 KB 461.76
Storage 1.031 s 1.00 - - 605.36 KB 1.00

Создание клиента

Для работы с хранилищем необходимо создать клиент.

var storageClient = new S3Client(new S3Settings
{
    AccessKey = "ROOTUSER",
    Bucket = "mybucket",
    EndPoint = "localhost",     // для Yandex.Objects это "storage.yandexcloud.net"
    Port = 9000,                // стандартный порт Minio - 9000, для Yandex.Objects указывать не нужно
    SecretKey = "ChangeMe123",
    UseHttps = false,           // для Yandex.Objects укажите true
    UseHttp2 = false            // Yandex.Objects позволяет работать по HTTP2, можете указать true
})

Minio предоставляет playground для тестирования (порт для запросов всё тот же - 9000). Ключи можно найти в документации. Доступ к Amazon S3 не тестировался.

Операции с S3 bucket

Создание bucket'a

Мы передаём название bucket'a в настройках, поэтому дополнительно его вводить не надо.

bool bucketCreateResult = await storageClient.CreateBucket(cancellationToken);
Console.WriteLine(bucketCreateResult
    ? "Bucket создан"
    : "Bucket не был создан");

Проверка существования bucket'a

Как и в прошлый раз, мы знаем название bucket'a, так как мы передаём его в настройках клиента.

bool bucketCheckResult = await storageClient.IsBucketExists(cancellationToken);
if (bucketCheckResult) Console.WriteLine("Bucket существует");

Удаление bucket'a

bool bucketDeleteResult = await storageClient.DeleteBucket(cancellationToken);
if (bucketDeleteResult) Console.WriteLine("Bucket удалён");

Операции с S3 object

Напомню, что объект в смысле S3 это и есть файл.

Создание файла

Создание, то есть загрузка файла в S3 хранилище, возможна двумя путями: можно разбить исходные данных на кусочки ( multipart), а можно не разбивать. Самый простой способ загрузки файла - воспользоваться следующим методом (если файл будет больше 5 МБ, то применяется multipart):

bool fileUploadResult = await storageClient.UploadFile(fileName, fileContentType, fileStream, cancellationToken);
if (fileUploadResult) Console.WriteLine("Файл загружен");

Управление Multipart-загрузкой

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

using S3Upload upload = await storageClient.UploadFile(fileName, fileType, cancellationToken);

await upload.AddParts(stream, cancellationToken); // загружаем части документа
if (!await upload.AddParts(byteArray, cancellationToken)) { // загружаем другую часть документа
    await upload.Abort(cancellationToken); // отменяем загрузку
}
else {
    await upload.Complete(cancellationToken); // завершаем загрузку
}

В коде клиента именно эту логику использует метод PutFileMultipart. Конкретную реализацию можно подсмотреть в нём.

Получение файла

StorageFile fileGetResult = await storageClient.GetFile(fileName, cancellationToken);
if (fileGetResult) {
    Console.WriteLine($"Размер файла {fileGetResult.Length}, контент {fileGetResult.ContetType}");
    return await fileGetResult.GetStream(cancellationToken);
}
else {
    Console.WriteLine($"Файл не может быть загружен, так как {fileGetResult}");
}

Получение файла как Stream

var fileStream = await storageClient.GetFileStream(fileName, cancellationToken);

В случае, если файл не существует, возвратится Stream.Null.

Проверка существования файла

bool fileExistsResult = await storageClient.IsFileExists(fileName, cancellationToken);
if (fileExistsResult) {
	Console.WriteLine("Файл существует");
}

Создание подписанной ссылки на файл

Метод проверяет наличие файла в хранилище S3 и формирует GET запрос файла. Параметр expiration должен содержать время валидности ссылки начиная с даты формирования ссылки.

string? preSignedFileUrl = storageClient.GetFileUrl(fileName, expiration);
if (preSignedFileUrl != null) {
	Console.WriteLine($"URL получен: {preSignedFileUrl}");
}

Существует не безопасный способ создать ссылку, без проверки наличия файла в S3.

string preSignedFileUrl = await storageClient.BuildFileUrl(fileName, expiration, cancellationToken);

Удаление

Удаление объекта из S3 происходит почти мгновенно. На самом деле в S3 хранилище просто ставится задача на удаление и клиенту возвращается результат. Кстати, если удалить файл, который не существует, то ответ будет такой же, как если бы файл существовал. Поэтому этот метод ничего не возвращает.

await storageClient.DeleteFile(fileName, cancellationToken);
Console.WriteLine("Файл удалён, если он, конечно, существовал");

Измерение производительности и тестирование

Локальное измерение производительности и тестирование осуществляется с помощью Minio в Docker'e по http. Понимаю, что это не самый хороший способ, но зато он самый доступный и простой.

  1. Файл docker-compose для локального тестирования можно найти в репозитории.
  2. Запускаем docker-compose up -d. Если всё хорошо, то бенчмарк заработает в Docker'e.
  3. Если нужно запустить бенчмарк локально, то обращаем внимание на файл appsettings.json. В нём содержатся основные настройки для подключения к Minio.
  4. Свойство BigFilePath файла appsettings.json сейчас не заполнено. Его можно использвоать для загрузки реального файла (больше 100МБ). Если свойство не заполнено, то тест сгенерирует случайную последовательность байт размером 123МБ в памяти.

Вопросы

У меня есть канал в TG: @csharp_gepard. К нему привязан чат - вопросы можно задавать в чате, либо в любом из последних постов.

storage's People

Contributors

antomys avatar teoadal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.