29 января 2013 в 11:47

SXB: инкрементальный бэкап MySQL

PHP*, MySQL*
Эта статья является продолжением статьи Разрабатываем новый формат файла для бэкапа сайтов, в которой рассматривался перспективный формат для бэкапа сайтов.

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

Формат SXB предназначен для пользователей начального и среднего уровня. Для тех, кто не знаком (или не может использовать их на конкретном сайте) со средствами горячего бэкапа (бинарные логи, снимки файловой системы, Xtrabackup и т.п.). Грубо говоря, для тех, кто для бэкапа MySQL использует mysqldump и подобные программы, создающие SQL-дамп базы.

Сразу напомню, что формат пока на стадии отработки технологии, и в конце статьи вас ждет тестовый PHP-скрипт.

Почему не mysqldump?


Итак, одним из самых популярных вариантом для бэкапа баз данных MySQL является идущая в комплекте программа mysqldump. В интернете, можно встретить множество, как простых скриптов (в том числе, есть несколько статей на Хабре), так и отдельных программ бэкапа в которых используется mysqldump.

Так почему же не использовать его? Основные недостатки связаны с пресловутым «unix way» (когда каждая программа делает минимальную задачу и не подозревает о других программах).

В данном случае возникают следующие проблемы:

  • Использование временного файла
    Стандартная схема работы, это создание файла с дампом, а потом добавление его в архив tar или zip. Следовательно, нужно больше места для бэкапа, а также дополнительное время на копирование.

  • Плохая поддержка дедупликации
    Из-за того, что mysqldump вставляет комментарии и различные метаданные (типа значения auto_increment), а также из-за зависимости одних таблиц от других.

  • Отсутствие навигации по дампу
    Чтобы достать данные только из одной таблицы нужно парсить дамп, пока не найдешь нужное место. Потому чаще всего восстанавливают весь дамп (возможно во временную базу данных).

  • Отсутствие постпроцессинга
    Так как дамп представляет собой просто набор SQL запросов, а восстановление выполняет стандартная программа для выполнения любых запросов. То восстановление занимает дольше времени (из-за более сложного парсера), и нет возможности изменять запросы (например, использовать REPLACE вместо INSERT).

Часть из этих вопросов можно попробовать решить различными опциями mysqldump, но в результате усложняется восстановление дампа. Да и на практике таких решений не встречал. Я пробовал решить некоторые из этих проблем в Sypex Dumper 2. Там в SQL-дамп добавлены специальные метаданные. Но в новой версии решил пойти дальше.

Новые возможности бэкапа MySQL в формате SXB


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

В pro версии дампера, уже был использован SELECT OUTFILE для ускорения процесса бэкапа. Так как вполне понятно, что намного быстрее будет, если MySQL-сервер сам будет сохранять данные в файл, а не передавать данные разбитые на отдельные поля, каждое из которых еще нужно экранировать, добавить кавычки, скобки и т.п. Но при этом дамп всё же приводился к привычному SQL-виду.

В новой же версии, я задумался над тем, зачем тратить время на оформление дампа во время бэкапа, если на эти декорации уходит 30-50% времени. Учитывая, что бэкап обычно делается значительно чаще, чем восстановление. То естественно лучше перенести дополнительную нагрузку на процесс восстановления.

Работая над форматом SXB и блочной дедупликацией для файлов, появилась идея, что неплохо бы попробовать и дедупликацию для самой БД. Ведь в базе данных меняется не так много данных между бэкапами.
На первом этапе решил реализовать дедупликацию на блочном уровне, также как и для файлов. У такого варианта, конечно, есть недостатки по сравнению с дедупликацией на уровне строк. Но он будет значительно быстрее и менее требовательным к ресурсам.

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

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

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

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

Обязательно наличие прав доступа FILE у вашего MySQL пользователя и MySQL-сервер должен находиться на localhost. Если будет много желающих добавлю версию и с простыми селектами.

