Схемата на базата данни не е нещо, което е изписано в камък. Той е проектиран за дадено приложение, но тогава изискванията могат и обикновено се променят. Към приложението се добавят нови модули и функционалности, събират се повече данни, извършва се рефакторинг на код и модел на данни. По този начин необходимостта от модифициране на схемата на базата данни, за да се адаптира към тези промени; добавяне или модифициране на колони, създаване на нови таблици или разделяне на големи. Заявките също се променят, тъй като разработчиците добавят нови начини за взаимодействие на потребителите с данните – новите заявки могат да използват нови, по-ефективни индекси, така че ние бързаме да ги създадем, за да осигурим на приложението най-добрата производителност на базата данни.
И така, как най-добре да подходим към промяната на схемата? Какви инструменти са полезни? Как да сведем до минимум въздействието върху производствена база данни? Кои са най-често срещаните проблеми с дизайна на схеми? Какви инструменти могат да ви помогнат да останете на върха на вашата схема? В тази публикация в блога ще ви дадем кратък преглед на това как да правите промени в схемата в MySQL и MariaDB. Моля, имайте предвид, че няма да обсъждаме промените в схемата в контекста на Galera Cluster. Вече обсъдихме пълната изолация на поръчките, надстройките на непрекъснати схеми и съвети за минимизиране на въздействието от RSU в предишни публикации в блога. Ще обсъдим също съвети и трикове, свързани с дизайна на схемата и как ClusterControl може да ви помогне да останете в крак с всички промени в схемата.
Видове промени на схеми
Първо най-важното. Преди да се задълбочим в темата, трябва да разберем как MySQL и MariaDB извършват промени в схемата. Виждате, една промяна на схемата не е равна на друга промяна на схемата.
Може да сте чували за онлайн промени, незабавни промени или промени на място. Всичко това е резултат от продължаваща работа за минимизиране на въздействието на промените в схемата върху производствената база данни. Исторически погледнато, почти всички промени в схемата бяха блокирани. Ако сте изпълнили промяна на схемата, всички заявки ще започнат да се натрупват, изчаквайки ALTER да завърши. Очевидно това създава сериозни проблеми за внедряването на производството. Разбира се, хората веднага започват да търсят заобиколни решения и ние ще ги обсъдим по-късно в този блог, тъй като дори днес те са все още актуални. Но също така започна работа за подобряване на способността на MySQL да изпълнява DDL (език за дефиниране на данни) без много въздействие върху други заявки.
Незабавни промени
Понякога не е необходимо да се докосват никакви данни в табличното пространство, защото всичко, което трябва да се промени, са метаданните. Пример тук ще бъде пускането на индекс или преименуването на колона. Такива операции са бързи и ефективни. Обикновено тяхното въздействие е ограничено. Не е без никакво въздействие обаче. Понякога са необходими няколко секунди, за да се извърши промяната в метаданните и такава промяна изисква заключване на метаданни, за да бъде придобито. Това заключване е на база на таблица и може да блокира други операции, които трябва да се изпълнят на тази таблица. Ще видите това като записи „Изчакване на заключване на метаданните на таблицата“ в списъка с процеси.
Пример за такава промяна може да бъде моментално ADD COLUMN, въведено в MariaDB 10.3 и MySQL 8.0. Това дава възможност да се изпълни тази доста популярна промяна на схемата без никакво забавяне. Както MariaDB, така и Oracle решиха да включат код от Tencent Game, който позволява незабавно добавяне на нова колона към таблицата. Това е при някои специфични условия; колоната трябва да бъде добавена като последна, пълните текстови индекси не могат да съществуват в таблицата, форматът на реда не може да бъде компресиран - можете да намерите повече информация за това как работи колоната за незабавно добавяне в документацията на MariaDB. За MySQL единствената официална справка може да се намери в блога mysqlserverteam.com, въпреки че съществува грешка за актуализиране на официалната документация.
Промени на място
Някои от промените изискват промяна на данните в пространството за таблици. Такива модификации могат да се извършват върху самите данни и няма нужда да създавате временна таблица с нова структура от данни. Такива промени обикновено (макар и не винаги) позволяват да се изпълняват други заявки, докосващи таблицата, докато се изпълнява промяната на схемата. Пример за такава операция е добавянето на нов вторичен индекс към таблицата. Тази операция ще отнеме известно време, но ще позволи изпълнението на DML.
Преструктуриране на таблица
Ако не е възможно да се направи промяна на място, InnoDB ще създаде временна таблица с новата желана структура. След това ще копира съществуващите данни в новата таблица. Тази операция е най-скъпата и е вероятно (въпреки че не винаги се случва) да заключите DML. В резултат на това такава промяна на схемата е много трудна за изпълнение на голяма таблица на самостоятелен сървър, без помощта на външни инструменти - обикновено не можете да си позволите базата данни да бъде заключена за дълги минути или дори часове. Пример за такава операция е промяната на типа данни на колоната, например от INT на VARCHAR.
Промени в схемата и репликация
Добре, така че знаем, че InnoDB позволява онлайн промени в схемата и ако се консултираме с документацията на MySQL, ще видим, че по-голямата част от промените в схемата (поне сред най-често срещаните) могат да се извършват онлайн. Каква е причината да се отделят часове на разработка за създаване на онлайн инструменти за промяна на схеми като gh-ost? Можем да приемем, че pt-online-schema-change е остатък от старите, лоши времена, но gh-ost е нов софтуер.
Отговорът е сложен. Има два основни проблема.
Като за начало, след като започнете промяна на схемата, нямате контрол върху нея. Можете да го прекратите, но не можете да го поставите на пауза. Не можете да го задушите. Както можете да си представите, повторното изграждане на таблицата е скъпа операция и дори ако InnoDB позволява изпълнението на DML, допълнителното I/O работно натоварване от DDL засяга всички други заявки и няма начин да се ограничи това въздействие до ниво, което е приемливо за приложение.
Вторият, още по-сериозен проблем, е репликацията. Ако изпълните неблокираща операция, която изисква повторно изграждане на таблица, тя наистина няма да заключи DML, но това е вярно само за главния. Да приемем, че завършването на такъв DDL е отнело 30 минути - скоростта на ALTER зависи от хардуера, но е доста често да виждате такива времена за изпълнение на таблици с размери от 20 GB. След това се репликира на всички подчинени устройства и от момента, в който DDL стартира на тези подчинени устройства, репликацията ще изчака да завърши. Няма значение дали използвате MySQL или MariaDB, или ако имате многонишкова репликация. Подчинените ще изостават - те ще изчакат тези 30 минути, за да завърши DDL, преди да започнат да прилагат останалите binlog събития. Както можете да си представите, 30 минути забавяне (понякога дори 30 секунди няма да са приемливи - всичко зависи от приложението) е нещо, което прави невъзможно използването на тези подчинени устройства за мащабиране. Разбира се, има заобиколни решения - можете да извършвате промени в схемата от долната до горната част на веригата за репликация, но това сериозно ограничава вашите възможности. Особено ако използвате репликация, базирана на редове, можете да изпълнявате само съвместими промени в схемата по този начин. Няколко примера за ограничения на репликация, базирана на редове; не можете да пуснете колона, която не е последната, не можете да добавите колона на позиция, различна от последната. Не можете също да промените типа на колоната (например INT -> VARCHAR).
Както можете да видите, репликацията добавя сложност към начина, по който можете да извършвате промени в схемата. Операциите, които са неблокиращи на самостоятелния хост, стават блокиращи, докато се изпълняват на подчинени. Нека да разгледаме няколко метода, които можете да използвате, за да сведете до минимум въздействието на промените в схемата.
Онлайн инструменти за промяна на схема
Както споменахме по-рано, има инструменти, които са предназначени да извършват промени в схемата. Най-популярните са pt-online-schema-change, създадена от Percona и gh-ost, създадена от GitHub. В поредица от публикации в блога ги сравнихме и обсъдихме как gh-ost може да се използва за извършване на промени в схемата и как можете да намалите и преконфигурирате преминаваща миграция. Тук няма да навлизаме в подробности, но все пак бихме искали да споменем някои от най-важните аспекти на използването на тези инструменти. Като за начало промяна на схемата, изпълнена чрез pt-osc или gh-ost, ще се случи на всички възли на базата данни наведнъж. Няма никакво забавяне по отношение на това кога промяната ще бъде приложена. Това прави възможно използването на тези инструменти дори за промени в схемата, които са несъвместими с репликация, базирана на редове. Точните механизми за това как тези инструменти проследяват промените в таблицата са различни (задействания в pt-osc срещу binlog синтактичен анализ в gh-ost), но основната идея е същата – създава се нова таблица с желаната схема и съществуващите данни са копирано от старата таблица. Междувременно DML се проследяват (по един или друг начин) и се прилагат към новата таблица. След като всички данни бъдат мигрирани, таблиците се преименуват и новата таблица заменя старата. Това е атомна операция, така че не се вижда от приложението. И двата инструмента имат опция за дроселиране на натоварването и пауза на операциите. Gh-ost може да спре цялата дейност, само pt-osc може да спре процеса на копиране на данни между старата и новата таблица - тригерите ще останат активни и ще продължат да дублират данни, което добавя някои допълнителни разходи. Поради таблицата за преименуване и двата инструмента имат някои ограничения по отношение на външните ключове - не се поддържат от gh-ost, частично се поддържат от pt-osc или чрез обикновен ALTER, което може да причини забавяне на репликацията (неосъществимо, ако дъщерната таблица е голяма) или чрез изтриване на старата таблица преди преименуване на новата - това е опасно, тъй като няма начин за връщане назад, ако по някаква причина данните не са копирани в новата таблица правилно. Тригерите също са трудни за поддръжка.
Те не се поддържат в gh-ost, pt-osc в MySQL 5.7 и по-нови имат ограничена поддръжка за таблици със съществуващи тригери. Други важни ограничения за онлайн инструменти за промяна на схеми е, че уникален или първичен ключ трябва да съществува в таблицата. Използва се за идентифициране на редове за копиране между стари и нови таблици. Тези инструменти също са много по-бавни от директния ALTER – промяна, която отнема часове, докато се изпълнява ALTER, може да отнеме дни, когато се извършва с pt-osc или gh-ost.
От друга страна, както споменахме, докато изискванията са изпълнени и ограниченията няма да влязат в игра, можете да изпълнявате всички промени в схемата, като използвате един от инструментите. Всичко ще се случи по едно и също време на всички хостове, така че не е нужно да се притеснявате за съвместимостта. Освен това имате известно ниво на контрол върху това как се изпълнява процесът (по-малко в pt-osc, много повече в gh-ost).
Можете да намалите въздействието на промяната на схемата, можете да ги поставите на пауза и да ги оставите да работят само под наблюдение, можете да тествате промяната, преди действително да я изпълните. Можете да ги накарате да проследяват забавянето на репликацията и да поставят на пауза, ако бъде открит удар. Това прави тези инструменти наистина страхотно допълнение към арсенала на DBA, докато работите с MySQL репликация.
Постоянни промени в схемата
Обикновено DBA ще използва един от онлайн инструментите за промяна на схеми. Но както обсъдихме по-рано, при някои обстоятелства те не могат да се използват и директната промяна е единствената жизнеспособна опция. Ако говорим за самостоятелен MySQL, нямате избор - ако промяната е неблокираща, това е добре. Ако не е, добре, нищо не можете да направите по въпроса. Но тогава не толкова много хора изпълняват MySQL като единични екземпляри, нали? Какво ще кажете за репликацията? Както обсъдихме по-рано, директната промяна на главния не е осъществима - в повечето случаи това ще доведе до забавяне на подчинения и това може да не е приемливо. Това, което може да се направи обаче, е промяната да се извърши по плавно. Можете да започнете с подчинени и, след като промяната бъде приложена към всички тях, да повишите един от подчинените като нов главен, да понижите стария господар до роб и да изпълните промяната върху него. Разбира се, промяната трябва да е съвместима, но, честно казано, най-честите случаи, в които не можете да използвате промените в онлайн схемата, са поради липса на първичен или уникален ключ. За всички останали случаи има някакво решение, особено в pt-online-schema-change, тъй като gh-ost има по-строги ограничения. Това е заобиколно решение, което бихте нарекли „така така“ или „далеч от идеалното“, но ще свърши работа, ако нямате друга възможност да избирате. Освен това е важно, че повечето от ограниченията могат да бъдат избегнати, ако наблюдавате схемата си и улавяте проблемите, преди таблицата да нарасне. Дори ако някой създаде таблица без първичен ключ, не е проблем да се изпълни директна промяна, която отнема половин секунда или по-малко, тъй като таблицата е почти празна.
Ако се разрасне, това ще се превърне в сериозен проблем, но от DBA зависи да хване този вид проблеми, преди те всъщност да започнат да създават проблеми. Ще разгледаме някои съвети и трикове как да сте сигурни, че ще хванете подобни проблеми навреме. Ще споделим и общи съвети как да проектирате схемите си.
Съвети и трикове
Дизайн на схема
Както показахме в тази публикация, онлайн инструментите за промяна на схеми са доста важни, когато работите с настройка за репликация, затова е много важно да се уверите, че вашата схема е проектирана по такъв начин, че да не ограничава възможностите ви за извършване на промени в схемата. Има три важни аспекта. Първо, трябва да съществува първичен или уникален ключ - трябва да се уверите, че няма таблици без първичен ключ във вашата база данни. Трябва да наблюдавате това редовно, в противен случай това може да се превърне в сериозен проблем в бъдеще. Второ, трябва сериозно да помислите дали използването на външни ключове е добра идея. Разбира се, те имат своите приложения, но също така добавят допълнителни разходи към вашата база данни и могат да направят проблематично използването на онлайн инструменти за промяна на схеми. Отношенията могат да бъдат наложени чрез приложението. Дори ако това означава повече работа, все пак може да е по-добра идея, отколкото да започнете да използвате външни ключове и да бъдете строго ограничени до това кои типове промени в схемите могат да бъдат извършени. Трето, тригери. Същата история като с външните ключове. Те са приятна функция, но могат да се превърнат в тежест. Трябва сериозно да помислите дали ползите от използването им надвишават ограниченията, които поставят.
Проследяване на промените в схемата
Управлението на промените в схемата не е само за извършване на промени в схемата. Вие също трябва да сте на върха на структурата на вашата схема, особено ако не сте единственият, който прави промените.
ClusterControl предоставя на потребителите инструменти за проследяване на някои от най-често срещаните проблеми с дизайна на схеми. Може да ви помогне да проследявате таблици, които нямат първични ключове:
Както обсъдихме по-рано, ранното улавяне на такива таблици е много важно, тъй като първичните ключове трябва да се добавят чрез директна промяна.
ClusterControl може също да ви помогне да проследявате дублиращи се индекси. Обикновено не искате да имате множество индекси, които са излишни. В примера по-горе можете да видите, че има индекс на (k, c) и също така има индекс на (k). Всяка заявка, която може да използва индекс, създаден в колона „k“, може също да използва съставен индекс, създаден върху колони (k, c). Има случаи, в които е полезно да поддържате излишни индекси, но трябва да подхождате към това за всеки отделен случай. Започвайки от MySQL 8.0, е възможно бързо да се тества дали индексът наистина е необходим или не. Можете да направите излишния индекс „невидим“, като изпълните:
ALTER TABLE sbtest.sbtest1 ALTER INDEX k_1 INVISIBLE;
Това ще накара MySQL да игнорира този индекс и чрез наблюдение можете да проверите дали е имало отрицателно въздействие върху производителността на базата данни. Ако всичко работи по план за известно време (няколко дни или дори седмици), можете да планирате да премахнете излишния индекс. В случай, че откриете, че нещо не е наред, винаги можете да активирате отново този индекс, като изпълните:
ALTER TABLE sbtest.sbtest1 ALTER INDEX k_1 VISIBLE;
Тези операции са мигновени и индексът е там през цялото време и все още се поддържа - само че няма да бъде взет под внимание от оптимизатора. Благодарение на тази опция премахването на индекси в MySQL 8.0 ще бъде много по-безопасна операция. В предишните версии повторното добавяне на неправилно премахнат индекс може да отнеме часове, ако не и дни на големи таблици.
ClusterControl може също да ви уведоми за MyISAM таблици.
Въпреки че MyISAM все още може да има своите приложения, трябва да имате предвид, че това не е транзакционна машина за съхранение. Като такъв, той може лесно да въведе несъответствие на данните между възлите в настройката за репликация.
Друга много полезна функция на ClusterControl е един от оперативните отчети – отчет за промяна на схемата.
В идеалния свят DBA преглежда, одобрява и прилага всички промени в схемата. За съжаление това не винаги е така. Такъв процес на преглед просто не върви добре с гъвкавото развитие. В допълнение към това съотношението разработчик към DBA обикновено е доста високо, което също може да се превърне в проблем, тъй като DBA ще се борят да не се превърнат в пречка. Ето защо не е необичайно да видите промени в схемата, извършвани извън знанието на DBA. И все пак, DBA обикновено е този, който отговаря за производителността и стабилността на базата данни. Благодарение на отчета за промяна на схемата те вече могат да следят промените в схемата.
Първоначално е необходима някаква конфигурация. В конфигурационен файл за даден клъстер (/etc/cmon.d/cmon_X.cnf) трябва да дефинирате на кой хост ClusterControl да проследява промените и кои схеми да се проверяват.
schema_change_detection_address=10.0.0.126
schema_change_detection_databases=sbtest
След като това е направено, можете да насрочите отчет да се изпълнява редовно. Примерен изход може да бъде като по-долу:
Както можете да видите, две таблици са се променили от предишното изпълнение на отчета. В първия е създаден нов съставен индекс върху колони (k, c). Във втората таблица беше добавена колона.
При следващото изпълнение получихме информация за нова таблица, която беше създадена без индекс или първичен ключ. Използвайки този вид информация, можем лесно да действаме, когато е необходимо, и да разрешим проблемите, преди те всъщност да започнат да се превръщат в блокиращи.