Тънко резервиране на файлови системи Linux. Как да създадете резервни копия на три терабайтна MySQL база данни за 20 секунди

Тънко резервиране на файлови системи Linux. Как да създадете резервни копия на три терабайтна MySQL база данни за 20 секунди

Казвам се Юрий, ръководител на екипа за системно администриране в Ситимобил. Днес ще споделя опит с технологията за тънко резервиране (thin provisioning) на файловите системи Linux и как може да се прилага в технологичните CI/CD процеси на компанията. Ще разгледаме ситуацията, когато за автоматично тестване на кода при доставката му в продукция, колкото се може по-бързо ни трябват копия на MySQL бази данни, максимално близки до

Въведение: защо да даваме вредни съвети?

Логичен въпрос, тъй като има отработени механизми за миграция на схемите на бази данни в тестови среди. Защо всъщност да довеждаме основната неразделена СУБД до такива обеми? Освен това не всички данни са необходими за тестване. Ще се опитам да обясня.

Преди около година, на фона на активен растеж на нашия агрегатор за таксита (през 2018 година се увеличихме по завършени поездки около 15 пъти), обемите на данните нараснаха, натоварването на сървърите и честотата на изданията също се увеличиха. Оказахме се в следната ситуация:

  • Основната MySQL база данни нарасна до около 1000 таблици с общ обем от 2,5 Тб и продължава да расте.
  • Нямаше възможност да се раздели бързо базата данни. Старият подход 'пиша в базата каквото искам и както искам', множество JOIN'ове и вътрешни зависимости между таблиците не позволиха това.
  • Нямаше механизмът за миграция на схемата на базата данни в тестови среди.
  • Нямаше автоматично тестване на кода при издаване в експлоатация.

Последният проблем искахме да решим възможно най-бързо. Вече бяха написани тестове Postman за проверка на основния PHP монолит, но нямаше актуална база данни. В същото време не можехме да създаваме реплика през нощта, да я правим основна и да я предоставяме за работа дневно: много голямо количество издания и промени, в това число в данните и схемата на базата, биха направили стенда неработоспособен още към средата на деня. Освен това да ограничим изданията само до работния ден би било неефективно.

Тем не менее, задачата беше изпълнена: първият работен стенд получихме само след две седмици. През изминалата година той преживя много промени и продължава да се използва.

Следващите стъпки ще опиша подробно. Ще се уверите, че този метод заслужава право на съществуване.

Какво е 'тънко резервиране'?
Това е хардуерна или софтуерна технология (друго име — sparse volumes), която позволява да се изолира повече от необходимия ресурс, отколкото има налично. При това, извлеченият обем трябва да отговаря на критериите just-enough (точно толкова, колкото е необходимо) и just-in-time (в необходимото време). Основно, тънкото резервиране се прилага в различни СХД, за да предоставя дисково пространство в необходимите обеми, надвишаващи фактически наличното. Технологията се поддържа от различни файлови системи, като LVM2, ZFS, BTRFS. Тя широко се използва в хипервизори за виртуализация. Чрез тънкото резервиране успяхме бързо да създадем от моментни снимки на основния дял с данни толкова копия на този дял, колкото ни е необходимо (data-директория СУБД MySQL).

Първият стенд, технология Thin LVM

Тази глава може да бъде наречена "Как да направим максимално бързи моментни снимки на големи обеми данни с помощта на Thin LVM, намалявайки стабилността на файловата система и СУБД MySQL до недопустими нива."

Тъй като вече използвахме LVM за изграждане на основните дялове на ОС, решихме да започнем точно с нея. Първоначално ни трябваше отделна физическа машина — реплика на нашата основна база MySQL, на която можехме да създаваме моментни снимки на репликата и да я стартираме до отделен екземпляр на MySQL. По време на тестването разрешихме да се прилагат променящи операции на този екземпляр, а след приключване на тестовете успешно го изтривахме. Конфигурацията на сървъра беше следната:

  • 2 x Intel Silver 4114 (10×2,2 GHz HT)
  • 8 x 32 GB DDR4
  • 8 x 1920 GB Intel SSD в RAID-контролер Adaptec в RAID-10

Тема за избора между RAID-контролер и софтуерен RAID MD би могла да бъде отделна статия. Ще спомена единствено, че нашият избор бе повлиян от два фактора:

  • В времето на задаване на задачата, всички СУБД инсталирахме на RAID-контролери, така че може да се каже, че това исторически се е наложило.
  • Разликата в производителността при синтетични тестове на файловата система и тестове с различни операции в MySQL беше минимална.

Разделихме получения RAID-10: създадохме единен Volume Group (VG) за целия обем (с накладни разходи около 6,7 Гб) и създадохме логичен дял (Logical Volume, LV) за системата от 50 Гб. В нормална ситуация останалото пространство определяме за дял c MySQL. Но беше необходимо тонко резервиране, поради което първо създадохме т.нар. pool, вътре в който създадохме дял за /var/lib/mysql с обем от 3,5 Тб (предвид предполагаемите обеми на БД):

lvcreate -l 100%FREE -T vga/thin
lvcreate -V 3.5T -T vga/thin -n mysql

Форматирахме дяла в ext4, монтирахме го, записахме реплика и получихме изходния стенд. След това направихме обвивка под формата на API, който трябва да създава снапшотове, да стартира экземпляр на БД MySQL на зададения порт и да изтрива създадения экземпляр. Тъй като се използват изключително системни повиквания, за език на скриптовете избрахме обикновен bash, а за свързването на API HTTP → bash разгръщаме open source решение goexpose, написано на Go.

Някога ще публикуваме нашите bash-скриптове в open source, а засега просто ще опиша основния алгоритъм:

Създаване на основния снапшот snapmain:

  1. Спираме основната реплика.
  2. Поставяме заключване на операциите със снапшота snapmain.
  3. Създаваме нов снапшот snapmain.
  4. Стартираме MySQL и премахваме заключването.

Създаване на БД на произволен порт от snapmain:

  1. Поставяме заключване на конкретния экземпляр на БД (порт).
  2. Проверяваме наличието на заключване за създаването на основния снапшот. Ако го има, чакаме и проверяваме отново на всеки 5 секунди.
  3. Проверяваме дали има стар LV-дял на экземпляра.
    3.1 Ако има, спираме с помощта на kill -9 экземпляра на MySQL и изтриваме LV-дяла.
  4. Създаваме нов экземпляр от snapmain.
  5. Подготвяме и монтираме директории за този экземпляр.
  6. Премахваме признаците на слейва (файлове) и стартираме экземпляра на MySQL.
  7. Правим го мастер.
  8. Премахваме заключването.

Изтриване на БД на произволен порт:

  1. Поставяме заключване на конкретния экземпляр на БД (порт).
  2. Убиваме экземпляра на MySQL с помощта на kill -9.
  3. Размонтираме директориите.
  4. Изтриваме LV-дяла и премахваме заключването.

Примерни команди за клониране на дяловете на новия экземпляр на БД:

lvcreate -n stage_3307 -s vga/snapmain
lvchange -ay -K vga/stage_3307
mount -o noatime,nodiratime,data=writeback /dev/mapper/vga-stage_3307 /mnt/stage_3307

Сега ще ви разкажа за основния проблем, с който се сблъскахме при използването на тънко резервиране. Стигнахме до ограничението на производителността на SSD дисковете. Причината за това са особеностите на Thin LVM: той в своята основа оперира на ниво устройство с нискоуровневи чанкове с размер по подразбиране 4 Мб. Как изглеждаше това:

  1. Създаваме моментна снимка от основния дял /var/lib/mysql.
  2. Стартираме репликацията, за да настигнем мастера.
  3. Каквото и да е изменение в таблиците на репликата, то налага запазването на старите, неизменени чанкове данни в секцията на моментната снимка.
  4. Каквото и да е изменение в стартирания тестов экземпляр, то налага запазването на старите, неизменени чанкове данни в секцията на клонираната моментна снимка за този экземпляр.
  5. Получаваме натовареност на операции за вход-изход от 100% на устройството, забавяне на всякакви операции и постепенно отставане на репликата.
  6. Към края на работния ден получаваме отставал стенд с няколко часа.

Как се справихме с това, за да получим по-адекватен резултат (основни моменти):

RAID контролер:

  • Изключихме по подразбиране всички видове кеширане.
  • Настанихме writeback (при попадането на данни в буфер, записа завършва преди действителното запазване на диска).

Файловата система:

  • В точката на монтиране /var/lib/mysql написахме noatime,nodiratime,data=writeback
  • Изключихме логването на ext4 с помощта на tune2fs.

MySQL:

  • Записахме innodb_flush_method = O_DSYNC (увеличихме скоростта на запис, като понижаваме надеждността).
  • Изключихме логването, логовете не ни трябват.
  • Записахме innodb_buffer_pool_size = 4G (колкото по-малък е размерът на InnoDB пула, толкова по-бързо MySQL ще спре при спиране, и толкова по-бързо ще създадем моментна снимка).

Това далеч не е пълен списък, особено по отношение на MySQL. Впрочем, останалите промени са минорни и често не са приложими или точни. Например, в опит да облекчим дисковете, дори преместихме innodb_parallel_doublewrite_path в /dev/shm, което в някои случаи при стартирането на некоректно завършен экземпляр спестяваше до 5 секунди.