В результате работы получите такую таблицу (обрезал дату, чтобы влезло на страницу).
+--------+------+---------+--------+--------+----------+----------+----------+--------+
|  D & t | Tabs | Rows    | Blocks | Dubs   |   Size   | Dub.size | SXB.size | Time   |
+--------+------+---------+--------+--------+----------+----------+----------+--------+
|  07:38 |   26 |  557180 |   4779 |      0 | 37.03 MB |        - | 11.43 MB | 3.8561 |
|  08:06 |   26 |  557187 |   4779 |   4761 | 37.03 MB | 36.92 MB |  39.8 KB | 2.8214 |
|  08:22 |   26 |  557187 |   4779 |   4775 | 37.03 MB |    37 MB | 12.22 KB | 2.5557 |
|  08:37 |   26 |  557187 |   4779 |   4778 | 37.03 MB | 37.03 MB |  3.75 KB | 2.5052 |
|  08:52 |   26 |  557193 |   4779 |   4768 | 37.03 MB | 36.96 MB | 24.57 KB | 2.6060 |
|  09:10 |   26 |  557196 |   4779 |   4775 | 37.03 MB | 37.01 MB |  7.79 KB | 2.8218 |
+--------+------+---------+--------+--------+----------+----------+----------+--------+

Первый раз делается полный бэкап, последующие бэкапы инкрементальные. «SXB.size» показывает размер файла с инкрементным бэкапом (т.е. измененные блоки).
+24
9543
156
zapimir 54,3

Комментарии (65)

+2
Zibx, #
Сама по себе идея хорошая, но в разрезе конкретной проблемы «бэкап данных» — решение является странным. Возникает необходимость делать бэкап бэкапов.
0
zapimir, #
В чем странность инкрементальных бэкапов? И что Вы имеете ввиду под «Возникает необходимость делать бэкап бэкапов»?
+3
Zibx, #
Инкрементальность просаживает надёжность. Если помрёт начальный бэкап, на который делались инкрементальные, то абсолютно все последующие потеряют смысл (в некоторых кейсах можно будет что-то восстановить, но в целом — так).
Это классический случай взаимосвязи ресурсов (занимаемый объём) с надёжностью. Хорошим решением будет делать полный бэкап раз в день, а каждый час делать инкрементальный. Тогда в случае выхода из строя носителя последнего бэкапа будет велика вероятность что мы сможем откатиться на вчерашний. Если же за физическую целостность данных отвечает решение другого уровня (рэйд), то можно переложить ответственность на него. Но я за баланс и перестраховку. Тот же человеческий фактор, когда юзер удалит старый бэкап руками, ибо вот есть новый и весит мало.
0
antaries, #
т.е. получается, что кроме того, что полный бэкап нужно делать раз в день, делать его надо еще и на отдельный носитель? Иначе ведь, если выйдет из строя носитель с последним бэкапом, то и предыдущих мы не увидим. Как-то мне кажется, тут raid выглядит более сбалансированным и перестрахованным решением.
0
svetasmirnova, #
А это с любым бэкапом нужно делать.

RAID не является бэкапом. Во-первых, потому, что проблема с выходом дисков из строя всё равно существует. Во-вторых, потому, RAID-«бэкап» нельзя использовать, например, для отката последнего DROP TABLE /* Hi from coolhacker */ very_important

Ещё я сомневаюсь, что RAID поможет восстановить corrupt-нутую таблицу
+1
svetasmirnova, #
Сразу на два Ваших комментария отвечу.

Бэкап бэкапов нужно делать всегда.

> Инкрементальность просаживает надёжность. Если помрёт начальный бэкап, на который делались инкрементальные, то абсолютно все последующие потеряют смысл (в некоторых кейсах можно будет что-то восстановить, но в целом — так).

Инкрементальные бэкапы нужно правильно планировать. Когда я рассказываю про backup, я привожу в пример такую схему: full backup раз в неделю и incremental backup ежедневно. Это для не очень активных изменений, в общем-то. Другие специалисты могут предлагать какие-то другие общие схемы в вакууме, но вряд ли кто в своём уме предложит делать full backup-ы реже.

Почитайте ещё рекомендации для MySQL Enterprise Backup. Искать нужно whitepapers, соответствующие страницы в официальном мануале и в Team Blog (https://blogs.oracle.com/mysqlenterprisebackup/) есть ссылки на слайды с презентаций.
+1
zapimir, #
Ну так понятное дело, что нужно использовать схемы бэкапа, и периодически делать полный бэкап. Инкрементальный бэкап позволяет делать бэкапы чаще, и следовательно меньше терять данных в случае отката. К тому же тулза из коробки будет уметь заливать бэкапы на несколько облачных хранилищ, так что вероятность повреждения уменьшается.
0
deMone, #
Стандартная схема работы, это создание файла с дампом, а потом добавление его в архив tar или zip. Следовательно, нужно больше места для бэкапа, а также дополнительное время на копирование.
Слабый аргумент. У большинства сайтов базы данных редко превышают пару сотен мегабайт, а на таких объёмах экономить пространство как-то странно.
+1
AotD, #
И перенаправление потока для сжатия на лету тоже никто не отменял ;)
0
vsespb, #
Да уж, действительно. Не аргумент вообще. Всю жизнь использовал mysqldump --quick… | gzip -9
–2
click0, #
На лету не стоит.
Время бэкапа увеличится в разы, да и CPU будет перегружен.
Лучше дампить сырой SQL на диск, а потом его сжать, использую nice.
+1
vsespb, #
Это на каком таком железе диск будет быстрее работать чем gzip?
–1
click0, #
На большом дампе, от 400MB.
А с учетом, если это действительно нагруженный сервер, у которого свободного CPU не более 20-25% будет куча неприятных эффектов.
0
vsespb, #
Если сервер нагруженный в плане CPU, но совершенно не нагруженный в плане HDD (что маловероятно учитывая что mysqldump обычно запускают на той же машине что и база), то будет так как Вы пишете.

Но по моему опыту как раз наоборот — с gzip быстрее, потому что на диск в несколько раз меньше пишется (учитывая что пока пишется, оно же с него и читается mysqldump'ом).

на счёт ssd не уверен, но думаю в половине случаев с gzip быстрее.
–1
click0, #
В вашем случае весь дамп будет крутится в памяти, пока полностью не сожмется (еще в свопе пару раз побывает :) ), а потом еще будет писаться на диск.
В моем случае дамп будет держаться в памяти, пока полностью не запишется на диск.
0
vsespb, #
Во первых он не будет в пямяти
-q, --quick Don't buffer query, dump directly to stdout.

во вторых в моём случае он быстрее запишется на диск чем в вашем )
–1
click0, #
Или будет в памяти, или будут базы залочены и mysqldump будет ждать, когда поток сожмется.
А насчет быстрее — проведите тесты и подсчитайте сами :)
0
vsespb, #
Конечно я потестировал — gzip быстрее HDD в 1.1 — 1.8 раза на базе 2 гига, при том что памяти 16 Гб, если база будет ещё больше (а значит больше дисковая активность) — gzip ещё выиграет.
0
click0, #
Так вы тестили на свободной памяти и CPU.
А потестите на загруженной системе :)
0
vsespb, #
У меня 4 ядра (с HT — 8). Gzip однопоточный. Если 3 других ядра занять чем-то — результат будет почти такой же.

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

А ещё можно взять многопоточный архиватор — он будет ещё быстрее.
0
click0, #
У меня:
16 GB RAM
8 GB SWAP из 32GB
4х1,5TB RAID 10 (200-300 iops)
4 Core (+Hyper-threading)
LA 7-8

Ресурсов нет, как по-другому прикажете бэкапить?
Это типичная нода виртуалок или нагруженный масс-хостинг.

0
zapimir, #
А вы можете его сразу в tar.gz или zip перенаправить?
0
vsespb, #
конечно можно, mysqldump --quick… | gzip -9 > dump.sql.gz
+1
zapimir, #
И где тут tar? В gz вы можете положить только один файл, я говорю о бэкапе и базы и файлов в один архив.
0
vsespb, #
Нет, мы в этой ветке
habrahabr.ru/post/167469/#comment_5789049
habrahabr.ru/post/167469/#comment_5789049

и пост про бэкап mysql.
обсуждение недостатков mysqldump, который выдаёт дамп БД ввиде одного файла.
+1
zapimir, #
Перенаправление куда? В sql.gz? gzip не является архивом, это сжатие/распаковка одного файла.
Так что в итоге, получится тот самый временный файл, который потом нужно будет закинуть в tar или zip, вместе с остальными файлами сайта. А если паковать в tar, то вы еще и будете терять время на попытке сжатия уже сжатого sql.gz.
В моем варианте можно писать прямо в файл бэкапа и файлы, и данные БД. Более того писать только измененные данные.
Вот что я имел ввиду.
0
vsespb, #
А, ну раз так, то имхо просто не стоит стараться положить файлы сайта вместе с бэкапом БД в один файл. Мухи отдельно котлеты отдельно.
+1
zapimir, #
Т.е. не ложить их вместе просто потому, что текущие инструменты этого не умеют… логично. Было бы удивительно если бы они умели, их разрабатывали отдельно, и никто не задумывался о совместной работе.
Тем не менее для работы важны как файлы, так и база данных, и чтобы не нарушалась целостность, бэкап нужно делать всего. Причем в данном случае формат предлагает дополнительные плюшки в виде быстрого доступа как к файлам, так и отдельным таблицам, что затруднено в случае c классическими tar.gz и sql.gz.
0
vsespb, #
Сайты сайтам рознь. Я считал что файлы (исходники) должны быть в системе управления версий, конфиги там же. Полный снапшот машины со всеми пакетами — это отдельная песня. И БД отдельно. Причём во многих фреймвоках веб программирования есть понятие «миграции» — по любой копии БД можно понять с какой версией исходников можно работать.

