Migrācijas

MySQL ALTER TABLE bez dīkstāves: INSTANT, INPLACE, gh-ost vai pt-osc

Kolonnas pievienošana 2 TB tabulai var aizņemt sekundes daļu vai uz minūtēm iesaldēt lietotni. Kas notiks, atkarīgs no operācijas, algoritma un vienas ilgas transakcijas, par kuru jūs nezinājāt.

· 17 min lasīšanai · AG Data komanda

MySQL ALTER TABLE bez dīkstāves lielai tabulai lielākoties nozīmē pareizi izvēlēties metodi, pirms nospiežat Enter. Dažas izmaiņas skar tikai metadatus un beidzas uzreiz pat uz terabaitiem. Citas pārbūvē visu tabulu, prasa tikpat daudz brīvas vietas, cik aizņem pati tabula, un uz stundām atstāj katru repliku iepakaļ. Un jebkura no tām, pat tūlītējā, var iesaldēt lietotni, ja viena aizmirsta transakcija tur tabulu atvērtu. Lūk, kā saprast, kurā situācijā esat, un ko darīt.

Trīs algoritmi ar ļoti atšķirīgām izmaksām

InnoDB ir trīs veidi, kā izpildīt ALTER TABLE. MySQL rokasgrāmatas online DDL operāciju tabula norāda, kurus atbalsta katra izmaiņa:

Vienmēr norādiet algoritmu un bloķēšanas līmeni skaidri, piemēram, ALGORITHM=INSTANT vai ALGORITHM=INPLACE, LOCK=NONE. Ja izmaiņu tā nevar izpildīt, MySQL atgriež kļūdu, nevis klusi izvēlas ko smagāku. Kļūda testa serverī ir daudz labāka par negaidītu tabulas kopēšanu produkcijā.

Kas ir tūlītējs un kas nav

Labā ziņa ir tā, ka biežākās izmaiņas ir lētas. Saskaņā ar rokasgrāmatu INSTANT atbalsta:

ALTER TABLE orders ADD COLUMN source VARCHAR(32) NULL, ALGORITHM=INSTANT;

-- cik tūlītējo rindu versiju tabula jau izmantojusi? (limits: 64 versijā 8.4)
SELECT NAME, TOTAL_ROW_VERSIONS
FROM INFORMATION_SCHEMA.INNODB_TABLES
WHERE NAME = 'shop/orders';

Ilgi dzīvojošām tabulām svarīgi divi ierobežojumi. Katra tūlītēja pievienošana vai dzēšana izveido jaunu rindas versiju, un MySQL 8.4 atļauj ne vairāk kā 64 (no 9.1 versijas 255). Pēc tam saņemat ERROR 4092 (HY000): Maximum row versions reached, un nākamajai izmaiņai tabula jāpārbūvē. Pārbūve ar INPLACE, COPY vai OPTIMIZE TABLE atiestata skaitītāju. Tūlītēja kolonnas pievienošana nedarbojas arī tabulām ar ROW_FORMAT=COMPRESSED, tabulām ar FULLTEXT indeksu un pagaidu tabulām.

Šīs operācijas lielai tabulai sāp:

Ar skaidri norādītu algoritmu izmaiņa, ko nevar veikt uz vietas, uzreiz beidzas ar kļūdu. Rokasgrāmatas piemērs vienbaita rakstzīmju kopai, pārejot no VARCHAR(255) uz VARCHAR(256):

ALTER TABLE t ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(256);
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change
column type INPLACE. Try ALGORITHM=COPY.

Metadatu bloķēšanas rinda: kā "online" ALTER iesaldē produkciju

Tas ir viens no biežākajiem shēmas maiņas incidentiem, un tas notiek pat ar tūlītējām izmaiņām. Katram ALTER TABLE vajag ekskluzīvu metadatu bloķējumu uz tabulas, vismaz uz īsu brīdi. Rokasgrāmata apraksta secību precīzi:

  1. Kāda transakcija ir lasījusi no tabulas un vēl nav apstiprināta. Tā tur koplietojamu metadatu bloķējumu. Tā var būt atskaite, pakešuzdevums vai savienojums, ko lietotne atstājusi dīkstāvē transakcijas vidū.
  2. Jūsu ALTER TABLE pieprasa ekskluzīvo bloķējumu un gaida šo transakciju.
  3. Katrs jauns vaicājums uz tabulu tagad gaida aiz gaidošā ALTER, arī vienkārši SELECT.

No malas izskatās, ka tabula nestrādā. Savienojumi krājas, pūls izsīkst, un lietotne sāk kļūdīties, un tas viss vienas transakcijas dēļ, kas neko nedarīja. SHOW FULL PROCESSLIST parāda gaidošās sesijas.

Noklusējuma lock_wait_timeout ir 31536000 sekundes, tas ir, viens gads. Tātad pēc noklusējuma ALTER gaidīs un liks gaidīt visiem citiem praktiski bezgalīgi. Pirms jebkura DDL uz noslogotas tabulas samaziniet to savā sesijā un vispirms pārbaudiet ilgas transakcijas:

-- padoties pēc 5 sekundēm, nevis likt visiem gaidīt aiz mums
SET SESSION lock_wait_timeout = 5;
ALTER TABLE orders ADD INDEX idx_customer_created (customer_id, created_at),
  ALGORITHM=INPLACE, LOCK=NONE;

Ja bloķējums netiek piešķirts 5 sekundēs, ALTER beidzas ar kļūdu, rinda iztīrās, un varat mēģināt vēlāk. Neizdevies mēģinājums neko nemaksā, bet bloķēta tabula maksā incidentu. Šī metadatu bloķējuma gaidīšana atšķiras no InnoDB rindu bloķējumu gaidīšanas, ko aprakstām mūsu rakstā par lock wait timeout.

Lielas tabulas: disks, žurnāli un replikas

Dažu gigabaitu tabulai pārbūve uz vietas ir kafijas pauze. Pie simtiem gigabaitu pirms sākšanas pārbaudiet šo.

Ilgu ALTER var sekot līdzi caur Performance Schema posmu notikumiem. WORK_ESTIMATED darbības laikā var mainīties, tāpēc uztveriet to kā aptuvenu rādītāju:

UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
 WHERE NAME LIKE 'stage/innodb/alter%';
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES'
 WHERE NAME LIKE '%stages%';

SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED
FROM performance_schema.events_stages_current;

gh-ost un pt-online-schema-change

Ja izmaiņai vajag pārbūvi vai kopiju un tabula ir liela un noslogota, online shēmas maiņas rīki parasti ir labāka izvēle. Abi izveido jaunu tabulu ar jauno struktūru, kopē rindas mazās daļās, sinhronizē to ar notiekošo rakstīšanu un beigās samaina tabulas. Atšķirība ir sinhronizācijas veidā.

pt-online-schema-change no Percona Toolkit izmanto trigerus uz oriģinālās tabulas un samaina tabulas ar atomāru RENAME TABLE. Kas jāzina:

gh-ost no GitHub neizmanto trigerus. Tā vietā tas lasa izmaiņas no binārā žurnāla, tāpēc rakstīšana oriģinālajā tabulā neiedarbina papildu trigerus. Tā prasības:

Tā stiprā puse lielām tabulām ir kontrole: tas ierobežo darbu pēc repliku nobīdes ar --max-lag-millis, pēc slodzes ar --max-load, pārtrauc darbu pie --critical-load un var atlikt galīgo pārslēgšanu, līdz izdzēšat karoga failu, tāpēc maiņa notiek tad, kad jūs izvēlaties:

gh-ost --host=replica-1 --database=shop --table=orders \
  --alter="MODIFY amount DECIMAL(14,2) NOT NULL" \
  --max-lag-millis=1500 --max-load=Threads_running=30 \
  --critical-load=Threads_running=80 \
  --postpone-cut-over-flag-file=/tmp/ghost.postpone \
  --execute

Abi rīki kopē tabulu, tāpēc tiem vajag brīvu vietu pilnai otrai kopijai. Kopēšana sastāv no parastas rakstīšanas, tāpēc tā nonāk arī binārajā žurnālā un katrā replikā. Tas ir lēnāk nekā iebūvēta pārbūve, taču ierobežojams, apturams un tur replikas gandrīz aktuālas, un produkcijā parasti tieši to vajag.

Mūsu īkšķa likums: ja izmaiņa ir INSTANT, izpildiet to iebūvēti ar ALGORITHM=INSTANT un īsu lock_wait_timeout. Ja tā ir INPLACE bez pārbūves un tabula ir vidēja, izpildiet to iebūvēti mierīgā laikā. Ja tā pārbūvē vai kopē lielu tabulu vai replikām nedrīkst būt nobīde, izmantojiet gh-ost vai pt-online-schema-change. Un neatkarīgi no metodes vispirms pārbaudiet ilgas transakcijas.

Pārbaudes saraksts pirms ALTER lielai tabulai

  1. Noskaidrojiet algoritmu: izpildiet komandu ar skaidri norādītu ALGORITHM kopijā ar to pašu shēmu un skatieties, vai MySQL to pieņem.
  2. Tūlītējām izmaiņām pārbaudiet TOTAL_ROW_VERSIONS.
  3. Pārbūvēm pārbaudiet brīvo vietu datu direktorijā un tmpdir/innodb_tmpdir.
  4. Pārbaudiet ilgas un dīkstāvē esošas transakcijas uz tabulas un iestatiet savā sesijā īsu lock_wait_timeout.
  5. Novērtējiet ilgumu un repliku nobīdi uz pilna izmēra kopijas un izlemiet, vai der iebūvēts DDL vai rīks.
  6. Sagatavojiet svaigu, pārbaudītu rezerves kopiju un iepriekš izlemiet, kā apturēt vai atcelt.

Galvenās atziņas

MySQL Online DDL gh-ost pt-online-schema-change
Sadarbība ar mums

Vajag mainīt shēmu lielai MySQL tabulai?

Mēs plānojam un veicam shēmas izmaiņas lielās MySQL produkcijas tabulās: izvēlamies metodi, pārbaudām vietu un replikas, ierobežojam slodzi un veicam pārslēgšanu drošā logā.

Sazināties Vairāk no emuāra