Защо спираме MySQL, преди да направим моментна снимка? Все пак можем да я направим от работеща реплика. Верно е, само че новият экземпляр на БД на тази моментна снимка по подразбиране ще се счита за повреден и ще изисква пълно сканиране при стартиране. Спирането на репликата определено е по-бързо, макар че накрая е най-дългият процес в цялата процедура.

В резултат на това получихме по-приемливи тайминги и стенд готов за работа. Въпреки това, както личи от най-ясния график за закъснение на репликацията на основната реплика, ситуацията все още е далеч от идеалната:
Тънко резервиране на файлови системи Linux. Как да създадете резервни копия на три терабайтна MySQL база данни за 20 секунди

От другите недостатъци заслужава да се спомене практически невъзможността за мониторинг на пулa Thin LVM: освен системните стандартни функции iostat, например, не е възможно да се разбере кой елемент от пула в момента натоварва най-много файловата система.

По-специално, заслужава да се отбележи един голям недостатък, свързан с описаната по-горе оптимизация: получихме YOLO-стенд. Приблизително веднъж на един-два месеца ext4 не издържаше на подобни посегателства и се повреждаше безвъзвратно, изисквайки преформатиране и повторно зареждане на репликата. Спечелили в скорост, ние безнадеждно убихме стабилността.

На какви метрики да внимаваме в процеса на експлоатация на Thin LVM:

  • Процент на данните в Thin pool
  • Процент на метаданните в Thin pool

Ако свършилото място за данни стендът ни оцелее (достатъчно е да почистим дисковете), свършилото място за метаданни ще доведе до пълен крах на пула и необходимост от неговото създаване от нулата.

Файловата система в пула с времето много силно се фрагментира. Препоръчвам веднъж дневно да пуснете по крон командата fstrim -v /var/lib/mysql.

Промеждинни заключения:

  • Технологията е лесна за приложение, както и самия LVM, и не изисква специална квалификация на инженера.
  • Тя е подходяща за бази данни с малки размери и не особено натоварени. Колкото по-малка е базата данни, толкова по-малко чанкове се преместват по файловата система в пула, и толкова по-ниска е натовареността на дисковете.
  • За нашата задача започнахме да търсим други решения, за които ще говорим в следващия раздел.

Вторият стенд, технология ZFS

Отдавна имах работа с файловата система ZFS, но тогава тя работеше доста добре на родното си семейство операционни системи Solaris. Имаше порт на FreeBSD версия с достатъчно добро ниво на реализация. Имаше и незавършен порт на Linux, който никой не използваше. Поради структурата на съхранение на данни B-tree (между другото, същата структура на съхранение има и InnoDB MySQL), ZFS не се представяше добре на инсталации с много голямо количество файлове. Всичко това, съчетано с необходимостта да се изучи техническата част преди използване, дълго време изключваше тази файловата система от практиката ми. Появиха се ext4 и xfs, които се превърнаха в стандарт. Но като се има предвид, че за нашата задача ZFS е повече от подходящ, а и Linux версията, според отзивите, се е развила в напълно разумен продукт (макар и без пълна поддръжка, поради което инсталирането на система на ZFS изцяло от нулата може да стане само с разнообразни трикове), решихме да я пробваме.

По разбираеми причини, стендът беше избран с аналогична конфигурация (с изключение на RAID контролера). Инсталирахме осем SSD диска по 1920 Гб. Нямаше желание да пишем собствен мрежови образ за инсталиране на сървера на гола ZFS, затова отрязахме по 50 Гб от всеки диск и направихме на тях MD RAID-10 за системата. Останалите 1950 Гб на всеки диск обединихме в ZFS аналог на RAID-10:

zpool create zpool mirror /dev/sda2 /dev/sdb2 mirror /dev/sdc2 /dev/sdd2 mirror /dev/sde2 /dev/sdf2 mirror /dev/sdg2 /dev/sdh2

Направихме дялове за MySQL:

zfs create zpool/mysql
zfs set compression=gzip zpool/mysql
zfs set recordsize=128k zpool/mysql
zfs set atime=off zpool/mysql
zfs create zpool/mysql/data
zfs set recordsize=16k zpool/mysql/data
zfs set primarycache=metadata zpool/mysql/data
zfs set mountpoint=/var/lib/mysql zpool/mysql/data

Обърнете внимание, че включихме стандартното сжатие на данни gzip. Процесорните ресурси на нашия сървър са много и не се използват напълно. В резултат 3 Тб от нашата база данни се превърнаха в 1,6 Тб, а тъй като слабото звено, както и в предишния случай, е максималната производителност на дисковете, колкото по-малко данни — толкова по-добре, от самото начало получаваме отличен бонус от ZFS! В час пик при пълна натовареност за поддържане на работата на gzip отиват до 4 ядра, но на нас не ни е жал.