Если у Вас несколько файлов вместо одного, просто положите их в одну директорию, делов то. Директории для этого и придумали чтобы не изобретать велосипед и распоряжаться отдельными по сути файлами по-отдельности.
+1
zapimir, #
А с чего вы решили, что файлы только исходные? А пользовательские файлы уже перестали быть файлами, или их бэкапить не нужно?

Количество файлов это вообще мелочь, это не столь важно. Тут намного важнее структура этих файлов, в частности что tar.gz, что sql.gz являются неидексированными, и чтобы хотя бы узнать, что именно в них находится, их нужно полностью распаковать и пропарсить.

Чтобы понять о чем речь, возьмите заархивируйте в tar.gz каталог с большим количеством файлов (скажем 100 тысяч) и потом попробуйте открыть, чтобы посмотреть содержимое, или достать из него случайный файл. А после, этого попробуйте достать из гигового sql.gz только одну последнюю таблицу.

Да можно сказать, что вам все равно содержимое, и не нужно извлечение отдельных файлов. Но вам никто и не запрещает использовать tar.gz и sql.gz.
0
zapimir, #
Чтобы сжать эти сотни мегабайт тоже нужно время, чтобы перелить на какой-нибудь Google Drive тоже. Да и уменьшение размеров позволяет делать бэкап чаще и/или хранить бэкапы за больший промежуток времени. К тому же в данном случае решение комплексное будет бэкапиться и база, и все нужные файлы с сервера.
0
AotD, #
Эм… А как вашим решением разрулить следующие чисто гипотетические ситуации:
1) Между 'SELECT * INTO OUTFILE ' и обработкой блоков одной таблицы на сайт зайдет незадачливый пользователь и добавит записей в таблицу, уже сдампленую?
2) Тот же незадачливый пользователь уберет одну запись из таблицы, еще не пошедшей в обработку, что каскадно выкосит пару тысяч записей из таблицы, которую уже заботливо положили в result.txt?

И третий вопрос вытекает из первых двух:
3) Как тогда восстанавливать это неконсистентное уныние с зависимостями по внешним ключам?
0
zapimir, #
Точно также как и в mysqldump блокировкой таблиц, перед бэкапом. Можно будет также добавить свои скрипты перед и после бэкапа, чтобы выключали сайт на обслуживание. Тут уже простор для фантазии.
0
click0, #
У меня бэкап Mysql делается средствами ZFS.
Получаются (инкрементальные) снапшоты файловой системы с MySQL базами.
+1
phprus, #
К сожалению это не бекап, а ZFS может развалиться, даже находящаяся в зеркале из-за аппаратных проблем. В прошлом году я на практике столкнулся с ситуацией, когда после жесткого ребута по питанию что-то произошло с дисками и в результате ZFS пришла в состояние, когда у некоторой части файлов просто отсутствовали данные (длина стала 0), а у некоторых содержание превратилось в фарш. ZFS была родная на Solaris 10.

По этому бекапы нужно уносить как минимум на другой сервер, а лучше на другую площадку с независимым питанием и прочими инженерными системами.
0
click0, #
У меня ZFS v28 на FreeBSD. Таких сбоев не видел.
Про хранения бэкапов на другой машине, а лучше в другом ДЦ знаю.

Но тут палка о двух концах. Как быстро передать 100ГБ-2ТБ данных с другого ДЦ?
+2
phprus, #
У нас это тоже был первый сбой с таким масштабом разрушений после сбоя питания, но тем не менее он был, что опять-же говорит в пользу того, что бекапы лучше сразу уносить на другой сервер. В случае базы это может быть кстати онлайн-репликация, правда я к сожалению не знаю, умеет ли ее MySQL.

Да, по сети в другой ДЦ это будет перекачиваться часы. Но на практике встречается способ переноса данных в другой ДЦ путем отправки человека или машины с жесткими дисками, по этому для критичных данных можно использовать его.
А вообще все от ситуации очень сильно зависит, в том числе и от архитектуры ДЦ и имеющихся сетевых ресурсов, а также самое главное от требований к надежности системы.
0
WaveCut, #
Умеет, односторонне и очень стремно.
0
vsespb, #
Файлы нулевой длины могут случится с любой ФС, в которой нет полного журналирования (например EXT4 с дефолтными настройками) — файлы впорядке, файловая система впорядке, но некоторое данные в некоторых файлах отсутсвтуют.
Не уверен на счёт содержимого = фарш, если до этого его там точно не было, то да, сбой ФС.
0
phprus, #
Так ZFS же вроде полностью транзакционная или я что-то путаю?

Да, до этого там точно его не было, так как ОС работала. Накрылся в основном пул, где была установлена ОС. Правда первопричина скорее всего была в дисках, а из-за них уже и ФС пришла в такое состояние.
+2
zapimir, #
Это не бэкап, так как вы вообще не имеете копии данных, причем желательно вообще в другом ДЦ. ZFS просто помечает, что текущие файлы не менять, а изменения писать в новые блоки, но в итоге если файл находится в нескольких блоках, то при повреждении старых блоков, вы потеряете и старую версию и новую.
0
click0, #
Да, но я могу управлять количеством копий в ZFS.

Но я обычно ставлю пару одинаковых серверов с 1HDD с взаимной репликаций.
Или 1 сервер, но винты в зеркале или RAID10.
0
zapimir, #
И как вам, это поможет если ДЦ сгорит/затопит и любое другое происшествие в результате которого пострадает большая часть оборудования ДЦ? Вот выше phprus пишет о ситуации с которой он лично столкнулся, даже без всяких природных катаклизмов.
0
click0, #
Вы путаете разные уровни и стратегии резервирования.
0
click0, #
Большинству пользователей хватает одного винта и недельного бэкапа на удаленный ftp.

Если нужна более высокая доступность и актуальность, выбирается стратегия исходя из объемов данных и стоимости недоступности сервиса.
В каждом случае индивидуальная :)
+1
svetasmirnova, #
Интересное решение!

> Обязательно наличие прав доступа FILE у вашего MySQL пользователя и MySQL-сервер должен находиться на localhost. Если будет много желающих добавлю версию и с простыми селектами.

Это сразу уменьшает полезность вашей программы для пользователей хостинга. В принципе, если можно дать FILE, как правило можно и бинарные бэкапы делать.

> Работая над форматом SXB и блочной дедупликацией для файлов, появилась идея, что неплохо бы попробовать и дедупликацию для самой БД. Ведь в базе данных меняется не так много данных между бэкапами.

> Для каждого блока считается идентификатор (CRC32 + MD5 + Размер блока), по этому идентификатору определяется уникальность блока.

> Таким образом, если мы встречаем блок, который уже есть в нашем бэкапе (текущем или предыдущих), то мы используем ссылку на этот блок, и не добавляем сам повторяющийся блок в текущий бэкап. Благодаря чему экономим место для бэкапа, процессорное время (не нужно сжимать одни и те же данные), а также из-за меньших размеров значительно ускоряется загрузка бэкапа в облачные хранилища.

То есть для MySQL-сервера — это всё тот же полный бэкап? Это хорошо только для небольших объёмов.

> Учитывая, что бэкап обычно делается значительно чаще, чем восстановление. То естественно лучше перенести дополнительную нагрузку на процесс восстановления.

Справедливое замечание, но не стоит забывать, что восстановление иногда требуется для того, чтобы вернуть работоспособность приложения, а тут каждая секунда на счету. В то время как бэкап может запускаться в максимально ненагруженное время и работать как угодно долго.
+1
zapimir, #
Насчет FILE это просто временные ограничения данного тестового скрипта, тестил максимальную производительность. В дальнейшем естественно будут и обычные селекты.

То есть для MySQL-сервера — это всё тот же полный бэкап? Это хорошо только для небольших объёмов.

Для MySQL да, но для сервера в целом нет, так как не нужно форматировать весь дамп и сжимать его, поэтому в целом нагрузка уменьшится. Да и в принципе в любом блочном бэкапе проверяются все блоки (если конечно где-то не фиксируется время изменения). Тем более, что файлы также будут инкрементально бэкапиться.

Справедливое замечание, но не стоит забывать, что восстановление иногда требуется для того, чтобы вернуть работоспособность приложения

На самом деле всё будет заливаться значительно быстрее (LOAD DATA будет использоваться), так как значительно упрощен парсинг. Плюс имеется мгновенный доступ к данным любой таблицы.
0
svetasmirnova, #
> Для MySQL да, но для сервера в целом нет, так как не нужно форматировать весь дамп и сжимать его, поэтому в целом нагрузка уменьшится. Да и в принципе в любом блочном бэкапе проверяются все блоки (если конечно где-то не фиксируется время изменения).

В бинарном incremental backup этот процесс хотя бы на текущие запросы никак не влияет. Но у вас другая ниша, это понятно.

У меня ещё вопросик:

> Для каждого блока считается идентификатор (CRC32 + MD5 + Размер блока), по этому идентификатору определяется уникальность блока.

А как вы неуникальные строки идентифицируете. Например, есть такая таблица:

create table names(name varchar(255)) engine=innodb;

insert into names values('sveta', 'sveta', 'sveta');


Делаем бэкап.

insert into names values('more', 'sveta', 'sveta');


Как вы последние две строчки от первых трёх отличаете?
+1
zapimir, #
По сути нет необходимости их различать, мы получаем их от MySQL в формате текста с разделителями табуляцией, потом уже этот текст разбиваем на куски и сравниванием хэши этих кусочков. Т.е. допустим для упрощения размер блока будет равным размеру строки получаем от mysql строки
sveta
sveta
sveta

делаем бэкап, в него попадает
sveta
Б1.1
Б1.1

т.е. в сам дамп уже попадает только первый блок, а два следующих блока ссылаются на первый блок первого бэкапа (т.к. у них одинаковое содержимое)
После выполним
insert into names values('more', 'sveta', 'sveta');

и при новом бэкапе MySQL уже вернет
sveta
sveta
sveta
more
sveta
sveta

в бэкап файл у нас уже попадет
Б1.1
Б1.1
Б1.1
more
Б1.1
Б1.1

Т.е. добавится новое имя, а вместо sveta будут стоять ссылки на первый блок первого бэкапа.

Естественно на схеме это не сильно заметно, но на самом деле ссылка на блок занимает в тысячу с лишним раз меньше места, чем сам блок данных, поэтому достигается значительная экономия.
0
svetasmirnova, #
Спасибо! А при удалении как это работает?
+2
zapimir, #
точно также, тут нет привязки к самой структуре таблицы, по сути каждый раз делается полный дамп, просто при этом не сохраняются блоки которые уже были, а заменяются ссылками. Т.е. если мы удалим первые две sveta, то при очередном бэкапе получим
Б1.1
Б2.4
Б1.1
Б1.1

В итоге по этим ссылкам мы можем собрать полный дамп
sveta
more
sveta
sveta

Чтобы отслеживать изменения на уровне отдельных строк, лучше конечно бинарный лог использовать. Можно конечно заморочиться и сделать бэкап на основе полей с уникальными индексами и timestamp, но будет очень затратно.
В случае с SXB чтобы узнать, что конкретно изменилось можно попробовать извлечь блоки с одинаковым смещением относительно начала таблицы и сделать им diff, но пока сильно не задумывался на эту тему. Главное, чтобы можно было откатить базу или отдельную таблицу на определенную дату.
0
Vilko, #
Быстро работает… еще б функции/вьюхи/триггеры бэкапить… )
+1
zapimir, #
Да это не проблема, просто у них обычно размер мизерный по сравнению с таблицами, потому для теста они не очень интересны. В конечном результате конечно будут все объекты MySQL бэкапиться.
0
symbix, #
А почему бы просто не пользоваться xtrabackup?
0
zapimir, #
Я вроде об этом писал в третьем абзаце поста… Примерно по тем же причинам, по которым нет смысла юзать Enterprise софт на домашнем ноуте.
+1
symbix, #
Упс. Вот она, привычка пропускать введения. :)

Вообще говоря, конечно, тогда требование file привелегий несколько противоречит: у целевой аудитории с большой вероятностью шаред, где их никогда не будет. Кстати, можно попробовать общаться с сервером по mysql-протоколу самостоятельно, и бэкапить непосредственно из ответа сервера без обработки клиентской библиотекой. Достаточная для этой цели реализация протокола есть в phpDaemon.
+1
zapimir, #
Это требования конкретного тестового скрипта, а не технологии в целом. Просто сейчас тестирую максимальную производительность. Готовое решение можно будет запустить на практически любом шаред-хостинге, разве что не планируется поддержка PHP ниже 5.2, т.к. костылей придется много писать.

