Прежде чем начну, должен оставить
В этой статье хотел бы разобрать слой, который отвечает за хранение файлов, и как это может быть использовано любым человеком.
В предыдущей статье я немного "накатил бочку" на ipfs, но это произошло именно в контексте решаемой мной задачи. В целом, я считаю этот проект крутым. Просто мне больше нравится возможность создавать разные сети под разные задачи. Это позволяет лучше организовывать структуру и снижать нагрузку на отдельные узлы и сеть в целом. Можно даже в рамках одного какого-то проекта, при необходимости, дробить сеть на куски по каким-то критериям, снижая общую нагрузку.
Итак, storacle использует механизм
- Файлы могут добавляться в хранилище через любой узел.
- Файлы сохраняются целиком, не блоками.
- У каждого файла есть свой уникальный хэш по содержимому для дальнейшей работы с ним.
- Файлы могут дублироваться для большей надежности
- Количество файлов на одном узле ограничено только файловой системой (есть исключение, о нем пониже будет)
- Количество файлов в сети ограничено возможностями 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 и изоморфен, его можно использовать прямо из браузера.
Можно загрузить файл
Отложенные ссылки
Интересной фичей также является "отложенная ссылка". Это ссылка на файл, которую можно получить синхронно, здесь и сейчас, а файл подтянется когда уже будет найден в хранилище. Это очень удобно, когда, например, нужно показать на сайте какие-то картинки. Просто проставляем в 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, чтобы добавить файл. Все экшены можно найти в
Зачем тебе это может быть нужно
- Если ты хочешь создать какой-то децентрализованный проект, в котором планируется хранить и работать с файлами удобными методами. Например, проект с музыкой, описанный по ссылке в начале статьи, использует storacle.
- Если ты работаешь над любыми другими проектами, где нужно хранить файлы распределенно. Ты можешь легко выстроить свою закрытую сеть, гибко настраивать узлы и добавлять новые, когда это нужно.
- Если тебе просто нужно где-то хранить файлы своего сайта и тебе влом писать все самому. Возможно эта библиотека подойдет лучше других, в твоем случаи.
- Если у тебя проект, в котором ты работаешь с файлами, но хочешь все манипуляции совершать из браузера. Ты можешь избежать написания серверного кода.
Мои контакты:
Источник: habr.com