По-нататъшното внедряване протече по-бързо. По подобен начин прехвърлихме настройките на репликата на MySQL от LVM стенда. Трябваше да отделим известно време за преписване на скриптовете на команди ZFS, но общо взето алгоритмите останаха същите. Пример за създаване на моментна снимка:

zfs set snapdir=visible zpool/mysql/data
zfs create zpool/stage_3307
zfs clone zpool/mysql/data@snapmain zpool/stage_3307/data
zfs set mountpoint=/mnt/stage_3307 zpool/stage_3307/data

От допълнителните настройки: изнесохме в паметта ZFS-разделите с метаданни и логове l2arc и zil. За нашата задача, както се оказа по-късно, това беше излишно, но засега оставихме оптимизацията, лесно е да я променим при необходимост. От негативните ефекти — е необходимостта след рестартиране на сървъра да се преосновават съответните области на паметта. Данните не се губят. Изрезка zpool status:

logs
      /dev/shm/zil_slog.img  ONLINE       0     0     0
cache
      /dev/shm/l2arc.img     ONLINE       0     0     0

В тази конфигурация започнахме да тестваме стенда и получихме отлични резултати: с две работещи едновременно инстанции на БД (и активна основна реплика) на снапшотове дисковете бяха натоварени с 50-60%.

Спряхме основния си проблем, което се вижда на графика с отставането на репликацията (сравнете с предишната графика в секция Thin LVM):
Тънко резервиране на файлови системи Linux. Как да създадете резервни копия на три терабайтна MySQL база данни за 20 секунди

Освен и благодарение на това, значително ускорихме всички операции: пълното създаване на снапшот с спиране и стартиране на реплика отнема до 40 секунди, разгръщането на нова инстанция на MySQL от снапшот отнема до 20 секунди. Това повече от удовлетворява както нас, така и тестовете на програмния код.

Промеждинни заключения:

  • Резултатите напълно удовлетвориха нуждата ни от получаване на копия на работната БД за тестване на кода.
  • Технологията изисква навлизане: трябва да разберете какво е ZFS и как да работите с него.
  • Не проверявахме текущия статус на работата на ZFS с голямо количество (от 1 млн) малки файлове. Но предполагаме, че проблемът остава, затова не бих препоръчал тази файлова система за каквито и да било файлови хранилища.

Какво следва?

В рамките на стенда не правим нищо повече, резултатът ни удовлетворява. Възможно е в бъдеще да добавим изключения за таблици, ненужни за тестване, в настройките за репликация на стенда, което ще съкрати допълнително обема на БД. Не сме тествали системата BTRFS и нейната реализация на технологията за тънко резервиране. Въпреки това, такава задача вече не е на дневен ред, тъй като основната цел е постигната. В общи линии, разбира се, искаме да се отдалечим от описания подход — да реализираме работещи миграции на БД в тестова среда, да създадем отделен тестов контур на БД, да се занимаваме с шардирование на основната база. Много от това вече реализираме в живота, за което определено ще разкажем в бъдещите статии.

Резюме

Първоначалната задача беше решена, макар и по необичаен начин. В междинните изводи бяха описани предимствата и недостатъците на всяка от използваните технологии, така че да решим коя технология и кога може да се използва:

  • Thin LVM — за малки БД и когато не искаме или нямаме време да изучаваме ZFS.
  • ZFS — ако имаме опит с нея или възможност да отделим време за изучаване при всякакви ситуации.

На по-високо ниво на представяне, тази статия не е просто сравнение на технологиите на две файлови системи. Основната идея, която искам да предам и затвърдя, е, че не трябва да се страхувате да мислите нестандартно в ситуациите, критични за бизнеса, и да използвате само готови рецепти. Някога можехме всички в техническия департамент да поклатим глави и да кажем, че задачата за създаване на трите гигабайтни копия на БД за по-малко от минута е неизпълнима, и че не ни трябват рискови технологии; нека да направим както трябва. Това беше възможно, но щяхме да загубим около половин година до година и много клиентски пътувания (пътуванията са нашия основен бизнес показател) без тестове и по време на внедряване. Като постъпихме нестандартно, не загубихме толкова много време за внедряване, получихме опит в нови и забравени стари технологии и предоставихме тестове точно в момента, когато много ги нуждаехме. Несъмнено, това се отрази положително на всички наши показатели. Изборът винаги е ваш, а ние от своя страна ще продължим да разказваме в нашия блог за интересни текущи и бъдещи достижения.

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

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster