Боль, которую мы все знаем
Анализируете хранилище и находите десятки копий одного файла? Пользователи загружают одинаковые документы, и вот уже:
? Хранилище раздувается на десятки процентов
⏳ Бэкапы хранят лишнее вместо того чтобы хранить нужное
? Данные теряют консистентность - разные модели ссылаются на разные копии
? Деньги за место улетают впустую
Я сталкивался с этой проблемой в каждом первом с половиной проекте. Поэтому сделал пакет, который можно добавлять в Laravel-проекты хранить и мигрировать Legacy-файлы без дубликатов.
✨Laravel Storage Dedupler
Dedupler — Laravel-пакет, который автоматически предотвращает дубликаты файлов через SHA-1 хеширование.
⚙️Как это работает изнутри
Каждый файл получает уникальный SHA-1 отпечаток
$hash = sha1_file($file->getPathname());
Хеш есть в БД → возвращаем существующий файл
Хеша нет → сохраняем и создаём запись
Все модели ссылаются на один физический файл
?Quick Start нового проекта без лишних копий
Подключаем и устанавливаем
composer require maxkhim/laravel-storage-dedupler
php artisan dedupler:install
Используем Dedupler через трейт
Используя полиморфную магию Laravel можно указать трейт у любой модели и все файлы во всех моделях будут уникальны.
// Используем в модели
class Post extends Model
{
use Deduplable;
}
И далее во всех точках вызова для сохранения и "прикрепления" файла к модели:
// Загружаем файлы
$uniqueFile = $post->storeUploadedFile($file); // Физически сохраняется один раз
// Загружаем ещё раз
$uniqueFile = $post->storeUploadedFile($sameFile); // Возвращает существующую запись
// Загружаем из локального хранилища
$uniqueFile = $post->storeLocalFile($absolutePathToFile); // Возвращает существующую запись
// Загружаем файл из переменных
$uniqueFile = $post->storeContentFile($content, $fileName); // Возвращает существующую запись
Или без прикрепления к моделям через фасад
$uniqueFile = Dedupler::storeFromPath($absolutePathToFile);
$uniqueFile = Dedupler::storeFromUploadedFile($file);
$uniqueFile = Dedupler::storeFromContent($content, $fileName);
Структура хранения
storage/
└── deduplicated/
└── da/
└── 39/
└── da39a3ee5e6b4b0d3255bfef95601890afd80709.pdf
Сборка мусора
php artisan dedupler:prune --help
Миграция структуры Legacy-проектов
Выполняем миграцию legacy структуры на хранилище без дубликатов (файлы в первоначальных местах заменяются симлинками на новое расположение в дедуплицированом хранилище)
php artisan dedupler:migrate-legacy --help
Произвольный кейс из боевого проекта
CMS для медиа-портала
Пакет был испробован для анализа архивных изображений
Было найдено: 35k дубликатов изображений (из 475k файлов)
Освобождено: 1GB (из 12GB)
Отдедуплено: за 32 мин
Планы по развитию
Дополнительные методы RestAPI
Расширение консольных команд для бэнчмарка оценки полезности дедупликации, миграции из структуры Legacy проектов
Улучшение производительности для больших файлов
Попробуйте в деле
GitHub: https://github.com/maxkhim/laravel-storage-dedupler
Packagist: https://packagist.org/packages/maxkhim/laravel-storage-dedupler
Документация: в README.md
P.S. Первые 5 качественных Issue (сообщения об ошибках или предложения функций) получат упоминания в релизных нотах! ?
P.S.S Пакет заапрувили Laravel News, это вдохновляет на дальнейшее развитие!
maxkhim Автор
Всем привет, автор здесь. Вижу, что статью читают - уже 90 просмотров за 2 часа!
Но пока тишина в комментариях.
Старался сделать акцент на технической стороне, миграции legacy-проектов и потенциальной пользе. Если есть конкретные вопросы - с радостью отвечу!
Давайте запустим дискуссию:
• Кто уже сталкивался с проблемой дубликатов файлов?
• Если да, какие решения пробовали до этого?
• Есть ли опыт миграции legacy-хранилищ?