Storacle — децентрализованное хранилище файлов

Storacle — децентрализованное хранилище файлов

Прежде чем начну, должен оставить ссылку на предыдущую статью, чтобы было понятно о чем именно речь.

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

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

Итак, storacle использует механизм spreadable для организации сети. Основные особенности:

  • Файлы могут добавляться в хранилище через любой узел.
  • Файлы сохраняются целиком, не блоками.
  • У каждого файла есть свой уникальный хэш по содержимому для дальнейшей работы с ним.
  • Файлы могут дублироваться для большей надежности
  • Количество файлов на одном узле ограничено только файловой системой (есть исключение, о нем пониже будет)
  • Количество файлов в сети ограничено возможностями spreadable по числу допустимых узлов в сети, которые во второй версии смогут позволять работать с бесконечным числом узлов (об этом в другой статье)

Простой пример, как это вообще работает из программы:

Сервер:

const  Node = require('storacle').Node;

(async () => {
  try {
    const node = new Node({
      port: 4000,
      hostname: 'localhost'
    });
    await node.init();
  }
  catch(err) {
    console.error(err.stack);
    process.exit(1);
  }
})();

Клиент:

const  Client = require('storacle').Client;

(async () => {
  try {
    const client = new  Client({
      address: 'localhost:4000'
    });
    await client.init();
    const hash = await client.storeFile('./my-file');
    const link = await client.getFileLink(hash); 
    await client.removeFile(hash);
  }
  catch(err) {
    console.error(err.stack);
    process.exit(1);
  }
})();

Взгляд изнутри

Под капотом ничего сверхъестественного. Информация о количестве файлов, совокупном их размере и прочие моменты хранятся в in-memory базе и обновляются при удалении и добавлении файлов, поэтому необходимости часто обращаться к файловой системе нет. Исключением является включение сборщика мусора, когда нужна циркуляция файлов при достижении каких-то размеров хранилища, а не запрет на добавление новых. В этом случае приходится обходить хранилище, и работа с большим количеством файлов(> миллиона скажем) может приводить к существенным нагрузкам. И лучше хранить поменьше файлов и запускать побольше узлов. Если "чистильщик" отключен, то такой проблемы нет.

Хранилище файлов представляет собой 256 папок и 2 уровня вложенности. Файлы хранятся в папках второго уровня. То есть при наличии 1млн. файлов в каждой такой папке будет около 62500 штук (1000000 / sqrt(256)).

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

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

Кэширование

При добавлении файлов, а также при их получении, в кэш записываются ссылки на файлы.
Благодаря этому очень часто нет необходимости обходить всю сеть в поисках файла. Это ускоряет получение ссылок и уменьшает нагрузку на сеть. Также кэширование происходит через http заголовки.

Изоморфность

Клиент написан на javascript и изоморфен, его можно использовать прямо из браузера. 
Можно загрузить файл https://github.com/ortexx/storacle/blob/master/dist/storacle.client.js как скрипт и получить доступ к window.ClientStoracle либо импортить через систему сборки и.т.п.

Отложенные ссылки

Интересной фичей также является "отложенная ссылка". Это ссылка на файл, которую можно получить синхронно, здесь и сейчас, а файл подтянется когда уже будет найден в хранилище. Это очень удобно, когда, например, нужно показать на сайте какие-то картинки. Просто проставляем в src отложенную ссылку и все. Кейсов можно придумать много.

Api клиента

  • async Client.prototype.storeFile() — сохранение файла
  • async Client.prototype.getFileLink() — получение прямой ссылки на файл
  • async Client.prototype.getFileLinks() — получение списка прямых ссылок на файл со всех узлов, где он есть
  • async Client.prototype.getFileToBuffer() — получить файл в буфер
  • async Client.prototype.getFileToPath() — получить файл в файловую систему
  • async Client.prototype.getFileToBlob() — получить файл в blob(для браузерной версии)
  • async Client.prototype.removeFile() — удалить файл
  • Client.prototype.createRequestedFileLink() — создать отложенную ссылку

Экспорт файлов на другой сервер

Для того, чтобы перенести файлы на другой узел можно:

  • Просто скопировать всю папку хранилища вместе с настройками. (в будущем это может не работать)
  • Скопировать только папку с файлами. Но, в этом случаи, нужно будет один раз запустить функцию node.normalizeFilesInfo(), чтобы пересчитать все данные и занести в базу.
  • Использовать функцию node.exportFiles(), которая начнет копирование файлов.

Основные настройки узла
Запуская узел хранилища, можно указать все необходимые настройки.
Опишу самые основные, остальное можно найти на гитхабе.

  • storage.dataSize — размер папки с файлами
  • storage.tempSize — размер временной папки
  • storage.autoCleanSize — минимальный размер хранилища, который нужно удерживать. Если указать этот параметр, то как только места начнет не хватать наиболее малоиспользуемые файлы будут удаляться.
  • file.maxSize — максимальный размер файла
  • file.minSize — минимальный размер файла
  • file.preferredDuplicates — предпочтительное количество дубликатов файла в сети
  • file.mimeWhitelist — допустимые типы файла
  • file.mimeBlacklist — недопустимые типы файла
  • file.extWhitelist — допустимые расширения файла
  • file.extBlacklist — недопустимые расширения файла
  • file.linkCache — различные настройки кэширования ссылок

Почти все параметры, связанные с размерами могут проставляться и в абсолютных и в относительных величинах.

Работа через командную строку
Библиотеку можно использовать через командную строку. Для этого нужно установить ее глобально: npm i -g storacle. После этого можно запускать нужные экшены из директории с проектом, где узел. Например, storacle -a storeFile -f ./file.txt -c ./config.js, чтобы добавить файл. Все экшены можно найти в https://github.com/ortexx/storacle/blob/master/bin/actions.js

Зачем тебе это может быть нужно

  • Если ты хочешь создать какой-то децентрализованный проект, в котором планируется хранить и работать с файлами удобными методами. Например, проект с музыкой, описанный по ссылке в начале статьи, использует storacle.
  • Если ты работаешь над любыми другими проектами, где нужно хранить файлы распределенно. Ты можешь легко выстроить свою закрытую сеть, гибко настраивать узлы и добавлять новые, когда это нужно.
  • Если тебе просто нужно где-то хранить файлы своего сайта и тебе влом писать все самому. Возможно эта библиотека подойдет лучше других, в твоем случаи.
  • Если у тебя проект, в котором ты работаешь с файлами, но хочешь все манипуляции совершать из браузера. Ты можешь избежать написания серверного кода.

Мои контакты:

Источник: habr.com