„MySQL for Zabbix“ skaidymas naudojant daugybę stebėjimo objektų

Serveriams ir paslaugoms stebėti ilgą laiką ir vis dar sėkmingai naudojame kombinuotą sprendimą, pagrįstą Nagios ir Munin. Tačiau šis derinys turi nemažai trūkumų, todėl mes, kaip ir daugelis, aktyviai išnaudojame Zabbix. Šiame straipsnyje mes kalbėsime apie tai, kaip su minimaliomis pastangomis galite išspręsti našumo problemą, kai padidinsite imtų metrikų skaičių ir padidinsite MySQL duomenų bazės apimtis.

Problemos naudojant MySQL duomenų bazę su Zabbix

Nors duomenų bazė buvo maža ir joje saugomų metrikų skaičius buvo mažas, viskas buvo puiku. Standartinis namų ruošos procesas, kurį paleidžia pats „Zabbix Server“, sėkmingai ištrynė pasenusius įrašus iš duomenų bazės, neleidžiant jai augti. Tačiau kai tik imtų metrikų skaičius padidėjo ir duomenų bazės dydis pasiekė tam tikrą dydį, viskas pablogėjo. Houserkeeper nustojo ištrinti duomenis per jam skirtą laiko intervalą, o seni duomenys pradėjo likti duomenų bazėje. Kol namų tvarkytoja dirbo, Zabbix serverio apkrova buvo padidinta, kuri galėjo išlikti ilgą laiką. Tapo aišku, kad turime kažkaip išspręsti esamą situaciją.

Tai žinoma problema, beveik visi, dirbę su dideliais Zabbix stebėjimo kiekiais, susidūrė su tuo pačiu. Taip pat buvo keletas sprendimų: pavyzdžiui, MySQL pakeitimas PostgreSQL ar net Elasticsearch, tačiau paprasčiausias ir labiausiai pasiteisinęs sprendimas buvo perėjimas prie skirstymo lentelių, kuriose saugomi metrikos duomenys MySQL duomenų bazėje. Nusprendėme eiti būtent šiuo keliu.

Perėjimas nuo įprastų MySQL lentelių prie skaidinių

„Zabbix“ yra gerai dokumentuota, o lentelės, kuriose ji saugo metriką, yra žinomos. Štai tokios lentelės: history, kur saugomos slankiosios vertės, history_str, kur saugomos trumpos eilučių reikšmės, history_text, kur saugomos ilgos teksto reikšmės ir history_uint, kur saugomos sveikųjų skaičių reikšmės. Taip pat yra stalas trends, kuriame saugoma pokyčių dinamika, tačiau nusprendėme jo neliesti, nes jo dydis nedidelis ir prie jo grįšime kiek vėliau.

Apskritai buvo aišku, kurias lenteles reikia apdoroti. Nusprendėme kiekvienai savaitei, išskyrus paskutinę, daryti pertvaras pagal mėnesio skaičius, t.y. keturios partijos per mėnesį: nuo 1 iki 7 d., nuo 8 iki 14 d., nuo 15 iki 21 ir nuo 22 iki 1 (kito mėnesio). Sunkumas buvo tas, kad mums reikalingas lenteles reikėjo paversti skaidytomis „skraidydamas“, nepertraukiant „Zabbix Server“ veikimo ir metrikos rinkimo.

Kaip bebūtų keista, čia mums padėjo pati lentelių duomenų struktūra. Pavyzdžiui, lentelė history turi tokią struktūrą:

`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`value` double(16,4) NOT NULL DEFAULT '0.0000',
`ns` int(11) NOT NULL DEFAULT '0',

tuo pačiu metu

KEY `history_1` (`itemid`,`clock`)

Kaip matote, kiekviena metrika galiausiai įtraukiama į lentelę su dviem mums labai svarbiais ir patogiais laukais itemid и laikrodis. Taigi, mes galime lengvai sukurti laikiną lentelę, pavyzdžiui, su pavadinimu history_tmp, nustatykite jo skaidymą ir tada perkelkite visus duomenis iš lentelės ten historytada pervardykite lentelę history в history_old, ir stalas history_tmp в history, tada pridėkite duomenis, kurių neužpildėme history_old в history ir ištrinti history_old. Tai galima padaryti visiškai saugiai, nieko neprarasime, nes aukščiau pateikti laukai itemid и laikrodis pateikti tam tikros metrikos susiejimą su konkrečiu laiku, o ne su kokiu nors serijos numeriu.

Pati perėjimo procedūra

Dėmesio! Labai patartina prieš pradedant bet kokius veiksmus pasidaryti visą duomenų bazės atsarginę kopiją. Visi esame gyvi žmonės ir komandų rinkinyje galime padaryti klaidą, o tai gali sukelti duomenų praradimą. Taip. Atsarginė kopija neužtikrins maksimalaus atnaujinimo, bet geriau turėti tokią, nei jokios.

Taigi, nieko neišjungiame ir nieko nestabdome. Svarbiausia, kad pačiame MySQL serveryje būtų pakankamai laisvos vietos diske, t.y. kad kiekvienai iš aukščiau išvardytų lentelių history, history_text, history_str, history_uint, bent jau buvo pakankamai vietos sukurti lentelę su priesaga „_tmp“, atsižvelgiant į tai, kad ji bus tokio pat dydžio kaip ir originali lentelė.

Mes neaprašysime visko kelis kartus kiekvienai iš aukščiau pateiktų lentelių ir viską apsvarstysime tik vienos iš jų pavyzdžiu - lentelės history.

Taigi, sukurkime tuščią lentelę history_tmp remiantis lentelės struktūra history.

CREATE TABLE `history_tmp` LIKE `history`;

Sukuriame mums reikalingas pertvaras. Pavyzdžiui, darykime tai mėnesį. Kiekvienas skaidinys sukuriamas pagal skaidymo taisyklę, pagrįstą lauko verte laikrodis, kurią lyginame su laiko žyma:

ALTER TABLE `history_tmp` PARTITION BY RANGE( clock ) (
PARTITION p20190201 VALUES LESS THAN (UNIX_TIMESTAMP("2019-02-01 00:00:00")),
PARTITION p20190207 VALUES LESS THAN (UNIX_TIMESTAMP("2019-02-07 00:00:00")),
PARTITION p20190214 VALUES LESS THAN (UNIX_TIMESTAMP("2019-02-14 00:00:00")),
PARTITION p20190221 VALUES LESS THAN (UNIX_TIMESTAMP("2019-02-21 00:00:00")),
PARTITION p20190301 VALUES LESS THAN (UNIX_TIMESTAMP("2019-03-01 00:00:00"))
);

Šis operatorius prideda mūsų sukurtos lentelės skaidymą history_tmp. Paaiškinkime tuos duomenis, kurių lauko reikšmė laikrodis mažiau nei „2019-02-01 00:00:00“ bus įtraukta į paketą p20190201, tada duomenys, kurių lauko reikšmė laikrodis daugiau nei „2019-02-01 00:00:00“, bet mažiau nei „2019-02-07 00:00:00“ bus įtraukta į skaidinį p20190207 ir taip toliau.

Svarbi pastaba: Kas atsitiks, jei padalintoje lentelėje turime duomenų, kurių reikšmė laikrodžio lauke yra didesnė arba lygi „2019-03-01 00:00:00“? Kadangi šiems duomenims nėra tinkamo skaidinio, jie nebus rodomi lentelėje ir bus prarasti. Todėl reikia nepamiršti laiku sukurti papildomų skaidinių, kad išvengtumėte tokių duomenų praradimų (kaip aptarta toliau).

Taigi, laikina lentelė yra paruošta. Užpildykite duomenis. Procesas gali užtrukti gana ilgai, bet, laimei, jis neblokuoja jokių kitų užklausų, todėl tereikia apsišarvuoti kantrybe:

INSERT IGNORE INTO `history_tmp` SELECT * FROM history;

Pirminio pildymo metu IGNORE raktažodis nereikalingas, nes lentelėje vis tiek duomenų nėra, tačiau pildant duomenis jų prireiks. Be to, gali būti naudinga, jei įkeldami duomenis turėjote nutraukti šį procesą ir pradėti iš naujo.

Taigi po kurio laiko (gal net kelių valandų) įvyko pirmasis duomenų įkėlimas. Kaip suprantate, dabar lentelė history_tmp nėra visų lentelės duomenų history, bet tik tuos, kurie buvo jame tuo metu, kai buvo pateikta užklausa. Čia jūs iš tikrųjų turite pasirinkimą: arba atliekame dar vieną eigą (jei pildymo procesas užtruko ilgai), arba iš karto pereiname prie lentelių pervadinimo, kaip buvo minėta aukščiau. Pirmiausia pakalbėkime apie antrąjį praėjimą. Pirmiausia turime suprasti paskutinio įterpto įrašo laiką history_tmp:

SELECT max(clock) FROM history_tmp;

Tarkime, kad gavote: 1551045645. Dabar gautą reikšmę naudojame antrajame duomenų pildymo etape:

INSERT IGNORE INTO `history_tmp` SELECT * FROM history WHERE clock>=1551045645;

Ši ištrauka turėtų baigtis daug greičiau. Bet jei pirmasis praėjimas užtruko valandas, o antrasis taip pat užtruko ilgai, gali būti teisinga atlikti trečią perdavimą, kuris atliekamas lygiai taip pat, kaip ir antrasis.

Galiausiai vėl atliekame paskutinio įrašo įterpimo laiko gavimo operaciją history_tmpbėgant:

SELECT max(clock) FROM history_tmp;

Tarkime, kad gavote 1551085645. Išsaugokite šią vertę – jos mums prireiks papildymui.

Ir dabar, iš tikrųjų, kai pradinis duomenų pildymas history_tmp baigta, pradėkime pervardyti lenteles:

BEGIN;
RENAME TABLE history TO history_old;
RENAME TABLE history_tmp TO history;
COMMIT;

Šį bloką suprojektavome kaip vieną operaciją, kad būtų išvengta duomenų įterpimo į neegzistuojančią lentelę, nes po pirmojo PERVARDINIMO iki antrojo RENAME įvykdymo lentelė history nebus. Bet net jei tarp RENAME operacijų į lentelę history kai kurie duomenys atkeliaus, bet pačios lentelės dar nebus (dėl pervadinimo), gausime nedaug įterpimo klaidų, kurių galima nepaisyti (turime monitoringą, o ne banką).

Dabar turime naują stalą history su skaidymu, tačiau trūksta duomenų, kurie buvo gauti paskutinio duomenų įterpimo į lentelę metu history_tmp. Bet mes turime šiuos duomenis lentelėje history_old ir dabar mes juos papildysime iš ten. Norėdami tai padaryti, mums reikia anksčiau išsaugotos reikšmės 1551085645. Kodėl išsaugojome šią reikšmę ir nepanaudojome maksimalaus užpildymo laiko iš dabartinės lentelės history? Nes į jį jau patenka nauji duomenys ir sulauksime netinkamo laiko. Taigi, pridėkime duomenis:

INSERT IGNORE INTO `history` SELECT * FROM history_old WHERE clock>=1551045645;

Kai ši operacija bus baigta, mūsų naujoje, atskirtoje lentelėje history yra visi duomenys, kurie buvo senajame, plius tie, kurie jau atkeliavo pervadinus lentelę. Lentelė history_old mums jo nebereikia. Galite ištrinti jį iš karto arba galite padaryti atsarginę kopiją prieš ištrindami (jei esate paranojiškas).

Visą aukščiau nurodytą procesą reikia pakartoti lentelėms history_str, history_text и history_uint.

Ką reikia pataisyti Zabbix serverio nustatymuose

Dabar duomenų bazės priežiūra duomenų istorijos požiūriu gula ant mūsų pečių. Tai reiškia, kad „Zabbix“ nebereikia trinti senų duomenų – tai padarysime patys. Kad „Zabbix Server“ nebandytų išvalyti duomenų, turite eiti į „Zabbix“ žiniatinklio sąsają, meniu pasirinkti „Administravimas“, tada submeniu „Bendra“, tada išskleidžiamajame sąraše pasirinkti „Išvalyti istoriją“. dešinė. Pasirodžiusiame puslapyje turite panaikinti visų grupės „Istorija“ langelių žymėjimą ir spustelėti mygtuką „Atnaujinti“. Tai neleis mums be reikalo išvalyti lentelių history* per namų tvarkytoją.

Tame pačiame puslapyje atkreipkite dėmesį į grupę „Pokyčių dinamika“. Tai tik lentelė trends, į kurią pažadėjome sugrįžti. Jei ji taip pat tapo per didelė ir ją reikia skaidyti, atžymėkite šios grupės langelius ir apdorokite lentelę taip pat, kaip darėte lenteles history*.

Tolesnė duomenų bazės priežiūra

Kaip buvo rašyta anksčiau, norint normaliai veikti skaidytose lentelėse, būtina laiku sukurti skaidinius. Tai galite padaryti taip:

ALTER TABLE `history` ADD PARTITION (PARTITION p20190307 VALUES LESS THAN (UNIX_TIMESTAMP("2019-03-07 00:00:00")));

Be to, kadangi sukūrėme skaidytas lenteles ir uždraudėme „Zabbix Server“ jų valyti, senų duomenų ištrynimas dabar yra mūsų rūpestis. Laimei, čia nėra jokių problemų. Tai daroma tiesiog ištrinant skaidinį, kurio duomenų mums nebereikia.

Pavyzdžiui:

ALTER TABLE history DROP PARTITION p20190201;

Skirtingai nuo DELETE FROM teiginių, nurodančių dienų seką, DROP PARTITION vykdomas per kelias sekundes, visiškai neįkrauna serverio ir veikia taip pat sklandžiai naudojant replikaciją MySQL.

išvada

Aprašytas sprendimas buvo patikrintas laiko. Duomenų kiekis auga, tačiau pastebimo našumo sulėtėjimo nėra.

Šaltinis: www.habr.com

Добавить комментарий