Насчет общаться напрямую с сервером, спасибо за подсказку, изучим этот вопрос.
0
storms, #
Возможно ли использовать этот софт для инкрементного восстановления БД?

Поясню: У меня на сервер БД находится в состояниии «Х», есть бекап с состоянием «Х+1». можно ли накатить только изменения (+1)?
0
pcmaniac, #
Для каждого блока считается идентификатор (CRC32 + MD5 + Размер блока), по этому идентификатору определяется уникальность блока. Два алгоритма хэширования используются для того, чтобы избежать коллизий. А сами алгоритмы выбраны, как наиболее быстрые. Также считается общий MD5-хэш для всей таблицы.

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


Не совсем верное решение. Хэш (CRC32 + MD5 + Размер блока) ненамного лучше чистого MD5 и вероятность коллизий остаётся. Лучше использовать схему: быстрый хэш + побайтовое сравнение. т.е. вы считаете для блока например CRC32, ищете в бекапе все блоки с таким CRC32 и сравниваете новый с ними побайтово, если он в точности с каким-то совпал — ставите ссылку, а если не совпал, создаёте новый.

Так вы гарантированно защищаете себя от коллизий. В плане выбора хэша логика простая — хороший криптохэш даст нормальные результаты в такой схеме для размеров базы 2^(n-1). т.е. для CRC32 (если бы он был хорошим криптохэшем) результаты удовлетворительные были бы для дампов до 2Гб. С ростом дампа начнут расти коллизии и замедляться работа алгоритма. В принципе можно с перестраховкой сразу остановиться на MD5, которого тут заведомо хватит, но он довольно ресурсоёмкий. Думаю таки стоит собрать статистику на предмет того, насколько съедобные в такой схеме 32/64-битные быстрохэши типа CRC.

Я так понял это закладывается функционал для SypexDumper 3? Очень буду его ждать, вкусный функционал вырисовывается. Вторым пользуюсь ещё с беты и очень доволен, ни разу не подвёл, чего только не хватало, так это бэкапа файлов.
0
zapimir, #
Ну вообще, теоретически, вероятность одновременной коллизии двух разных функций хэширования значительно ниже, чем вероятность коллизии в одной функции, тем более на двух одинаковых небольших блоках. Для страховки от коллизии еще считается полный MD5 всей таблицы или файла.

В принципе так работают тот же rsync (только там MD4) и некоторые другие системы в которых есть блочная дедупликация. Скорость MD5 в PHP практически такая же как у CRC32, это 2 самых быстрых алгоритма в PHP.

Что касается побайтового сравнения, то это будет слишком медленно, а иногда и практически невозможно, так как при инкрементальном бэкапе, сами файлы с данными могут находиться в облаке (в сжатом и закодированном виде, причем в нескольких файлах). Т.е. как раз мысль в том, чтобы на сайте сохранять только каталог с хэшами. Для параноиков будет ускоренный Full Backup.

Да этот функционал будет в Sypex Dumper 3 + Sypex Backuper. Тут кроме этого еще одна очень крутая фишка тестируется, так называемый RAW бэкап MySQL. Суть в том, что дампер не будет использовать стандартные mysql функции PHP, в дампере будет собственный MySQL клиент, заточенный именно на бэкап, он просто сохраняет пакеты полученные от MySQL без всяких преобразований в файл (в итоге мы экономим время на разборе пакетов MySQL, создании PHP-массивов, экранировании и т.п.), все эти действия будут делаться только при восстановлении из бэкапа.
В общем тестовый скрипт в самом сложном случае когда таблица с большим количеством небольших строк (41 млн строк, весом 3,9 ГБ) опережает mysqldump в 2 с лишним раза, при том что выполняется дедупликация.
0
pcmaniac, #
Вероятность коллизии идеальной хэш-функции пропорциональна 2-n, где n — размерность функции.

Для двух функций, если опять-же рассматривать идеальный вариант, это будет произведение их вероятностей: 2-n1*2-n2=2-(n1+n2)

Но это в идеале т.к. две хэш-функции от одного текста не совсем корректно рассматривать как несовместные события.

Т.е. для вашего алгоритма в идеале вероятность коллизии будет 2-160

Если мы возьмём SHA1-160 — его стойкость к возникновению коллизий будет выше вашей схемы и при этом его не оценочная, а фактическая стойкость является 2-52, что намного ниже идеальнотеоретического уровня. Теперь представьте какая будет у вас с учётом очень низкокачественного компонента в виде CRC32.

Для сравнения: в ZFS для дедупликации используется SHA-256 плюс побайтовое сравнение в случае совпадения хэша. Как по мне, то на критичных данных полагаться на слабые хэши рискованно. Лучше сразу заложить функционал перепроверки, но сделать его опциональным, чтобы пользователи уже могли сами решать как им быть. Ведь если не использовать сжатие, то дёргать бэкап для поиска дублирующихся данных будет не очень дорого. В принципе для сведения вероятности коллизии к минимуму можно использовать SHA2-512, но мы тут особо не сэкономим т.к. выигрыш будет только в случае если были коллизии на более слабой функции.
0
zapimir, #
2 52 это не фактическая стойкость, а теоретическая сложность нахождения коллизии, когда её ищут специально. Эти значения критичны для криптостойкости (когда хэши используются для цифровых подписей), в нашем случае это не так критично. Именно для уменьшения зависимости от недостатков одного алгоритма, используется 2 алгоритма, в принципе можно сделать, чтобы вместо md5 можно было использовать другой алгоритм.

ZFS не система бэкапа, и она всегда имеет быстрый доступ к любому блоку, чтобы можно было его сравнить побайтно. При инкрементальном бэкапе данные каждый раз будут совпадать на 95-99%, Вы предлагаете их каждый раз полностью побайтно сравнивать? И много вы знаете людей которые бэкапы хранят в несжатом виде?

Так что, считаю, что по умолчанию, CRC32 + MD5 будет более, чем достаточно, плюс будет возможность изменить на другую комбинацию CRC32 + SHA1/SHA2, а для совсем критичных ситуаций будет режим быстрого полного бэкапа.
0
pcmaniac, #
И много вы знаете людей которые бэкапы хранят в несжатом виде?

Я :)
У меня все сервера бэкапятся на ZFS сторадж. Сам сторадж с шифрованием и сжатием, но с точки зрения машины — это просто хранилище последней копии данных (идёт постоянная фоновая синхронизация). В случае же рестора — монтируем один из снэпшотов и выдёргиваем данные — очень удобно.

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

При инкрементальном бэкапе данные каждый раз будут совпадать на 95-99%

Тут пожалуй вы правы, но для особых параноиков я бы такую функцию сделал опциональной :)
Ну или хотя-бы использование максимально стойкого хэша, тот-же SHA2-512 — меняем IOPS-ы на CPU.
0
zapimir, #
Ну ZFS сторадж это из серии горячего бэкапа, и не спасают, в случае аварии в датацентре, к примеру если его затопит. Да и как пишут выше habrahabr.ru/post/167469/#comment_5790583 с ZFS тоже бывают проблемы. Так, что вероятность нарваться на какую ошибку железа, даже выше, чем вероятность попадания на коллизию в CRC32 + MD5.

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

Что касается SHA2-512, то не проблема сделать его в опциях, просто из-за него увеличится время создания бэкапа, где-то на 40%. Кроме того место под хранение каталога в памяти удвоится.
0
pcmaniac, #
Ну ZFS сторадж это из серии горячего бэкапа...

Это предусмотрено. Сторадж физически стоит в другой стране и с него снимаются копии раз в месяц на внешний носитель. т.ч. тут с перестраховкой всё нормально :)

Бэкапы будут храниться и с дедупликацией и со сжатием, так как deflate сжатие весьма быстрое...

Тут тоже можно было-бы добавить опцию для выбора сжатия. Я в SXD 2 юзаю bzip2 т.е. он заметно сильнее жмёт. База 200Мб бэкапится меньше минуты. Нет для теста под рукой баз большего размера, может на очень больших оно и оправдано, но там возникает другой момент: дисковое время дороже процового и на облаке и на реальном железе, узким местом может только стать оперативка, если её очень впритык то использовать тяжёлые алгоритмы не получится.

Что касается SHA2-512, то не проблема сделать его в опциях

Да, да, больше опций! На самом деле если это не сильно усложнит разработку, стОит заложить расширенный функционал, а по дефолту поставить рекомендованный, клиенты только «спасибо» скажут.

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