Сократить бэкапы на 99.5% с hashget

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


    Это обзорная статья для описания возможностей. Само использование hashget (довольно простое) описано в README проекта и wiki-документации.


    Сравнение


    По закону жанра, начну сразу с интриги — сравнения результатов:


    Data sample unpacked size .tar.gz hashget .tar.gz
    Wordpress-5.1.1 43 Mb 11 Mb ( 26% ) 155 Kb ( 0.3% )
    Linux kernel 5.0.4 934 Mb 161 Mb ( 20% ) 4.7 Mb ( 0.5% )
    Debian 9 (LAMP) LXC VM 724 Mb 165 Mb ( 23% ) 4.1 Mb ( 0.5% )

    Предыстория, каким должен быть идеальный и эффективный бэкап


    Каждый раз, когда я делал бэкап свежесозданной виртуалки, мне не давало покоя чувство, что я что-то делаю не так. Почему у меня получается увесистый бэкап от системы, где моего бесценного нетленного творчества — однострочный index.html с текстом "Hello world"?


    Почему в моем бэкапе есть 16-мегабайтный /usr/sbin/mysqld? Неужели в этом мире именно мне выпала честь хранить этот важный файл, и если я не справлюсь — он будет потерян для человечества? Скорее всего нет. Он хранится на высоконадежных серверах debian (надежность и бесперебойность которых ни в какое сравнение не идет с тем, что могу обеспечить я), а также в резервных копиях (миллионах их) других админов. Точно ли нам нужно создавать для повышения надежности 10 000 000 + 1'ую копию этого важного файла?


    В общем-то hashget и решает эту проблему. При запаковке — он создает очень маленький бэкап. При распаковке — полностью распакованную систему, аналогичную той, которая была бы при tar -c / tar -x. (Иными словами, это lossless упаковка)


    Как работает hashget


    В hashget есть понятия Package и HashPackage, с их помощью он выполняет дедупликацию.


    Package (пакет). Файл (обычно архив .deb или .tar.gz), который можно надежно скачать из сети, и из которого можно получить один или более файлов.


    HashPackage — небольшой JSON файл, представляющий Package, в том числе содержащий URL пакета и хеш-суммы (sha256) файлов из него. Например, для пакета mariadb-server-core размером 5 мегабайт размер hashpackage всего 6 килобайт. Примерно в тысячу раз меньше.


    Дедупликация — создание архива без дублированных файлов (если дедупликтор знает, где может быть скачан оригинал пакета, он сокращает дубли из архива).


    Запаковка


    При запаковке просматриваются все файлы из пакуемого каталога, считаются их хеш-суммы, и если сумма найдена в одном из известных HashPackage, то метаданные о файле (имя, хеш, права доступа итд) сохраняются в особый файл .hashget-restore.json, который тоже будет включен в архив.


    Сама запаковка в простейшем случае выглядит не сложнее tar'а:


    hashget -zf /tmp/mybackup.tar.gz --pack /path/to/data

    Распаковка


    Распаковка делается в два этапа. Сначала обычная tar распаковка:


    tar -xf mybackup.tar.gz -C /path/to/data

    затем восстановление из сети:


    hashget -u /path/to/data

    При восстановлении hashget читает файл .hashget-restore.json, скачивает необходимые пакеты, распаковывает их, и извлекает необходимые файлы, устанавливая их на нужные пути, с нужными owner/group/permissions.


    Более сложные вещи


    То, что описано выше — уже достаточно, для тех, кому "хочу как tar, но чтобы упаковал мой Debian в 4 мегабайта". Дальше посмотрим более сложные вещи.


    Индексирование


    Если у hashget совсем не было б ни одного HashPackage, то он просто не смог бы ничего дедуплицировать.


    Создать HashPackage можно и вручную (просто: hashget --submit https://wordpress.org/wordpress-5.1.1.zip -p my), но есть путь удобнее.


    Для того чтобы получить нужные hashpackage, есть этап индексирования (он автоматически выполняется при команде --pack) и эвристики. При индексировании hashget "скармливает" каждый найденный файл всем имеющимся эвристикам, которым он интересен. Эвристики затем могут проиндексировать какой-либо Package, чтобы создать HashPackage.


    Например, дебиановская эвристика любит файл /var/lib/dpkg/status и обнаруживает установленные debian пакеты, и если они не проиндексированы (для них не созданы HashPackage), скачивает и индексирует их. Получается очень приятный эффект — hashget всегда будет эффективно дедуплицировать дебиановские ОС, даже если на них есть самые новые пакеты.


    Файлы-подсказки (хинты)


    Если в вашей сети используется какой-то ваш проприетарный пакет или публичный пакет, который не включен в эвристики hashget, вы можете добавить в него простой hint-файл hashget-hint.json по образцу:


    {
        "project": "wordpress.org",
        "url": "https://ru.wordpress.org/wordpress-5.1.1-ru_RU.zip"
    }

    Далее, каждый раз при создании архива пакет будет проиндексирован (если не был ранее), и файлы пакета будут дедуплицированы из архива. Не нужно никакого программирования, все можно сделать из vim и сэкономить в каждом бэкапе. Заметьте, что благодаря подходу через хешсуммы, если какие-то файлы из пакета будут изменены локально (например, изменен файл конфигурации) — то измененные файлы сохранятся в архиве "как есть" не буду сокращены.


    Если какой-то ваш собственный пакет обновляется периодически, но изменения не очень большие, можно делать hint только для основных версий. Например, в версии 1.0 сделали хинт с указанием на mypackage-1.0.tar.gz, и она будет полностью дедуплицироваться, затем выпустили версию 1.1, которая немного отличается, а хинт не обновили. Ничего страшного. Дедуплицируются только файлы, которые совпадают (которые можно восстановить) с версией 1.0.


    Эвристика, которая обрабатывает hint-файл — хороший пример для понимания внутреннего механизма работы эвристик. Он обрабатывает только файлы hashget-hint.json (или .hashget-hint.json с точкой) и игнорирует все остальные. По этому файлу он определяет, какой URL пакета должен быть проиндексирован, и hashget его индексирует (если этого не было сделано раньше)


    HashServer


    Было бы довольно трудоемко при создании бэкапов полностью выполнять индексирование. Для этого нужно скачать каждый пакет, распаковать, проиндексировать. Поэтому hashget использует схему с HashServer. При обнаружении установленного debian'овского пакета, если он не найдется в локальных HashPackage, сначала делается попытка просто скачать HashPackage с хеш-сервера. И только если это не получается — hashget сам скачивает и хеширует пакет (и загружает на hashserver, чтобы в дальнейшем hashserver его предоставлял).


    HashServer — не обязательный элемент схемы, не критичный, служит исключительно для ускорения и снижения нагрузки на репозитории. Легко отключается (опцией --hashserver без параметров). Кроме того, легко можно сделать свой собственный hashserver.


    Инкрементальные и дифференциальные бэкапы, запланированное устаревание


    hashget позволяет очень просто сделать схему инкрементальных и дифференциальных бэкапов. Почему бы нам не проиндексировать сам наш бэкап (со всеми нашими уникальными файлами)? Одна команда --submit и все готово! Следующий бэкап, который создаст hashget, не будет включать файлы из этого архива.


    Но это не очень хороший подход, потому что может оказаться так, что при восстановлении нам придется дергать все hashget-бэкапы за всю историю (если в каждом будет хотя бы один уникальный файл). Для этого есть механизм запланированного устаревания бэкапов. При индексировании можно указать дату устаревания HashPackage --expires 2019-06-01, и по наступлению этой даты (c 00:00), он не будет использован. Сам архив можно после этой даты не удалять (Хотя hashget может удобно показать URLы всех бекапов, которые у нас протухли/протухнут на данный момент или на любую дату).


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


    Если так же будем индексировать и новые бэкапы — будет схема инкрементальных бэкапов.


    В отличие от традиционных схем, hashget позволяет использовать несколько базовых источников. Бекап будет сокращен и за счет сокращения файлов из предыдущих бэкапов (если они есть), и за счет публичных файлов (то, что можно выкачать).


    Если мы по какой-то причине не доверяем надежности дебиановских ресурсов (https://snapshot.debian.org/) или использует другой дистрибутив, мы просто можем один раз сделать полный бэкап со всеми пакетами, и далее опираться уже на него (отключив эвристику). Теперь, если все сервера наших дистрибутивов окажутся нам недоступны (в сувенирном Интернете или при зомби-апокалипсисе), но наши бэкапы будут в порядке — мы сможем восстановиться из любого короткого дифф-бэкапа, опирающегося только на наши более ранние бэкапы.


    Hashget опирается только на надежные источники восстановления по ВАШЕМУ усмотрению. Какие вы считаете надежными — те и будут использованы.

    FilePool и Glacier


    Механизм FilePool позволяет не обращаться постоянно к внешним серверам для скачивания пакетов, а использовать пакеты из локального каталога или корпоративного сервера, например:


    $ hashget -u . --pool /tmp/pool

    или


    $ hashget -u . --pool http://myhashdb.example.com/

    Чтобы сделать пул в локальном каталоге — достаточно просто создать каталог и накидать в него файлов, hashget сам по хешам найдет то, что ему нужно. Чтобы сделать пул доступным через HTTP, нужно специальным образом создать симлинки, это делается одной командой (hashget-admin --build /var/www/html/hashdb/ --pool /tmp/pool). Сам HTTP FilePool — это статичные файлы, так что обслуживать его может любой простейший вебсервер, нагрузка на сервер почти нулевая.


    Благодаря FilePool в качестве базовых ресурсов можно использовать не только ресурсы на http(s), но и, к примеру, Amazon Glacier.


    После аплоада бэкапа на гласьер получаем его Upload ID и используем его в качестве URL. Например:


    hashget --submit Glacier_Upload_ID --file /tmp/my-glacier-backup.tar.gz --project glacier --hashserver --expires 2019-09-01

    Теперь новые (дифференциальные) бэкапы будут опираться на этот бэкап и будут короче. После tar распаковки диффбэкапа мы можем посмотреть, на какие ресурсы он опирается:


    hashget --info /tmp/unpacked/ list

    и просто шелл-скриптом скачать из гласьера все эти файлы в pool и запустить обычное восстановление: hashget -u /tmp/unpacked --pool /tmp/pool


    Стоит ли овчинка выделки


    В простейшем случае — вы просто будете меньше платить за бэкапы (если вы их храните где-то в облаке за деньги). Может быть — гораздо-гораздо меньше.


    Но это не единственное. Количество переходит в качество. Можете использовать это, чтобы получить качественный апгрейд схемы бэкапов. Например, раз бэкапы у нас теперь короче — можно делать не ежемесячный бэкап, а ежедневный. Хранить их не полгода, как ранее, а 5 лет. Раньше хранили в медленном но дешевом "холодном" хранилище (Glacier), теперь можете хранить в горячем, откуда можно всегда быстро скачать бэкап и восстановиться за минуты, а не за день.


    Можно увеличить надежность хранения бэкапов. Если сейчас мы их храним в одном хранилище, то сократив объем бэкапов — сможем хранить в 2-3 хранилищах и безболезненно пережить, если одно из них повредится.


    Как попробовать и начать пользоваться?


    Заходим на гитлаб страничку https://gitlab.com/yaroslaff/hashget, устанавливаем одной командой (pip3 install hashget[plugins]) и просто читаем-выполняем quick-start. Думаю, все простые вещи сделать — займет минут 10-15. Затем можно попробовать пожать свои виртуалки, сделать, если надо, хинт-файлы, чтобы ужималось сильнее, поиграться с пулами, локальной базой хешей и хешсервером, если интересно будет, а на следующий день посмотреть, каков будет размер инкрементального бэкапа поверх вчерашнего.


    Restic + HashGet


    (Эта глава добавлена позже. Спасибо комментаторам за критику и мотивацию.)


    Есть хороший удобный инструмент для бэкапов — restic. Он тоже может выполнять дедупликацию, но только в пределах репозитория, не умеет внешнюю дедупликацию, которую легко делает hashget. Но в сочетании restic + hashget у нас получается использовать плюсы обоих подходов!


    Подготовка (распакуем wordpress и проиндексируем его):


    # wget -q https://wordpress.org/wordpress-5.2.2.tar.gz
    # hashget --submit https://wordpress.org/wordpress-5.2.2.tar.gz -p my --file wordpress-5.2.2.tar.gz --hashserver
    # tar -xf wordpress-5.2.2.tar.gz
    # du -sh wordpress
    46M wordpress

    Добавление снапшота в restic через


    # hashget -X exclude-list --prepack wordpress --hashserver
    Saved: 1468 files, 1 pkgs, size: 40.5M. Download: 10.7M
    
    # restic --exclude-file exclude-list backup wordpress
    password is correct
    scan [/tmp/wp/wordpress]
    scanned 193 directories, 367 files in 0:02
    [0:04] 100.00%  700.829 KiB / 700.829 KiB  560 / 560 items  0 errors  ETA 0:00 
    duration: 0:04
    snapshot 76b54230 saved
    
    # du -sh /tmp/restic-repo/
    2,1M    /tmp/restic-repo/

    На этом этапе мы добавили снапшот каталога (40+ Mb), и размер репозитория увеличился всего на 1 Mb.


    Восстановление делается двумя командами:


    # restic restore 76b54230 -t unpacked
    password is correct
    restoring <Snapshot 76b54230 of [/tmp/wp/wordpress] at 2019-06-19 04:30:55.760618336 +0700 +07 by root@braconnier> to unpacked
    # hashget -u unpacked/wordpress/ --hashserver
    Recovered 1468/1468 files 40.5M bytes (0 downloaded, 0 from pool, 10.7M cached) in 1.56s
    Поделиться публикацией

    Комментарии 40

      +1

      Интересная идея.
      Как определяется http-ссылка на "оригинал"?
      Что будет, если дистрибутив/пакет экзотический и его нигде нет?
      Что будет, если ссылки на оригинал протухнут?

        +4
        Как определяется http-ссылка на «оригинал»?

        Она указывается при submit пакета. Если пакет индексируется по хинтам, то ссылка берется из хинта. Если это debian, то эвристика генерирует ссылку на пакет на shapshot.debian.org. (Он живет уже примерно 10 лет, и все ссылки даже на древние пакеты живые и неизменные).

        Встроена только поддержка debian и исходных кодов linux kernel (и то, этот плагин больше как демонстрация, как писать свои эвристические плагины). Даже wordpress, который используется для примера в README добавляется пользователем (либо хинтом, либо вручную).

        Что будет, если дистрибутив/пакет экзотический и его нигде нет?

        Если вы вот сейчас такую экзотику возьмете и просто сходу запакуете — эффективность будет нулевая (получится обычный архив .tar.gz того же размера). А если добавите сами (через --submit) то будет тот URL, который укажете.

        Если нужно просто сделать 1 раз бэкап — то и даже не стоит заморачиваться с дедупликацией экзотики — просто пакуете как есть. Если экзотика толстая, а бэкапов много (много серверов, или один сервер, но бэкапы периодические) — то варианта два:
        1) Красивый — просто где-то выкладываете дистрибутив этой экзотики. Например, там же, где у вас бэкапы, и его сабмитите. Теперь он уже есть и в надежном месте.
        2) Простой — используете дифф. бэкапы. Экзотика уйдет в первый бэкап. Его проиндексировали, и во втором ее уже не будет (будет только метаинформация о каждом файле).

        Что будет, если ссылки на оригинал протухнут?

        Не надо такого допускать. Вопрос примерно аналогичен «Как мне обновить Apache на своем Debian/CentOS если эти проекты уже закрыты, их сервера лежат, а их разработчики расстреляны». В этом случае — ситуация сложная. Так что в первую очередь — такая ситуация не должна происходить. Если делаем бэкапы — опираемся на то, чему мы можем доверять. Если мы даже дебиану и вордпрессу не верим — опираемся только на свои прежние бэкапы.

        Но если вдруг такое случилось и сегодня, скажем, wordpress закрылся и сайты перестали работать — скорее всего вы про это узнаете. Просто нужно либо перестать использовать эти hashpackage / сделать свой вордпресс как выше описал про экзотику. Как только вы сделаете первый бэкап, который не опирается на умершие ресурсы — вы в безопасности. В таком случае мир рухнет, а ваша система бэкапов будет работать! :-)

        Если уж вообще пессимистичный сценарий рассматривать (вы вернулись из космоса, а тут ядерный апокалипсис, но есть бэкапы) — в каждом бэкапе в hashget-restore есть суммы и всех пакетов и всех файлов. Можно их где-то взять (нагуглить, выменять у панков на харлеях и багги за воду и топливо), свалить все в pool, и из него восстановить. hashget сам разберется, посчитает hash для всего и будет get нужные файлы :-)

        Но еще раз скажу — это не штатная ситуация (как восстанавливать побитый диск), надо не на нее ориентироваться, а на ее предотвращение. Шанс, что за время жизни бэкапа рухнет проект wordpress или debian или какой-то еще — крошечный, но все таки есть. Но вот вероятность того, что рухнет какой-то из таких проектов и в тот же день еще и ваш сервер полетит (который нужно из бэкапа восстанвливать) — она уже совсем принебрежимо мала. Гораздо более вероятна угроза того, что мир-то уцелел, а вот ваши личные бэкапы потерялись (побился диск, не проплатили сервису хранения) — тут hashget позволяет решить гораздо более вероятную проблему.

        0

        А какой смысл хранить бэкап всей файловой системы, если эту самую систему всегда можно просто переустановить? Разве что ради более быстрого восстановления (и то ещё не факт), но если это настолько критично, то это, как мне кажется, указывает на серьёзные организационные проблемы.

          0
          Под хорошей организацией вы имеете в виду четкое описание схемы восстановления, в виде «Поставить пакет apache версии именно 2.4.25-3+deb9u7 (она у нас точно проверена), в нем создать виртуальный хост example.com, с DocumentRoot /var/www/virtual/example.com/» и так далее? (Чтобы не только админ, который ставил и у него «руки помнят», но и любой другой по ней восстановил однозначно такую же машину)

          Так hashget как раз это и делает, как вы хотите! Инструкция называется .hashget-restore.json, и указывает, что откуда скачать, какой файл куда положить, какие права доступа поставить, какие крон-задачи настроить итд. И отлично описывает даже очень сложные сервера с диким зоопарком ПО.

          Только если человек может ошибиться в описании, пропустить что-то (и мы никак не узнаем, что у нас «серьезные организационные проблемы», пока не восстановимся из бэкапа, и не увидим, что что-то у нас не работает и разберемся мы через неделю только), то программа более точная и внимательная, тут вероятность сбоя (коллизии sha256, 2^256) какие-то астрономические квадриллионы триллионов.
            +3
            Так hashget как раз это и делает, как вы хотите!

            Только вот этим должен заниматься админ в виде, например, написания Ansible-плейбуков.


            может ошибиться в описании

            Поэтому администрирование сервера должно быть ПОЛНОСТЬЮ автоматизированным с самого первого дня существования сервера, например, через те же Ansible-плейбуки. Перед любыми действиями пишем/обновляем плейбук, проверяем на staging-сервере и потом на прод — таким образом гарантируется, что описание актуальное и безошибочное. Я перевёл все подконтрольные мне серверы на такую схему, и на фоне этого hashget смотрится бессмысленным костылём.


            (Кто-нибудь наверняка ещё всякие докеры вспомнит, кстати, но лично я контейнерами не пользуюсь)


            И отлично описывает даже очень сложные сервера с диким зоопарком ПО.

            То есть у вас никто не помнит, что же там на серверах стоит и как настроено, и все полагаются на hashget? Именно это и есть серьёзные организационные проблемы. У меня весь мой зоопарк чётко описан плейбуками.

              +1
              То есть у вас никто не помнит

              Более того — я убежден, что никто и не должен помнить! Кто помнит — может забыть, перепутать, заболеть, умереть или еще хуже — уволиться.

              У нас бывает так, что давний заказчик приходит и говорит «хочу странное...» и сказать ему «это не красиво, пошел вон, и не нужны нам твои грязные деньги» — не всегда можно. Деньги любим. У бизнеса свои потребности, и они не всегда совпадают с желаниями админов, как сделать проще-красивее.

              Ансибл — чудесно, но дикий оверкилл по трудозатратам. Если через ansible управлять десятками однотипных серверов — тогда это конечно же окупается. А вот если один сервер — то зачем? Чем ansible скрипт для восстановления лучше, надежнее hashget скрипта? Я вижу у него только недостатки.
                0
                никто и не должен помнить!

                Да. Помнить должна документация, ну или самодокументирующийся код в виде того же Ansible-плейбука. Плейбук ничего не забудет.


                Ансибл — чудесно, но дикий оверкилл по трудозатратам.

                Почему? У меня каждый плейбук управляет ровно одним сервером (не считая staging), и я очень доволен и оверкилла не вижу (кроме затрат на изучение самого ансибла).


                хочу странное

                И снова серьёзные организационные проблемы :)


                Чем ansible скрипт для восстановления

                Не восстановления. Установки. Когда есть возможность быстро и автоматически установить систему с нуля — никакое восстановление не нужно, только базу данных после установки загрузить, условно говоря. Следовательно, и hashget не нужен — ту же базу можно бэкапить более «традиционными» средствами, чем я у себя и занимаюсь.


                Пока что получается, что вы hashget'ом затыкаете серьёзные организационные проблемы)

                  0
                  Тут мы даже не про hashget спорим сейчас, а о подходе ansible vs tar. hashget — просто способ ужать tar.

                  Как вы оцениваете, за сколько времени вы бы вручную справились с задачей поставить новый сервер и запустить на нем какую-нибудь средней сложности CMSку? И второе — ваша же оценка, но вы делаете еще и ansible скрипт и набор тестов, которые проверяют, что ansible скрипт хорошо отработал? Второе ведь явно больше — насколько?

                    0

                    Ну, если вы настолько спешите, что не можете себе позволить потратить время на написание плейбука, то окей. У меня, к счастью, время есть. Буду считать, что hashget — для тех, кому некогда)


                    насколько?

                    Не настолько, чтобы это начало меня беспокоить и я начал его замерять, поэтому ответить не могу.

                      0
                      Для меня просто разница — примерно на порядок. Что-то поставить — допустим, час. Написать плейбук для этого — 10 часов минимум. (хотя больше — если что-то по инструкции ставится целый час — это явно что-то очень сложное, замудренное, не просто скачать-распаковать). А время — деньги. То, что можно сделать заказчику за сумму в X, приходится делать за 10*X (или 100*X).

                      А еще у нас есть сервак, где 3 или 4 постфикса на одной машине крутятся, настолько там нетрадиционная конфигурация… Сколько времени я бы писал плейбук для нее — страшно представить. Конфигурация ужасная — я с вами соглашусь. Но заказчик не хочет вчетверо увеличивать расходы на сервера ради красоты.

                      И обслуживать… обслуживать tar архив — даже звучит немного смешно. Что-то изменили на сервере — ночью оно сам в новом бэкапе появиться. А вот любое изменение при ansible подходе — придется в плейбуке снова разбираться и править его. И протестировать. А если вы уволитесь?

                      При этом в результате, при восстановлении, tar нам железно даст ту же систему, байт-в-байт. Ansible — в лучшем случае, если мы нигде не ошиблись (вы-то может быть и не ошибаетесь, а я вот — бывает) — даст то же самое. В плане восстановления тут легко сравнить — если два подхода дают одинаковый результат — значит каждый из них подходит.

                      Если заказчики готовы платить больше, оплачивать это время — отлично. Всем бы таких заказчиков! Но у нас, как вы верно сказали — «некогда». В нашей ситуации хорошая организация — это когда поставленная задача выполняется в короткие сроки и дешево, а плохая была бы, если б я ко всем затратам времени (= денег) из любви к красоте нолик начал приписывать. :-)
                        0
                        примерно на порядок

                        Это или по неопытности, или если установщик какой-то вещи полная дрянь


                        3 или 4 постфикса на одной машине крутятся

                        Не знаю подробностей, что как там крутится, но на первый взгляд это выглядит простым прописыванием конфигов и юнит-файлов для запуска — плейбук на первый взгляд выглядит тривиальным


                        придется в плейбуке снова разбираться и править его.

                        Если это тяжёлая задача — это опять же по неопытности, лично мне править плейбуки одно удовольствие


                        И протестировать.

                        А ручные изменения не надо тестировать, что ли?


                        Ansible — в лучшем случае, если мы нигде не ошиблись

                        Работающий сервер — гарантия того, что не ошиблись. Если, конечно, никто не лазил своими шаловливыми ручками на сервер в обход Ansible и не вызывал тем самым рассинхрон плейбука с реальным состоянием сервера, но за это надо больно по рукам давать


                        Но у нас, как вы верно сказали — «некогда»

                        Наверно, на этом можно и закончить, всё равно мы останемся при своих мнениях)

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

            Разные архиваторы вроде умеют в инкрементальность. Тут она на стероидах, но надо разворачивать инфраструктуру и конфигурить. Интересно и специфично)
            Ps: промахнулся и поставил минус статье. Как отменить?

              0
              Тут, как мне кажется, нет никакой лишней работы. Наоборот, все делалось как альтернатива tar'у со сравнимой «сложностью» использования. Вместо -c/-x, тут --pack, --unpack.

              Многое описано просто, чтобы пояснить механику. Для использования — достаточно иметь смутное представление об этом (как водитель справляется с руль-газ-тормоз, но знать что там под капотом — не обязательно)

              По правилу Парето, чтобы выжать 90% возможностей при 10% усилий — нужно освоить только одну команду `--submit`, вот она:

              hashget --submit https://wordpress.org/wordpress-5.1.1.zip -p my --hashserver --expires 2019-07-01
              


              Один раз такое сделали — все, файлы из этого архива будут «выучены» и сокращены в будущих архивах.

              Если еще освоите ключ `--exclude` сможете исключать из архива логи и временные файлы (примерно как аналогичный ключик у tar).

              Все. Теперь вы знаете о hashget почти все нужное, можете делать инкрементальные бэкапы, дифференциальные, добавлять собственные пакеты, внешние, итд. Ужимать 700 мегабайт в 4. :-) tar тоже ведь мало кто знает все ключики, но нам достаточно зазубренных пары ключей и все.

              Отменить — не знаю, попробуйте дважды может быть плюсануть?
                0

                По описанию похоже на докер. Тот тоже содержит единую базу образов, локальная версия является разницей с базовым образом на сервере.

                  0
                  Да, сильно близко к этому. Только у докера (может быть путаю) они оверлеями, кажется. То есть, каждая версия базируется на одной предыдущей и diff от нее. Как в обычных дифф-бэкапах.

                  А у hashget — на нескольких базах. Например, сделаем submit двух пакетов, бросим их в один каталог, и запакуем hashget — получится почти пустой архив. Вот проверил, засабмитил 2 разных архива:
                  hashget --submit https://ru.wordpress.org/wordpress-5.2.1-ru_RU.zip -p my --hashserver
                  hashget --submit https://ru.wordpress.org/wordpress-5.2-ru_RU.zip -p my --hashserver
                  

                  Затем оба положил в каталог просто не распаковывая и зажал. Архив обоих файлов — 25 мегабайт в 500 байт ровно (это в 50 000 раз):

                  $ hashget -zf test.tar.gz --pack x --hashserver
                  STEP 1/3 Indexing...
                  Indexing done in 0.59s. 0 local + 0 pulled + 0 new = 0 total packages
                  total=0 local=0 pulled=0 new=0
                  STEP 2/3 prepare exclude list for packing...
                  Saved: 2 files, 2 pkgs, size: 24.5M. Download: 24.5M
                  STEP 3/3 tarring...
                  x (24.5M) packed into test.tar.gz (500.0)
                  
                  $ ls -l test.tar.gz
                  -rw-r--r-- 1 xenon xenon 500 июн 17 10:08 test.tar.gz
                  


                  В архиве — только 1 файл .hashget-restore.json с описанием 2 файлов:
                  .hashget-restore.json
                  {
                      "files": [
                          {
                              "atime": 1560766079,
                              "ctime": 1560766079,
                              "file": "wordpress-5.2.1-ru_RU.zip",
                              "gid": 1001,
                              "mode": 420,
                              "mtime": 1560603629,
                              "sha256": "0bee89fbaa1cc1c849393ef219bfe512f682bb69e6be44c267d139ae437dce42",
                              "size": 12854138,
                              "uid": 1001
                          },
                          {
                              "atime": 1560766086,
                              "ctime": 1560766086,
                              "file": "wordpress-5.2-ru_RU.zip",
                              "gid": 1001,
                              "mode": 420,
                              "mtime": 1558152353,
                              "sha256": "3f73c559c9f21c908ec7df112d129833ca1fe63cf02431dc24cc2123672ec859",
                              "size": 12849541,
                              "uid": 1001
                          }
                      ],
                      "packages": [
                          {
                              "hash": "sha256:0bee89fbaa1cc1c849393ef219bfe512f682bb69e6be44c267d139ae437dce42",
                              "url": "https://ru.wordpress.org/wordpress-5.2.1-ru_RU.zip"
                          },
                          {
                              "hash": "sha256:3f73c559c9f21c908ec7df112d129833ca1fe63cf02431dc24cc2123672ec859",
                              "url": "https://ru.wordpress.org/wordpress-5.2-ru_RU.zip"
                          }
                      ],
                      "packagesize": 25703679,
                      "packagesize_exact": true
                  }
                  


              0
              Как насчет многогигабайтных дампов БД?
              От бекапа к бекапу дамп меняется слабо, однако разные бэкапы имеют разный хеш.
              Умеет эта ваша тулза такое инкрементно бэкапить?
                0
                Нет. Либо их просто бэкапить как есть, даже не пытаться дедуплицировать (просто зря будут хеши считаться — не сойдутся), либо как-то экспортировать в такой формат, чтобы пофайлово совпадали. Например, каждую запись из таблицы в свой JSON, или каждую таблицу в отдельный файл (тогда таблицы без изменений — сократятся, а с изменениями — целиком пойдут).

                Тут надо по каждой базе конкретно смотреть. Думаю, если мы исходим из того, что дельта у нас реально маленькая — то найти способ очень сильно их ужать — как-то можно, но сами файлы баз данных — так не получатся.

                Либо же не сами базы, а bin-логи использовать, они, наверное, хорошо будут дедуплицироваться. (Не пробовал).
                  0
                  Значит надо добавить как в торрентах, хэши кусков. Например, по 10 мегабайт :)
                    –1
                    А там оффсеты могут получиться разные. Все на байт сдвинется, и все пропало.
                    Уж лучше unix way, чтобы каждая тулза что-то свое делала.

                    Вообще, я не первый раз встаю перед задачей синхронизировать базы данных. Не просто перезалить (это тяжело, долго), а вот по аналогии с rsync'ом, только измененные-удаленные-новые записи. Может быть как-то от этого можно перейти к тому, чтобы оформить дифф как файл, и его уже поместить в бэкап.
                      0
                      Так есть же техники создания хэшей типа по похожести, используются в антивирусах всяких. Не могу сейчас вспомнить название :(
                        0
                        Fuzzy хеши, наверное? (когда для двух чуть различных файлов, хеш покажет разницу в 0.1% например — будет видно, что они отличаются, но незначительно).

                        У нас тут другая ситуация, если в базе данных чуть-чуть незначительно лишний нолик в балансе на счету клиента появится — вряд ли кто одобрит такой бэкап :-)
                +2
                мы просто можем один раз сделать полный бэкап со всеми пакетами, и далее опираться уже на него

                А почему не использовать решения типа borg или restic? Умная дедупликация (смещение на несколько байт не порушит хэши) и минимум места для бэкапов. Borg ещё и сжатие умеет.

                Бонус — никакой привязки ни к интернету, ни к пакетам, бэкапить можно всё что угодно, реально только первый бэкап может занять сравнительно много места, причём эффективно дедуплицируются даже файлы баз данных или образы дисков (благодаря CDC — Content Defined Chunking).

                В качестве примера — есть система с кучей медиа-контента + база с WP + много логов веб-сервера, общий объем около 380G (на этом фоне пакеты можно просто не считать, в лучшем случае 2-3G). 30 дней бэкапов занимают около 280G, при этом любой из них — полный.
                  0
                  Ну это же борг?
                  Ибо рестик не так красив, к сожалению. как минимум — не жмет, так что, в лоб бэкап не может быть меньше исходника.

                  По моим личным тестам (в репе — почти исключительно дампы баз), чемпион таки именно рестик. Но — натравленный на исходник, предварительно обработанный tar + gzip.
                    0

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


                    Я когда-то (около года назад) сравнивал borg со сзжатием и restic без… Разница на ~1.5TB данных была около 5-10% у меня. Просто из-за того что большая часть данных — фото/видео.

                      0
                      На дампах была катастрофа: в разы больше, чем тупо руками tar/gz вообще без дедупликации. То есть, делаем дамп, жмем его, кладем куда-то. Это «где-то» получается в 4-5 раз меньше репозитория restic, несмотря на дедупликацию.

                      Кстати, duplicacy, хоть он и жмет, делает это тоже хуже тупого tar/gz. в смысле, бэкап результирующий больше.
                        0
                        Может как раз из-за коротких блоков CDC? Длинные данные жмутся лучше.
                        Вот простой пример, выкачал текстовый файл, 459525 байт в чистом виде, gzip в 193944. (архив — 42.2% от исходного).

                        Режем на куски по 1000 байт (split -b 1000 /tmp/sireny.txt). gzip дает 580-620 уже. (58%-62%).

                        Режем на куски по 100 байт — и gz уже в среднем примерно по 110. (архив — 110%)
                          0
                          Гипотеза не проходит — там каждый (текстовый) файл в гигабайты размером. Коэффициент трамбовки — примерно 1:7.
                          Результат не меняется, даже если работать с всего одним файлом дампа.
                          Самый эффективный — restic предварительно gzipленного.
                          Второй — самый примитивный, пачка дампов, каждый в gzip.
                          Все остальное потом, самый худший из тестированных — restic необработанных дампов.
                    +1
                    Исходная идея за hashget — «внешняя дедупликация» (не знаю, есть ли какой-то устоявшийся термин для нее, назовем так). То есть, дедупликация не масштаба хранилища, а масштаба Интернета.

                    В hashget в принципе нет какого-то понятия вроде репозитория.

                    С hashget возможно:
                    1. Ужать (вот как выше в примере) 25Mb в 500 байт. Этот архив хранить где угодно или выслать по сети. ( Получатель сможет его распаковать. Этот крошечный архив — сам по себе достаточен. Как tar, но в эпоху Интернета.
                    2. При диффбэкапах предыдущие, конечно, нужны. Но требований к ним особых нет — это просто файлы. Например, можно хранить их в разных местах по частям или в Glacier или в сейфе. (Но перед распаковкой надо чтобы они были доступны по URL или из пула). Хранение в холодном хранилище (Glacier) гораздо дешевле, а restic так не может.
                    3. В подходе с hashget нет ничего ценного кроме самих бэкапов. Репозитория, какой-то структуры, служебных данных, которые мы боимся потерять или повредить. Единственное что есть помимо бэкапов — это база HashPackage, но ее можно пересоздать заново. Она по сути — кэш.

                    Borg мне показался более сложным решением, чем-то основательным. Совсем другая весовая категория. Hashget рядом с ним — это просто «более эффективный tar». Ну и CDC или какого-то аналога — тоже нет.
                      0
                      Но ведь то что публично доступно (и, собственно, позволяет экономить) — это меньшая часть от бэкапов, разве нет? Большую часть ведь составляют уникальные данные, более того, такие которые не выложить публично, и даже ещё хуже — эти данные (БД и подобное) меняются сравнительно часто.

                      В связи с этим вопрос — в чём выигрыш кроме как для темплейтов контейнеров или VM?

                      И другой момент — если у получателя проблемы с интернетом, то маленький размер архива hashget мало ему поможет — пакеты всё равно придётся тянуть (причём целиком — даже ради одного файла), хотя бы один раз, и это уже мало отличается от простого списка того что должно быть установлено (даже с учётом версий) + tar.gz от уникальных данных (конфигурация и тонкие настройки), плюс тут разве что в удобной среде для создания архивов.

                      И наконец — без CDC дедупликация уникального (для пользователя) контента будет не настолько эффективной, потому что изменение одного байта в одном файле приведет к новой копии всего файла (а он может оказаться очень немаленьким).

                      Что же до «холодных» копий — Glacier и его аналоги как раз плохи тем что доступны не мгновенно — т.е. hashget будет весьма тормозить на том что окажется в холодной копии, а если речь о данных (а не о пакетах) — то велик шанс что в Glacier вообще нет нужной версии файла.

                        0
                        В первую очередь, hashget делался именно для виртуалок. И, согласен, внешние данные на большой живой системе — это меньшая часть. Но базы данных у нас не очень большие, а остальное хорошо диффбэкапами сокращается (в нашем случае).

                        Распаковывать быстрее гласьера, конечно, не получится, но если мы выбираем гласьер — то знаем это, и 6 часов на добычу файла для нас — терпимо. В нем все должно быть, что мы туда положили. Цена — компенсирует время. (когда нужно срочно — тогда, конечно, glacier не подходит. Когда нужно дешево — не подходит все остальное).

                        Смысл супер-короткого архива не только в том, что он маленький и экономит трафик (так можно и просто файл с URLами хранить), а то что его дешево и удобно хранить и он восстанавливается точно. (например, можно изменить пару файлов в wordpress и изменения не потеряются). Хранить, пересылать — мы можем маленький файл, а эффект — как если бы весь репозиторий борга хранили-пересылали.

                        Мне нравится unix-way, чтобы утилита делала минимум. Делать комбайн из нее — не хочется. Например, вот вы написали что «Borg ещё и сжатие умеет.» — для меня это странно, потому что это gzip уметь должен. Зиповать или нет (и каким алгоритмом, может .rar или .7z) то, что выдает архиватор-дедупликатор — это уже по ситуации пользователь должен решать. (у hashget есть ключик -z для удобства, но вообще можно его вчистую использовать, и после hashget использовать tar + gzip (или rar), сам дизайн позволяет это)

                        Поэтому CDC для файлов данных — с одной стороны, мне нравится эффективностью, с другой — идейно кажется чем-то неправильным, чтобы это было встроенной частью hashget.

                        Наверное, в идеале нужно как-то по принципу конвейера чтобы было. Отдельно чтобы утилита вроде hashget вырезала «внешние файлы». Затем (или до) чтобы другая утилита обрабатывала файлы баз данных, их сжимала как-то. Потом какая-то другая занималась общим хранением и отдельно уже gzip зажимал. Но вот как это в виде конвейера или чего-то подобного организовать — я пока не очень представляю.
                          +1
                          Ясно, спасибо за объяснения. В целом понятно, у метода есть своя область применения.

                          вот вы написали что «Borg ещё и сжатие умеет.» — для меня это странно, потому что это gzip уметь должен

                          А вот тут не всё так просто — дело в том что сжатие происходит не целыми файлами и не после того как сформирован архив, оно применяется к найденным (посредством CDC) блокам, которые ищутся в процессе разбора исходников, и каждый блок представляет собой разную часть файла, к тому же, эти блоки могут быть разной длины (потому что зависят от контента).

                          При таком раскладе иного способа кроме как интегрировать сжатие в основной алгоритм — увы, нет. Да, можно извратится и вызывать gzip/7z/bzip/что-скажут на каждый найденный блок, но это существенный оверхед (особенно если много сравнительно мелких блоков), хотя в самом архиваторе есть выбор различных алгоритмов.

                          Если упрощенно, архив от borg или restic это нечто вроде базы данных, где индексом служит хэш блока, а собственно блок может быть сжат и зашифрован перед записью. На самом деле, конечно, всё чуть сложнее (метаданные и прочая) — и именно эта сложность не позволяет легко использовать внешние процессы. Особенно это актуально когда вы восстанавливаете из архива — в этом случае архиватор выдёргивает нужные блоки из архива и собирает результат по кусочкам, да и собственно организация в виде БД позволяет на лету его реорганизацию (удаление старых снапшотов, неиспользуемых блоков) — без необходимости полностью его распаковывать для этого.

                          К тому же, вызов внешних процессов сильно усложняет обработку ошибок — мало утилит имеют чёткие и стабильные коды возвратов и сообщения об ошибках, т.е. если что-то идёт не так после вызова gzip, трудно понять что это — нехватка памяти, ошибка ввода-вывода, etc. Умножте это на то что каждый внешний компрессор имеет свои коды возвратов, свой набор опций для выбора метода сжатия, а сообщения об ошибках могут быть локализованы, не говоря уже о том что и первое и второе может меняться от версии к версии — и представьте сложность интеграции и поддержки, не говоря же о том что это внешние зависимости.

                          Да, для скриптов в оболочке это не проблема, там важно «пан или пропал» (и вылет по ошибке с надеждой что пользователь решит что делать дальше), а вот для сложной системы архивации это слишком напряжно — к примеру, завис gzip где-то на чтении/записи, и пойди пойми почему — то ли в свопе, то ли диск тормозит, то ли сеть (если NFS/SMB/CEPH), то ли ещё чего, при «ручной» обработке это всё же проще контролировать, а если учесть что архив (точнее, конкретный snapshot) можно монтировать (посредством fuse) — то вызов декомпрессора в отдельном процессе (скорее всего многократный) при чтении файлов — это уже явный перебор.

                            +1
                            Glacier сейчас позволяет «срочной» сделать только операцию востановления.
                            Тоесть вы пишите в «обычный», потом когда надо — делаете «срочный» запрос на информацию.
                            Мы так записи разговоров, например, храним.
                        0
                        Дополнил статью разделом по интеграции restic + hashget.

                        В обычном случае, при добавлении в restic каталога с wordpress (47Mb), его репозиторий раздувает на 43Mb. Если через hashget — то всего на 1 мегабайт. Волшебные команды:
                        ~~~
                        # hashget --submit wordpress.org/wordpress-5.2.2.tar.gz -p my --file wordpress-5.2.2.tar.gz --hashserver
                        # hashget -X exclude-list --prepack wordpress --hashserver
                        # restic --exclude-file exclude-list backup wordpress
                        ~~~

                        Спасибо, что подтолкнули сделать это.
                        +2
                        Идея забавная, но как-то ненадежно выглядит. А если сервер с «образцами» загнется? У дебиана вон вовсю идет переход от ftp к https-репозиториям, плюс некоторые зеркала могут закрываться без предупреждения. Есть ли возможность подменить URL в таких случаях? Если нет, то бэкапу кранты.
                          0
                          Вся информация по восстановлению там — в одном JSON файле (.hashget-restore.json), в простом текстовом виде. можно хоть sed'ом править URLы. Вообще, hashget'овский архив — это обычный архив недедуплицированных (поэтичное слово) файлов + один .hashget-restore.json.

                          Еще вариант постапокалиптичного восстановления — просто накачать файлы (хоть вручную) в pool каталог и указать его при восстановлении. Если в pool есть файл с нужным хешем — hashget уже не использует URL, а просто распаковывает имеющийся файл.

                          Но там другая интересная ситуация была. Дело в том, что делать ссылки на живой репозиторий нельзя, они изменяются. После выхода новой версии пакета — старый URL может дать 404. Но у debian есть snapshot.debian.org. Там как раз ВСЕ версии пакетов и по постоянным URL. hashget эти URL используют. Они вроде не менялись за все 10 лет.

                          И по этой же причине, такая тесная дружба с Debian, а вот CentOS, например, так сделать нельзя — урлы могут протухнуть. (Хотя может быть я плохо знаю про CentOS и там есть какое-то свое решение?)
                          0

                          Мне как-то тяжело придумать сферу применения этой штуке. Данных почти всегда больше чем чем системы. Гораздо проще взять упомятнутые уже в комментах restic/borg и бэкапить ими.


                          Если смотреть на 'околодомашнее' использование, то первое что приходит в голову — фото/видео и прочий тяжелый и плохосжимающийся уникальный контент, который заведомо невозможно найти на snapshot.debian.org.


                          Если рассматривать вариант контейнеров и не разводить зоопарка дистрибутивов, то по сути всё равно бинари и прочий /usr будет забэкаплен один раз. И с увеличением количества данных, доля установленной системы (5, 10, ну пусть даже 20GB) будет уменьшаться. Зато все данных для восстановления под контролем и доступны локально когда это нужно.


                          А даже если и поставить цель развести зоопарк дистрибутивов, то в случае debian это будет целых полтора релиза (stable и oldstable), а для остальных про аналог snapshot.debian.org hashget ничего не знает.


                          Зависимость же от сторонних сервисов вроде http://snapshot.debian.org в эпоху копирастов и прочих DMCA это скорее минус чем плюс… Даже беглого просмотра багтрекера для snapshot.debian.org достаточно, чтобы понять что это ни разу не вечный архив. Пакеты оттуда тоже удаляют: #737359, #610303, #779822, #581157. Плюс возможные проблемы с доступом как раз когда нужно будет восстановиться...


                          PPS. В случае с debian был еще раньше 'дедовский' способ в виде --exclude=/usr и дальше манипуляций с dselectи dpkg --unpack при восстановлении.

                            0
                            Благодаря комментам на хабре, разобрался с restic и подружил их с hashget'ом (дополнил новую главу в пост), спасибо за мотивацию! :-)
                            0
                            У нас — именно VPSки. Есть заказчики, и чтобы не пихать разные проекты разных заказчиков (иногда с требованиями вроде «только PHP 5») на один сервер — у каждого VPS, но мы любим debian, поэтому у нас набор дебианов.

                            Бекапы все выкидываются в гласьер. На каждой хост-машие — только сами виртуалки + 1-2 последних бэкапа на них. Остальное в гласьере (много и сказочно дешево). Выделить в N раз большее места под бэкапы — дорого.

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

                            Скорее всего вообще немного неправильно выбирать либо одно, либо другое. (Все равно, что выбирать «или restic или gzip»). Я подумаю насчет того, чтобы может быть как-то можно было интегрировать функцию внешней дедупликации от hashget с остальными фичами restic, Это, мне кажется, будет самым правильным подходом.

                            По restic вопрос — там можно как-то репозиторий держать на нескольких машинах? (если у нас, допустим, несколько серверов по 1Tb, а данных — 5Tb). Потому что у нас сейчас подобная ситуация как раз.
                              0

                              Я про такую возможнсть не знаю… Возможно rclone умеет (restic может использовать rclone в качестве бэкенда).

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое