ClickHouse "Too many parts" parasti parādās dienā, kad viss pārējais izskatās normāli. Ievietošana sāk aizņemt ilgāku laiku, tad datu plūsma sāk izgāzties ar Too many parts (N). Merges are processing significantly slower than inserts, un dati sāk krāties rindās vai pazust. Kļūdas ziņojums ir godīgs: ClickHouse rada datu daļas ātrāk, nekā spēj tās apvienot. Risinājums gandrīz nekad nav limita palielināšana. Tas ir radīt mazāk daļu.
Kā darbojas daļas un apvienošana
Katrs INSERT MergeTree tabulā ieraksta vismaz vienu jaunu daļu (part): direktoriju ar sakārtotiem, saspiestiem kolonnu failiem diskā. ClickHouse neatjaunina lielu failu uz vietas. Tā vietā fona apvienošana (merge) pastāvīgi apvieno mazas daļas lielākās. Tieši tas padara ievietošanu ātru un vaicājumus efektīvus, kamēr apvienošana tiek līdzi.
Šai kļūdai svarīgas divas detaļas:
- Ievietošana rada vismaz vienu daļu katram nodalījumam (partition), ko tā skar. Viens
INSERTar rindām 50 dažādiem nodalījumiem ieraksta 50 daļas. - Apvienošana notiek tikai nodalījuma ietvaros. Daļas no dažādiem nodalījumiem nekad netiek apvienotas.
Materializētie skati to pastiprina. Katra ievietošana avota tabulā ievieto datus arī katra skata mērķa tabulā, tāpēc arī katrā mērķa tabulā rodas jaunas daļas.
Limiti aiz kļūdas
ClickHouse sevi aizsargā ar MergeTree iestatījumiem, kas reaģē uz aktīvo daļu skaitu:
parts_to_delay_insert(noklusējums 1000): kad nodalījumā ir tik daudz aktīvo daļu, ClickHouse tīši sāk palēnināt ievietošanu, lai dotu apvienošanai iespēju panākt.parts_to_throw_insert(noklusējums 3000; pirms versijas 23.6 tas bija 300): virs šī aktīvo daļu skaita vienā nodalījumā ievietošana izgāžas ar "Too many parts".max_parts_in_total(noklusējums 100 000): limits aktīvajām daļām visā tabulā. To sasniedz, ja ir pārāk daudz nodalījumu, nevis pārāk daudz daļu vienā.
Aizkaves fāze ir jūsu agrīnais brīdinājums. Ja ievietošana dienām ilgi kļuvusi lēnāka, bieži iemesls ir tieši šis.
1. solis: atrodiet, kur ir daļas
Sāciet ar aktīvajām daļām katrā nodalījumā, kā iesaka ClickHouse problēmu novēršanas ceļvedis:
SELECT database, table, partition_id,
count() AS active_parts,
formatReadableSize(sum(bytes_on_disk)) AS size,
formatReadableSize(avg(bytes_on_disk)) AS avg_part
FROM system.parts
WHERE active
GROUP BY database, table, partition_id
ORDER BY active_parts DESC
LIMIT 20;
Lasiet rezultātu, paturot prātā trīs jautājumus:
- Viens nodalījums ar tūkstošiem mazu daļu? Kaut kas tajā raksta mazas, biežas ievietošanas. To atklāj vidējais daļas izmērs dažu kilobaitu vai megabaitu apmērā.
- Tūkstošiem nodalījumu ar dažām daļām katrā? Nodalījumu atslēga ir pārāk sīka, piemēram, pa lietotājiem, ierīcēm vai stundām uz gadiem datu. Jūs tuvojaties
max_parts_in_total, un cieš arī vaicājumi. - Daļas ir normāla izmēra, bet tik un tā krājas? Ievietošana var būt kārtībā, un problēma ir apvienošanā.
2. solis: pārbaudiet, vai apvienošana tiešām notiek
SELECT database, table, round(elapsed) AS sec,
round(progress * 100) AS pct, num_parts,
formatReadableSize(total_size_bytes_compressed) AS size
FROM system.merges
ORDER BY elapsed DESC;
Ja apvienošana notiek, bet lēni, skatieties uz serveri: diska caurlaidību, brīvo vietu diskā (apvienošanai vajag vietu jaunās daļas ierakstīšanai, pirms vecās tiek dzēstas), CPU un konkurējošu fona darbu, piemēram, mutācijas. Ja nekas netiek apvienots vispār, pārbaudiet servera žurnālā apvienošanas kļūdas un to, vai kāds apkopes laikā neizpildīja SYSTEM STOP MERGES un nekad neizpildīja SYSTEM START MERGES.
3. solis: pārtrauciet radīt tik daudz daļu
Šis ir īstais risinājums, un parasti tas ir lietotnes pusē.
Grupējiet ievietošanas. ClickHouse iesaka paketes ar vismaz 1000 rindām, ideāli 10 000 līdz 100 000, un aptuveni vienu ievietošanas vaicājumu sekundē uz tabulu. Serviss, kas sūta vienu rindu katrā HTTP pieprasījumā no piecdesmit podiem, var radīt tūkstošiem daļu minūtē. Buferējiet lietotnē, rindas patērētājā vai datu ielādes rīkā un izlādējiet pēc izmēra vai laika.
Izmantojiet asinhrono ievietošanu, ja grupēšana klientā nav praktiska. Ar async_insert = 1 serveris savāc mazas ievietošanas buferī un ieraksta tās kā vienu daļu, kad buferis sasniedz izmēra, laika vai vaicājumu skaita slieksni:
INSERT INTO events
SETTINGS async_insert = 1, wait_for_async_insert = 1
VALUES (...);
Paturiet wait_for_async_insert = 1, kas ir noklusējums. Tad klients saņem apstiprinājumu tikai pēc tam, kad dati ir ierakstīti. Vērtība 0 padara ievietošanu par "aizsūti un aizmirsti", un ClickHouse dokumentācija to sauc par ļoti riskantu, jo klients var nekad neuzzināt, ka ievietošana neizdevās.
Salabojiet nodalījumu atslēgu. Nodalījumi ir datu pārvaldības rīks, nevis indekss. Mēneša nodalījums pēc datuma kolonnas ir klasiska izvēle; dienas nodalījums var būt jēgpilns lielam apjomam ar īsu glabāšanas laiku. Nodalīšana pēc lietotāja ID, klienta ID vai jebkā ar tūkstošiem vērtību vairo daļas un neļauj apvienošanai darīt savu darbu. Nodalījumu atslēgas maiņa nozīmē jaunas tabulas izveidi un datu pārvietošanu, tāpēc izvēlieties pareizi jau sākumā. Mēs to pieminējām, aprakstot, kā veidojam ClickHouse datu noliktavas no mantotiem datiem.
parts_to_throw_insert palielināšana uz laiku liks kļūdai pazust, un īstā ārkārtas situācijā īslaicīgs palielinājums var uzturēt datu plūsmu, kamēr salabojat avotu. Taču ClickHouse ceļvedis skaidri saka, ka tas nav risinājums: vairāk daļu nozīmē vairāk failu un metadatu, lēnākus vaicājumus, un tā pati siena atgriežas vēlāk, augstāka un grūtāk pārvarama. Ja to palielināt, pierakstiet, kad un kāpēc, un atjaunojiet vērtību, kad daļu skaits ir normāls.
Kā izkļūt no bedres
Kad mazo daļu avots ir novērsts, apvienošana parasti panāk pati. Sekojiet aktīvo daļu skaitam no 1. soļa: tam vajadzētu nostabilizēties un tad kristies. Vienam stipri sadrumstalotam nodalījumam var piespiest apvienošanu ar OPTIMIZE TABLE ... PARTITION ..., taču lielai tabulai tas ir smags darbs, tāpēc izpildiet to ārpus maksimālās slodzes stundām, vienu nodalījumu vienlaikus, un izvairieties no FINAL uz veselām lielām tabulām. Pirms sākat, pārliecinieties, ka diskā ir pietiekami brīvas vietas.
Dati, kurus incidenta laikā neizdevās ievietot, ir cits jautājums. Ja jūsu datu avoti neatkārto mēģinājumus vai rindas glabāšanas laiks ir īsāks par dīkstāvi, daļa datu ir zaudēta. Pārbaudiet, ko jūsu plūsma dara ar neizdevušos ievietošanu, pirms nākamā incidenta, nevis tā laikā.
Uzraugiet to, pirms tas salūzt
- Maksimālais aktīvo daļu skaits nodalījumā katrai tabulai, ar brīdinājumu krietni zem
parts_to_delay_insert. - Kopējais aktīvo daļu skaits tabulā salīdzinājumā ar
max_parts_in_total. - Ievietošanas latentums un kļūdas jūsu datu plūsmā.
- Notiekošo apvienošanu skaits un ilgums, kā arī brīvā vieta datu sējumā.
Šie rādītāji pieder tajā pašā panelī, kur pārējie rādītāji, kas prognozē datubāzes incidentus. Lēns daļu skaita pieaugums ir redzams dienām ilgi pirms pirmās neizdevušās ievietošanas.
Galvenās atziņas
- "Too many parts" nozīmē, ka ClickHouse rada daļas ātrāk, nekā spēj tās apvienot. Limits ir nodalījumam (
parts_to_throw_insert, noklusējums 3000) un tabulai (max_parts_in_total). - Biežākie cēloņi ir mazas, biežas ievietošanas un nodalījumu atslēga ar pārāk daudz vērtībām. Trešais ir lēna vai apturēta apvienošana.
- Grupējiet ievietošanas (10 000 līdz 100 000 rindu, aptuveni viena ievietošana sekundē) vai izmantojiet
async_insertarwait_for_async_insert = 1. - Limita palielināšana nopērk laiku uz vaicājumu veiktspējas rēķina. Uztveriet to kā īslaicīgu ārkārtas pasākumu.
- Brīdiniet par daļu skaitu nodalījumā. Problēma ir redzama ilgi pirms ievietošana sāk izgāzties.