ClickHouse pro pokročilé uživatele v otázkách a odpovědích

V dubnu se inženýři Avito sešli na online setkání s hlavním vývojářem ClickHouse Alexejem Milovidovem a Kirillem Shvakovem, vývojářem v jazyce Golang ze společnosti Integros. Diskutovali jsme, jak používáme systém pro správu databází a jaké obtíže nám vznikají.

Na základě setkání jsme sestavili článek s odpověďmi expertů na naše a divácké otázky ohledně záloh, reshardingu dat, externích slovníků, Golang ovladače a aktualizace verzí ClickHouse. Může být užitečný pro vývojáře, kteří již aktivně pracují s databází "Yandex" a zajímají se o její současnost a budoucnost. Odpovědi Alexeje Milovidova jsou defaultní, pokud není uvedeno jinak.

Pozor, pod tímto textem je mnoho obsahu. Doufáme, že otázky vám pomohou se orientovat.

ClickHouse pro pokročilé uživatele v otázkách a odpovědích

Obsah

Pokud se vám nechce číst text, můžete se podívat na záznam posezení na našem youtube kanále. Časové kódy jsou v prvním komentáři pod videem.

ClickHouse se neustále aktualizuje, ale naše data se neaktualizují. Co s tím dělat?

ClickHouse se neustále aktualizuje, ale naše data, která byla optimalizována a finálně zpracována, se neaktualizují a leží v zálohách.

Představme si, že nastal nějaký problém a data byla ztracena. Rozhodli jsme se obnovit a ukázalo se, že staré partition, které jsou uloženy na serverech záloh, se velmi liší od aktuální verze ClickHouse. Co dělat v takové situaci? Je to možné?

Situace, kdy jste obnovili data ze zálohy ve starém formátu a na nové verzi se nepřipojí, není možná. Sledujeme, aby formát dat v ClickHouse vždy zůstal zpětně kompatibilní. To je mnohem důležitější než zpětná kompatibilita funkcionality, pokud se změnilo chování nějaké málo používané funkce. Data, která jsou uložena na disku, by měla nová verze ClickHouse vždy číst. To je pravidlo.

Jaké nejlepší praktiky existují v současnosti pro zálohování dat z ClickHouse?

Jak provádět zálohy s ohledem na to, že máme operace optimize final, obrovské databáze v terabajtech a data, která se aktualizují, předpokládejme, za poslední tři dny, a dále s nimi žádné procedury neprobíhají?

Můžeme nastrkat vlastní řešení a napsat na bázi: shromáždit takové a takové zálohy. Možná není třeba nic vymýšlet, a kolo bylo dávno vynalezeno?

Nejprve k nejlepším praktikám. Moji kolegové vždy doporučují při otázkách ohledně záloh připomínat službu „Yandex.Cloud“, kde je tento úkol již řešen. Takže ji využijte, pokud je to možné.

Neexistuje plnohodnotné řešení, které by bylo stoprocentně integrováno do ClickHouse pro zálohy. Existují některé šablony, které lze použít. Aby bylo možné získat plné řešení, bude třeba buď trochu ručně pracovat, nebo vytvořit obaly ve formě skriptů.

Začnu od nejjednodušších řešení a skončím těmi nejsofistikovanějšími v závislosti na objemu dat a velikosti klastru. Čím větší je klastr, tím složitější se řešení stává.

Pokud tabulka s daty zabírá pouhé několik gigabajtů, můžete zálohu provést takto:

  1. Uložit definice tabulek, tedy metadata — show create table.
  2. Provést dump pomocí klienta ClickHouse — select * z tabulky do souboru. Výchozí formát bude TabSeparated. Pokud chcete větší efektivitu — lze použít formát Native.

Pokud je objem dat větší, záloha zabere více času a místa. To se nazývá logická záloha, není vázána na formát dat ClickHouse. Pokud existuje, můžete v krajním případě vzít zálohu a načíst ji do MySQL pro obnovu.

Pro pokročilejší případy má ClickHouse zabudovanou možnost vytvořit snapshot_partitions v lokálním souborovém systému. Tato funkce je dostupná ve formě dotazu alter table freeze partition. Nebo jednoduše alter table freeze — to je snapshot celé tabulky.

Snapshot bude vytvořen konzistentně pro jednu tabulku na jednom shardu, tedy není možné vytvořit konzistentní snapshot celého klastru tímto způsobem. Ale pro většinu úloh není taková potřeba a stačí provést dotaz na každém shardu a získat konzistentní snapshot. Ten se vytváří ve formě hardlinků, a proto nezabírá další místo. Dále tento snapshot zkopírujete na zálohový server nebo do úložiště, které používáte pro zálohy.

Obnovit takovou zálohu je dost snadné. Nejprve vytvoříte tabulky podle existujících definic tabulek. Poté zkopírujete uložené snapshoty particí do Directory-Detached pro dané tabulky a provedete dotaz attach partition. Takové řešení je zcela vhodné pro velmi vážné objemy dat.

Někdy je potřeba něco ještě silnějšího – ve chvílích, kdy máte desítky nebo dokonce stovky terabajtů na každém serveru a stovky serverů. Existuje řešení, které jsem si všiml u kolegů z „Yandex.Metriky“. Nedoporučil bych ho každému – přečtěte si a rozhodněte se sami, zda je vhodné nebo ne.

Nejdříve je třeba vytvořit několik serverů s velkými diskovými poli. Poté na těchto serverech zprovoznit několik serverů ClickHouse a nastavit je tak, aby fungovaly jako další repliky pro stejné shardování. A dále použít na těchto serverech souborový systém nebo nějaký nástroj, který umožňuje vytvářet snapshoty. Existují dva varianty. První variant je LVM snapshoty, druhá varianta je ZFS na Linuxu.

Poté je nutné každý den vytvářet snapshot, který bude ležet a zabírat nějaké místo. Samozřejmě, pokud se data mění, časem prostor poroste. Tento snapshot můžete vytáhnout kdykoli a obnovit data, to je zvláštní řešení. Kromě toho je třeba omezit tyto repliky v konfiguraci, aby se nesnažily stát se vůdci.

Bude možné organizovat kontrolované zpoždění replik v sloupcích?

V tomto roce plánujete vytvářet v ClickHouse vlny. Bude možné v nich organizovat kontrolované zpoždění replik? Rádi bychom tímto způsobem ochránili sebe před negativními scénáři s alternacemi a dalšími změnami.

Je možné provést nějaký rollback pro alternace? Například ve stávající vlně vzít a říct, že do tohoto okamžiku se mají aplikovat změny, a od tohoto okamžiku přestaňte změny aplikovat?

Pokud do našeho clusteru přišel tým a rozbil ho, máme hypotetickou repliku se zpožděním jednu hodinu, kde můžeme říct, že ji použijeme právě teď, ale posledních deset minut změn v ní aplikovat nebudeme?

Nejdříve k kontrolovanému zpoždění replik. Takový požadavek od uživatelů byl, a my jsme vytvořili issue na GitHubu s prosbou: „Pokud to někdo potřebuje, dejte like, dejte srdíčko“. Nikdo nedal like, a issue byla uzavřena. I přesto již nyní je možné tuto možnost získat, pokud správně nastavíte ClickHouse. Bohužel, pouze od verze 20.3.

ClickHouse neustále na pozadí provádí slučování dat - merdž. Když je merdž proveden, určitá sada kusů dat je nahrazena větším kusem. Přitom kusy dat, které byly dříve, zůstávají na disku po určitou dobu.

Za prvé, tyto kusy se nadále uchovávají, dokud existují dotazy select, které je používají, aby se zajistilo neblokující fungování. Dotazy select bez problémů čtou ze starých kusů.

Za druhé, existuje také časový práh - staré kusy dat leží na disku osm minut. Těchto osm minut lze nastavit a prodloužit dokonce až na jeden den. To bude stát místo na disku: v závislosti na toku dat může být zpět několik dní dat, ne že by se zdvojnásobila, ale může být pětkrát více. Ale při vážném problému můžete zastavit server ClickHouse a vše vyřešit.

Nyní vyvstává otázka, jak to chrání před altery. Zde je potřeba se podívat hlouběji, protože ve starých verzích ClickHouse alter fungoval tak, že jednoduše přímo měnil kusy. Existuje kus dat s nějakými soubory, a my provedeme, například, alter drop column. Poté je tento sloupec fyzicky odstraněn ze všech kusů.

Ale od verze 20.3 byl mechanismus alterů zcela změněn a nyní jsou kusy dat vždy neměnné. Vůbec se mění - alty nyní fungují přibližně stejně jako merdži. Místo toho, abychom změnili kus na místě, vytváříme nový. V novém kusu se soubory, které se nezměnily, stávají tvrdými odkazy a pokud jsme nějaký sloupec odstranili, jednoduše nebude v novém kusu. Starý kus bude ve výchozím nastavení odstraněn po osmi minutách, a zde lze upravit nastavení, o kterých se zmínilo výše.

Stejně tak to platí pro alty typu mutací. Když uděláte alter delete nebo alter update, nezmění kus, ale vytvoří nový. A poté odstraní starý.

Co dělat, pokud se struktura tabulky změnila?

Jak obnovit zálohu, která byla provedena se starou schémou? A druhá otázka se týká případu se snímky a prostředky souborového systému. Je v tomto případě Btrfs vhodná místo ZFS na Linux LVM?

Pokud děláte attach partition Pokud máte partition s jinou strukturou, ClickHouse vám dá vědět, že to není možné. Řešení je následující. První krok – vytvořte dočasnou tabulku typu MergeTree se starou strukturou, připojte k ní data pomocí attach a proveďte příkaz alter. Poté můžete buď zkopírovat nebo přesunout tato data a znovu provést attach, nebo použít příkaz alter table move partition.

Teď druhá otázka – lze použít Btrfs. Začněme tím, že pokud máte LVM, stačí LVM snapshoty, a souborový systém může být ext4, na tom nezáleží. U Btrfs vše závisí na vašich zkušenostech s jeho provozem. Je to vyzrálý souborový systém, ale přesto jsou určité obavy, jak to vše bude fungovat v praxi v konkrétním scénáři. Nedoporučoval bych to používat, pokud nemáte Btrfs v produkci.

Jaké jsou nyní nejlepší praktiky pro resharding dat?

Otázka o přešardování je složitá a mnohovrstevnatá. Na to lze odpovědět několika způsoby. Můžete začít z jedné strany a říct, že ClickHouse nemá vestavěnou funkci přešardování. Ale obávám se, že tato odpověď nikoho neuspokojí. Proto můžete přistoupit z druhé strany a říct, že v ClickHouse existuje mnoho způsobů, jak data přešardovat.

Pokud se na clusteru začne nedostávat místa nebo nezvládá zátěž, přidáte nové servery. Ale tyto servery jsou ve výchozím nastavení prázdné, na nich žádná data nejsou, žádná zátěž neprobíhá. Musíte přerozdělit data, aby byla rovnoměrně rozložena po novém, zvětšeném clusteru.

První způsob, jak to udělat, je zkopírovat část partition na nové servery pomocí příkazu alter table fetch partition. Například, měli jste partition podle měsíců a vezmete první měsíc roku 2017 a zkopírujete ho na nový server, pak – třetí měsíc zkopírujete na nějaký jiný nový server. A takhle pokračujete, dokud nebude rozložení více méně rovnoměrné.

Přenos je možné provádět pouze pro ty partition, které se nezmění při zápisu. Pro čerstvé partition je nutné zápis vypnout, protože jejich přenos není atomární. Jinak byste získali duplicity nebo mezery v datech. Nicméně, tento způsob je praktický a funguje dost efektivně. Po síti se přenášejí již hotové komprimované partition, což znamená, že data se nekomprimují a nepřekódují.

Tento způsob má jednu nevýhodu, a to závislost na schématu shardingu, které jste zvolili, a na vašem klíči shardingu. Ve vašem příkladu pro případ metrik je klíčem shardingu hash cesty. Když spustíte select na distribuované tabulce, provede se okamžitě na všech shardech clusteru a stáhne data z nich.

To znamená, že pro vás v podstatě nezáleží na tom, která data se na kterém shardu nachází. Hlavní je, že data podle jedné cesty jsou na jednom shardu, a na kterém konkrétně, už není tak důležité. V tomto případě je přenos hotových partition skvělou volbou, protože při dotazech select budete také – ať už před nebo po přeshardingu, schéma hodnoty nemá zásadní význam – dostávat kompletní data.

Ale existují i složitější situace. Pokud se na úrovni logiky aplikace zakládáte na speciálním schématu shardingu, že tento klient je umístěn na určitém shardu a dotaz může být odeslán přímo tam, místo do distribuované tabulky. Nebo používáte dostatečně novou verzi ClickHouse a aktivovali jste nastavení optimize skip unused shards. V takovém případě bude při dotazu select výraz v sekci where analyzován a bude vypočítáno, na které shardy je třeba jít podle schématu shardingu. To funguje za předpokladu, že data jsou skutečně rozdělena podle tohoto schématu shardingu. Pokud jste je přesunuli ručně, může se shoda změnit.

Takže to je první způsob. A čekám na vaši odpověď, zda je tento způsob vhodný, nebo pokračujeme dál.

Vladimir Kolobajev, lead system administrator ve službě Avito: Alexei, způsob, který jste zmínil, se příliš nehodí, když je potřeba rozložit zátěž včetně čtení. Můžeme vzít partition, která je měsíční, a můžeme odnést předchozí měsíc na jinou node, ale když přijde dotaz na tato data, zatížíme pouze ji. A chtěli bychom zatěžovat celý cluster, protože jinak po určitou dobu bude celá zátěž na čtení zpracovávána jen dvěma shardy.

Alexei Milovidov: Odpověď zde je zvláštní — ano, je to špatné, ale možná to vyjde. Vysvětlím, jak přesně. Je dobré podívat se na scénář zatížení, který doprovází vaše data. Pokud jde o data monitorování, lze téměř s jistotou říci, že drtivá většina dotazů se vztahuje na čerstvá data.

Nainstalovali jste nové servery, přesunuli staré partition, ale také jste změnili způsob, jakým jsou zaznamenávána čerstvá data. A čerstvá data budou rozložena po celém klastru. Takže už za pět minut budou dotazy za posledních pět minut rovnoměrně zatěžovat klastr, po dni budou dotazy za 24 hodin rovnoměrně zatěžovat klastr. Ale bohužel dotazy za minulý měsíc půjdou pouze na část serverů klastru.

Ale často nebudete mít dotazy přesně za únor 2019. Pravděpodobně, pokud už dotazy jdou do roku 2019, budou za celý rok 2019 — za velký časový interval, a ne za nějaký malý rozsah. A takové dotazy také rovnoměrně zatíží klastr. Ale celkově máte pravdu, že se jedná o ad hoc řešení, které nevyrovnává data úplně rovnoměrně.

Mám několik dalších bodů k odpovědi na otázku. Jeden z nich se týká toho, jak původně vytvořit schéma shardingu tak, aby bylo méně bolestné z hlediska přeshardování. To nemusí být vždy možné.

Například máte data monitorování. Data monitorování rostou ze tří důvodů. První je akumulace historických dat. Druhý je nárůst provozu. A třetí je zvýšení počtu věcí, které spadají pod monitorování. Objevují se nové mikroservisy a metriky, které je třeba uchovávat.

Možná, že z nich je největší nárůst spojen právě s třetím důvodem — tedy zvýšeným využíváním monitorování. A v tomto případě je dobré podívat se na charakter zatížení, jaké jsou hlavní dotazy na select. Hlavní dotazy na select pravděpodobně budou vycházet z určité podmnožiny metrik.

Například využití CPU na některých serverech nějakou službou. Vychází to tak, že existuje určité podmnožství klíčů, podle kterého tato data získáváte. A samotný dotaz na tato data je pravděpodobně dost jednoduchý a probíhá v řádu desítek milisekund. Používá se pro služby monitorování, pro dashboardy. Doufám, že to chápu správně.

Vladimir Kolobajev: Jde o to, že velmi často apelujeme na historická data, protože v reálném čase porovnáváme aktuální stav s historickým. A pro nás je důležité mít rychlý přístup k velkému objemu dat, a ClickHouse s tím skvěle zvládá.

Máte naprostou pravdu, většinu dotazů na čtení za poslední den testujeme jako jakýkoli monitorovací systém. Ale zároveň na historická data je také poměrně velká zátěž. Tu většinou vytváří systém alerting, který každých třicet sekund oslovuje ClickHouse: „Dej mi data za posledních šest týdnů. A teď mi z nich sestav nějaký klouzavý průměr a porovnejme aktuální hodnotu s historickou.“

Chtěl bych říci, že máme pro takové velmi čerstvé dotazy ještě jednu malou tabulku, ve které uchováváme pouze dvoudenní data, a hlavní dotazy míří do ní. Do velké shardované tabulky posíláme pouze větší historické dotazy.

Alexei Milovidov: Bohužel pro váš scénář to není příliš aplikovatelné, ale popíšu dvě špatné a složité schéma shardování, které byste neměli používat, ale které jsou použity ve službě mých přátel.

Existuje hlavní cluster s událostmi „Yandex.Metriky“. Události - to jsou zobrazení stránek, kliknutí a přechody. Většina dotazů jde na konkrétní web. Otevřete službu „Yandex.Metrika“, máte web - avito.ru, jdete do zprávy a probíhá dotaz podle vašeho webu.

Ale existují i další dotazy - analytické a globální, které provádějí interní analytici. Pro jistotu poznamenám, že interní analytici provádějí dotazy pouze na službách „Yandexu“. Nicméně i služby „Yandexu“ zaujímají významný podíl ze všech dat. To jsou dotazy nikoli podle konkrétních čítačů, ale podle širší filtrace.

Jak uspořádat data tak, aby efektivně fungovala jak pro jeden čítač, tak pro globální dotazy? Obtížnost spočívá také v tom, že počet dotazů v ClickHouse na klastr „Metriky“ dosahuje několika tisíc za sekundu. Přitom netriviální dotazy, například, jednomu serveru ClickHouse nezvládne přepracovat několik tisíc dotazů za sekundu.

Velikost klastru je něco přes šest set serverů. Pokud nad tímto klastrem jednoduše natáhneme distribuovanou tabulku a odešleme tam několik tisíc dotazů, bude to ještě horší než odesílat je na jeden server. Na druhou stranu, možnost, že jsou data rovnoměrně rozložena a my žádáme ze všech serverů, hned vylučujeme.

Existuje diametrálně opačná varianta. Představte si, že bychom data shardovali podle webů, a dotaz pro jeden web by šel na jeden shard. Nyní klastr bude moci zvládnout deset tisíc dotazů za sekundu, ale na jednom shardu by nějaký konkrétní dotaz fungoval příliš pomalu. Už by nebylo schopno škálovat podle propustnosti. Zvlášť pokud to je web avito.ru. Neodhalím žádné tajemství, když řeknu, že Avito je jedním z nejnavštěvovanějších webů v ruském internetu. A zpracovávat ho na jednom shardu by bylo šílenství.

Proto je schéma shardování navrženo zcela jinak. Celý klastr je rozdělen na určité množství klastrů, které nazýváme vrstvami. Uvnitř každého klastru je od deseti do několika desítek shardů. A celkově je takových klastrů třicet devět.

Jak se to všechno škáluje? Počet klastrů se nemění – jak bylo před několika lety třicet devět, tak zůstalo. Ale uvnitř každého z nich postupně zvyšujeme počet shardů s narůstajícími daty. A schéma shardování je v zásadě takové, že rozdělení na tyto klastry probíhá podle webových stránek, a abychom pochopili, který web je na kterém klastru, používáme vůbec samostatnou metadatovou bázi v MySQL. Jeden web – jeden klastr. A uvnitř něj probíhá shardování podle identifikátorů návštěvníků.

Při zápisu je rozdělujeme podle zbytku po dělení identifikátoru návštěvníka. Ale při přidání nového shardu se schéma shardování mění, pokračujeme v rozdělování, ale podle zbytku po dělení jiným číslem. To znamená, že jeden návštěvník je skutečně umístěn na několika serverech, což nelze podcenit. Bylo to provedeno výhradně pro to, aby se data lépe komprimovala. A při dotazech se obracíme na tabulku Distributed, která se dívá na cluster a oslovuje desítky serverů. Takové je to hloupé schéma.

Ale můj příběh by nebyl úplný, kdybych neřekl, že jsme se této schéma vzdali. V novém schématu jsme všechno změnili a všechna data zkopírovali pomocí clickhouse-copier.

V novém schématu jsou všechny weby rozděleny do dvou kategorií - velké a malé. Nevím, jak byl zvolen práh, ale výsledek je takový, že velké weby se zapisují na jeden cluster, kde je 120 shardů se třemi replikami v každém - tedy 360 serverů. A schéma shardování je takové, že jakýkoli dotaz jde ihned na všechny shardy. Pokud nyní v "Yandex.Metrice" otevřete jakoukoli stránku reportu pro avito.ru, dotaz půjde na 120 serverů. Velkých webů v RuNetu je málo. A dotazů se ukazuje ne tisíc za sekundu, ale dokonce méně než sto. Vše to v klidu zpracovává tabulka Distributed, kterou každý z nich zpracovává 120 servery.

Druhý cluster je pro malé weby. Zde je schéma shardování podle identifikátoru webu a každý dotaz jde přesně na jeden shard.

V ClickHouse existuje utilita clickhouse-copier. Můžete o ní říct něco víc?

Hned řeknu, že tohle řešení je objemnější a o něco méně výkonné. Výhodou je, že zcela rozprostírá data podle schématu, které uvedete. Ale nevýhodou nástroje je, že vůbec nevytváří přeshardování. Kopíruje data z jednoho schématu clusteru do jiného schématu clusteru.

To znamená, že pro její fungování musíte mít dva clustery. Mohou být umístěny na stejných serverech, ale přesto data nebudou přesunována inkrementálně, ale budou zkopírována.

Například, bylo čtyři servery, stalo se jich osm. Vytváříte na všech serverech novou distribuovanou tabulku, nové lokální tabulky a spouštíte clickhouse-copier, přičemž určujete v něm režim práce, který by měl číst odtud, přijmout nový plán rozdělení a přesunout tam data. A potřebujete na starých serverech místo o 50 % více než aktuálně, protože stará data musí zůstat na nich, a nad nimi přijdou poloviční kusy z těchto starých dat. Pokud jste si předem promysleli, že je potřeba data přerozdělit a místo je, pak vám tento způsob bude vyhovovat.

Jak funguje clickhouse-copier uvnitř? Rozděluje celou práci na sadu úloh pro zpracování jedné části jedné tabulky na jednom shardu. Všechny tyto úlohy mohou být vykonávány paralelně a clickhouse-copier může být spuštěn na různých strojích v několika instancích, ale to, co dělá pro jednu část, není nic jiného než insert select. Data se čtou, dekomprimují, přerozdělují, poté se znovu komprimují, zapisují někam, přetříďují. Je to těžší řešení.

Měli jste pilotní projekt, který se jmenoval resharding. Co je s ním?

Měli jste ještě v roce 2017 pilotní projekt, který se jmenoval rešarding. Dokonce existuje možnost v ClickHouse. Chápu, že to neuspělo. Můžete říct, proč k tomu došlo? Vypadá to jako velmi aktuální téma.

Celý problém spočívá v tom, že při potřebě přerozdělit data na místě vyžaduje velmi složitou synchronizaci, aby to bylo provedeno atomicky. Když jsme se začali dívat na to, jak je tato synchronizace uspořádána, bylo jasné, že existují základní problémy. A tyto základní problémy nejsou jen teoretického rázu, ale okamžitě se začaly projevovat v praxi ve formě, kterou lze velmi jednoduše vysvětlit — nic nefunguje.

Lze všechny části dat sloučit do jednoho před přesunem na pomalé disky?

Otázka ohledně TTL s možností přenosu na pomalý disk v kontextu sloučení. Existuje nějaký způsob, kromě cron, jak spojit všechny části do jedné před přesunem na pomalé disky?

Odpověď na otázku, zda je možné automaticky spojit všechny kusy do jednoho před jejich přesunem — ne. Myslím, že to není nutné. Můžete nespojovat všechny části do jedné, ale prostě počítat s tím, že budou automaticky přesunuty na pomalé disky.

Máme dvě kritéria pro přesun. První je na základě zaplnění. Pokud je na aktuální úrovni úložiště méně než nějaké procento volného místa, vybereme jeden blok a přesuneme jej na pomalejší úložiště. Přesněji řečeno, ne na pomalejší, ale na další — podle toho, jak to nastavíte.

Druhým kritériem je velikost. Týká se to přesunu velkých bloků. Můžete nastavit práh pro volné místo na rychlém disku a data budou automaticky přesunuta.

Jak přejít na nové verze ClickHouse, pokud není možné předem zkontrolovat kompatibilitu?

Toto téma se pravidelně diskutuje v telegramovém chatu ClickHouse s ohledem na různé verze, a přesto. Jak bezpečné je aktualizovat z verze 19.11 na 19.16 a například z 19.16 na 20.3. Jak nejlépe přejít na nové verze, aniž bychom měli možnost předem ověřit kompatibilitu v písku?

Existuje několik "zlatých" pravidel. První je číst changelog. Je to obsáhlé, ale obsahuje samostatné položky o zpětně nekompatibilních změnách. Tyto položky neberte jako červenou vlajku. Obvykle se jedná o drobné nekompatibility, které se týkají určité hraniční funkce, kterou pravděpodobně nepoužíváte.

Druhé — pokud není možné ověřit kompatibilitu v písečné údržbě a chcete se aktualizovat přímo v produkci, doporučení je takové — nedělejte to. Nejprve vytvořte písek a zkontrolujte. Pokud nemáte testovací prostředí, pravděpodobně nejste příliš velká firma, a proto můžete zkopírovat část dat na svůj notebook a ověřit si, že vše správně funguje. Můžete také spustit několik replik lokálně na svém stroji. Nebo můžete kousek vedle nasadit novou verzi a nahrát tam část dat — tedy vytvořit improvizované testovací prostředí.

Další pravidlo — neaktualizujte se během týdne po vydání verze kvůli odchytávání chyb v produkci a následným rychlým opravám. Pojďme se podívat na číslování verzí ClickHouse, abychom se nezamotal.

Existuje verze 20.3.4. Číslo 20 označuje rok vydání - 2020. Z hlediska toho, co je uvnitř, to nemá žádný význam, takže se na to nebudeme zaměřovat. Dále je zde 20.3. Druhé číslo - v tomto případě 3 - zvyšujeme pokaždé, když vydáme verzi s nějakou novou funkcí. Pokud chceme do ClickHouse přidat nějakou schopnost, musíme toto číslo zvýšit. To znamená, že ve verzi 20.4 bude ClickHouse fungovat ještě lépe. Třetí číslo - 20.3.4. Zde 4 - to je počet patch release, ve kterých jsme nepřidávali nové funkce, ale opravovali nějaké chyby. A 4 znamená, že jsme to udělali čtyřikrát.

Není třeba si myslet, že je to něco hrozného. Obvykle uživatel může nainstalovat nejnovější verzi a ta bude fungovat bez problémů po dobu jednoho roku. Ale představte si, že v nějaké funkci pro zpracování bitmap, která byla přidána našimi čínskými kolegy, server spadne při předání nesprávných argumentů. Musíme to opravit. Vydáme novou patch verzi a ClickHouse se stane stabilnějším.

Pokud máte ClickHouse v produkčním prostředí a vyjde nová verze ClickHouse s dalšími funkcemi - například 20.4.1 - nelépe ji nespěchejte nasadit do produkce v první den. Proč je vůbec potřebná? Pokud ClickHouse ještě nepoužíváte, můžete ji nainstalovat a pravděpodobně vše bude v pořádku. Ale pokud ClickHouse již stabilně funguje, sledujte patche a aktualizace - jaké problémy opravujeme.

Kirill Shvakov: Chci trochu doplnit o testovacích prostředích. Všichni se velmi bojí testovacích prostředí a z nějakého důvodu se domnívají, že pokud máte velmi velký klastr ClickHouse, musí být testovací prostředí alespoň desetkrát menší. To vůbec není pravda.

Mohu říci na svém příkladu. Mám projekt, a tam je ClickHouse. Naše testovací prostředí pro něj - je to malý virtuální server v Hetzneru za dvacet eur, kde je naprosto vše rozvinuto. Abychom to mohli dělat, máme plnou automatizaci v Ansible, a proto v zásadě nezáleží na tom, na co to nasazujeme - na fyzické servery nebo prostě rozvinout na virtuálních strojích.

Co lze udělat? Bylo by dobré vytvořit příklad v dokumentaci ClickHouse, jak rozběhnout malý klastr na Dockeru, v LXC, možná vytvořit Ansible playbook, protože každý má jiné deploymenty. To by hodně usnadnilo. Když můžete klastr rozběhnout za pět minut, je mnohem jednodušší se v něčem zorientovat. Je to tak mnohem pohodlnější, protože přechod na produkční verzi, kterou jste neověřili, je cesta nikam. Někdy to funguje, jindy ne. A proto spoléhat na úspěch – je špatné.

Maksim Kotyakov, senior backend engineer Avito: Trochu doplním o testovacích prostředích ze série problémů velkých firem. Máme plnohodnotný akceptační klastr ClickHouse, který je přesnou kopií produkčních dat a nastavení. Tento klastr je nasazen v dost špatných kontejnerech s minimem zdrojů. Píšeme tam určitý procento od produkčních dat, naštěstí máme možnost replikovat v Kafce stream. Vše je synchronizováno a škálováno – co se týče výkonu, toku, a v teorii by mělo při stejných podmínkách vykazovat chování jako produkce. Všechno potenciálně výbušné nejprve běží na tomto standu a několik dní tam zraje do připravenosti. Ale samozřejmě, tohle řešení je drahé, těžké a má nenulové náklady na údržbu.

Alexei Milovidov: Povím, jak vypadá testovací prostředí našich přátel z "Yandex.Metriky". Jeden klastr měl přes 600 serverů, druhý 360 a máme ještě třetí a několik dalších klastrů. Testovací prostředí pro jeden z nich je vlastně jen dva shardů se dvěma replikami v každém. Proč dva shardy? Aby nebyl jen jeden. A také repliky, aby byly. Prostě určité minimální množství, které si můžeme dovolit.

Toto testovací prostředí umožňuje ověřit funkčnost dotazů a zda se něco velkého nezlomilo. Ale často vznikají problémy zcela jiného charakteru, když vše funguje, ale jsou tam nějaké drobné změny s zatížením.

Dám příklad. Rozhodli jsme se nainstalovat novou verzi ClickHouse. Byla nasazena na testovací prostředí, automatizované testy v "Yandex.Metrika" byly úspěšně provedeny, které porovnávají data na staré a nové verzi, přičemž spouští celý proces. A samozřejmě, zelené testy našeho CI. Jinak bychom tuto verzi ani nenabídli.

Všechno je skvělé. Začínáme nasazovat do produkce. Přichází mi zpráva, že zatížení na grafech vzrostlo několikrát. Vracíme verzi zpět. Podívám se na graf a vidím: zatížení se skutečně několikrát zvýšilo během nasazení a pak se zpět snížilo, když byla verze zavedená. Pak jsme začali verzi vracet zpět. Zatížení se opět zvýšilo a stejně tak se zpět snížilo. Takže závěr je takový – zatížení vzrostlo v souvislosti s nasazením, nic překvapivého.

Dále bylo složité přesvědčit kolegy, aby skutečně nainstalovali novou verzi. Říkám: „Všechno je v pořádku, nasazujte. Držte palce, všechno bude fungovat. Teď zatížení vzrostlo na grafech, ale všechno je v pořádku. Držte se.“ Nakonec jsme to udělali a všichni — verze byla nasazena do produkce. Ale téměř při každém nasazení se objevují podobné problémy.

Kill query by měl zabíjet dotazy, ale nedělá to. Proč?

Přišel ke mně uživatel, nějaký analytik, a vytvořil nějaký dotaz, který položil můj cluster ClickHouse. Nějaký uzel nebo celý cluster — záleží na tom, do které repliky nebo shardu dotaz spadl. Vidím, že všechny prostředky na CPU na tomto serveru jsou na nule, všechno je červené. Přitom samotný ClickHouse na dotazy odpovídá. A píšu: „Ukaz mi prosím seznam procesů, který dotaz způsobil tento chaos.”

Najdu tento dotaz a napíšu mu kill. A vidím, že se nic neděje. Můj server je na nule, ClickHouse mi dále zasílá nějaké příkazy, ukazuje, že server žije a všechno je skvělé. Ale mám degradaci ve všech uživatelských dotazech, začíná degradace při zápisu do ClickHouse a můj kill query nefunguje. Proč? Myslel jsem, že kill query by mělo zabíjet dotazy, ale to se neděje.

Teď bude poměrně zvláštní odpověď. Jde o to, že kill query nezabíjí dotazy.

Kill query nastavuje malou značku s názvem „chci, aby byl tento dotaz zabit“. A samotný dotaz při zpracování každého bloku se dívá na tuto značku. Pokud je nastavena, dotaz přestane pracovat. Vychází to tak, že nikdo dotaz nezabíjí, musí si to sám zkontrolovat a zastavit se. A mělo by to fungovat ve všech případech, kdy se dotaz nachází ve stavu zpracování bloků dat. Zpracuje další blok dat, zkontroluje značku a zastaví se.

To není možné v případech, kdy je dotaz blokován při nějaké operaci. Pravděpodobně to ale není váš případ, protože podle vašich slov využívá spoustu serverových zdrojů. Možná, že to nefunguje při externím třídění a ještě v některých detailech. Ale celkově by to tak být nemělo, je to chyba. A jediné, co mohu doporučit, je aktualizovat ClickHouse.

Jak vypočítat dobu odezvy při čtecí zátěži?

Existuje tabulka, ve které jsou uloženy agregáty podle item - různé počítadla. Počet řádků je přibližně sto milionů. Lze očekávat předvídatelnou dobu odezvy, pokud se nalije 1K RPS na 1K itemů?

Soudě podle kontextu se jedná o čtecí zátěž, protože při zápisu nejsou žádné problémy - lze vložit tisíce i stovky tisíc řádků, někdy i několik milionů.

Čtecí dotazy mohou být velmi různorodé. V select 1 může ClickHouse vykonávat kolem desítek tisíc dotazů za sekundu, takže i dotazy podle jednoho klíče již vyžadují určité zdroje. A takové cílené dotazy budou složitější než v běžných key-value databázích, protože při každém čtení je nutné přečíst blok dat podle indexu. Index u nás adresuje nikoliv každou položku, ale každé rozpětí. Jinými slovy, je nutné přečíst celé rozpětí - to je 8192 řádků ve výchozím nastavení. A také je třeba dekomprimovat komprimovaný blok dat z 64 Kb na 1 Mb. Obvykle takové cílené dotazy trvají od několika milisekund. Ale to je ten nejjednodušší případ.

Pojďme zkusit jednoduchou aritmetiku. Pokud vynásobíte několik milisekund tisícem, dostanete několik sekund. Jakoby nebylo možné mít tisíc dotazů za sekundu, ale ve skutečnosti je to možné, protože máme několik procesorových jader. Takže v zásadě 1000 RPS ClickHouse někdy může zvládnout, ale na krátkých dotazech, právě cílených.

Pokud je potřeba škálovat klastr ClickHouse podle počtu jednoduchých dotazů, doporučuji to nejjednodušší - zvýšit počet replik a posílat dotazy na náhodnou repliku. Pokud jedna replika zvládá pět set dotazů za sekundu, což je zcela reálné, pak tři repliky zvládnou jeden a půl tisíce.

Někdy je samozřejmě možné nastavit ClickHouse na maximální počet bodových čtení. Co k tomu potřebujete? První je snížit granularitu indexu. Při tom ji sice nesmíte snižovat na jednotku, ale spíše s ohledem na to, že počet záznamů v indexu bude několik milionů nebo desítek milionů na serveru. Pokud má tabulka sto milionů řádků, můžete stanovit granularitu na 64.

Můžete snížit velikost komprimovaného bloku. K tomu jsou určena nastavení min compress block size, max compress block size. Ty lze zmenšit, přenastavit data a pak budou bodové dotazy rychlejší. Ale ClickHouse to není key-value databáze. Velké množství malých dotazů je antipattern zatížení.

Kirill Shvakov: Dám radu pro případ, že tam jsou běžné encountery. To je docela standardní situace, kdy se v ClickHouse uchovává nějaký čítač. Mám uživatele, je z nějaké země, k tomu je další třetí pole a potřebuji něco inkrementálně zvyšovat. Vezmete MySQL, vytvoříte unikátní klíč — v MySQL je to duplicate key, v PostgreSQL je to conflict — a přidáte to s plus. To bude fungovat mnohem lépe.

Když máte málo dat, nemá smysl ClickHouse používat. Existují běžné databáze a ty si s tím dobře poradí.

Co doladit v ClickHouse, aby bylo více dat v cache?

Představme si situaci — na serverech je 256 GB RAM, v každodenní rutině ClickHouse zabere přibližně 60—80 GB, v špičce — až 130. Co lze aktivovat a doladit, aby bylo více dat v cache a tím pádem méně přístupů na disk?

Obvykle si s tímto úkolem dobře poradí page cache operačního systému. Pokud otevřete top a podíváte se na cached nebo free — tam je také uvedeno, kolik je uloženo v cache — pak můžete poznamenat, že veškerá volná paměť je využita na cache. A tato data při čtení budou čtena ne z disku, ale z operační paměti. Mohu říci, že cache je používána efektivně, protože se ukládají právě komprimovaná data.

Nicméně, pokud chcete urychlit některé jednoduché dotazy ještě více, existuje možnost zapnout uvnitř ClickHouse cache pro dekomprimovaná data. To se nazývá uncompressed cache. V konfiguračním souboru config.xml nastavte velikost nekomprimované mezipaměti na požadovanou hodnotu — doporučuji, aby to bylo maximálně polovina volné operační paměti, protože zbytek bude použit na mezipaměť stránky.

Kromě toho existují dvě nastavení na úrovni dotazu. První nastavení — use uncompressed cache — aktivuje jeho použití. Doporučuje se jej zapnout pro všechny dotazy, kromě těžkých, které mohou přečíst všechna data a tím vyprázdnit tuto mezipaměť. A druhé nastavení je něco jako maximální počet řádků pro použití mezipaměti. Automaticky omezuje velké dotazy, aby je zpracovalo mimo mezipaměť.

Jak lze nastavit storage_configuration pro uložení do operační paměti?

V nové dokumentaci ClickHouse jsem nalezl část související s ukládáním dat. V popisu je příklad s rychlým SSD.

Zajímavé je, jak lze nakonfigurovat totéž s objemovou horkou pamětí. A ještě jedna otázka. Jak funguje select s takovou organizací dat, zda čte celou sadu nebo jen tu, která leží na disku, a jsou tato data komprimována v paměti? A jak funguje sekce prewhere na takové organizaci dat?

Toto nastavení ovlivňuje ukládání datových bloků a jejich formát se nijak nemění.
Podívejme se na to podrobněji.

Nastavení ukládání dat v operační paměti je možné. Vše, co se konfiguruje pro disk — to je jeho cesta. Vytvoříte tmpfs oddíl, který je přimontován na nějakou cestu v souborovém systému. Uvedete tuto cestu jako cestu pro ukládání dat pro nejlepší horký oddíl, kam začnou přicházet a zapisovat se datové bloky, všechno funguje dobře.

Ale nedoporučuji to dělat pro nízkou spolehlivost, i když, pokud máte minimálně tři repliky v různých datových centrech, dá se to. V každém případě budou data obnovena. Představme si, že server se náhle vypnul a znovu zapnul. Oddíl se přimontoval znovu, ale tam je prázdno. Server ClickHouse při spuštění zjistí, že mu tyto bloky chybí, i když podle metadat ZooKeeper by měly být. Podívá se, na kterých replikách jsou, požádá je o ně a stáhne je. Takto budou data obnovena.

V tomto smyslu se uchovávání dat v operační paměti zásadně neliší od jejich uchovávání na disku, protože při zápisu dat na disk se také nejprve dostanou do page cache a fyzicky se zapisují opožděně. To závisí na variantě připojení souborového systému. Ale pro jistotu říkám, že ClickHouse nedělá fsync při insert.

Data v operační paměti jsou uchovávána ve stejném formátu jako na disku. Dotaz select vybírá přesně takové části, které je třeba číst, vybírá potřebné rozsahy dat a čte je. A prewhere funguje naprosto stejně, bez ohledu na to, zda byla data v operační paměti nebo na disku.

Do jakého počtu unikátních hodnot je Low Cardinality efektivní?

Low Cardinality je chytře uspořádán. Vytváří datové slovníky, ale ty jsou lokální. Zaprvé, slovníky jsou vlastní pro každý kus, za druhé, i uvnitř jednoho kusu mohou být různé pro každý rozsah. Když počet unikátních hodnot dosáhne prahové hodnoty – myslím, že jednoho milionu – slovník se prostě odloží a vytvoří se nový.

Celková odpověď: pro každý lokální rozsah – řekněme, pro každý den – kdekoliv do jednoho milionu unikátních hodnot je Low Cardinality efektivní. Poté dojde k fallbacku, kde se použije mnoho různých slovníků, nikoli jen jeden. Bude to fungovat přibližně stejně jako běžný sloupec typu string, možná o něco méně efektivně, ale vážné snížení výkonu nenastane.

Jaké nejlepší praktiky existují pro fulltextové vyhledávání v tabulce s pěti miliardami řádků?

Existují různé možnosti odpovědi. První je říci, že ClickHouse není systém pro fulltextové vyhledávání. Na to existují specializované systémy, například Elasticsearch a Sphinx. Nicméně, stále častěji se setkávám s lidmi, kteří říkají, že přecházejí z Elasticsearch na ClickHouse.

Proč se to děje? Vysvětlují to tím, že Elasticsearch přestává zvládat zátěž při některých objemech, počínaje tím, co se týče vytváření indexů. Indexy se stávají příliš objemnými a pokud se jednoduše převedou data do ClickHouse, ukáže se, že se uchovávají několikrát efektivněji. Přitom vyhledávací dotazy často nebyly takové, že by bylo třeba najít v celém objemu dat nějakou frázi zohledňující morfologii, ale zcela jiné. Například najít v posledních několika hodinách vlogech podle nějaké podsouborové sekvence bytů.

V tomto případě v ClickHouse nahráváte index, jehož prvním polem bude datum se časem. A největší omezení dat bude právě podle rozsahu dat. Uvnitř vybraného rozsahu dat je obvykle možné provádět fulltextové vyhledávání i brutální metodou pomocí like. Operátor like v ClickHouse je nejefektivnější operátor like, který můžete najít. Pokud najdete lepší, dejte mi vědět.

Ale stále je like full scan. A full scan může být pomalý nejen podle CPU, ale i podle disku. Pokud náhodou máte jeden terabajt dat za den a za den hledáte nějaké slovo, budete muset prozkoumat terabajt. A je pravděpodobné, že se nachází na běžných pevných discích, takže nakonec budou zatíženy tak, že se na tento server přes SSH nedostanete.

V tomto případě jsem připraven nabídnout ještě jeden malý trik. Je to z kategorie experimentálních — může fungovat, ale také nemusí. V ClickHouse jsou k dispozici fulltextové indexy ve formě trigramových Bloom filtrů. Naši kolegové z firmy Arenadata už tyto indexy vyzkoušeli, a často fungují přesně tak, jak měly.

Abychom je správně používali, musíme dobře rozumět tomu, jak fungují: co představuje trigramový Bloom filtr a jak zvolit jeho velikost. Mohu říci, že pomohou u dotazů na nějaké vzácné fráze, podřetězce, které se v datech zřídka vyskytují. V takovém případě budou pomocí indexů vybrány podrozsahy a přečte se méně dat.

Nedávno se v ClickHouse objevily ještě pokročilejší funkce pro fulltextové vyhledávání. To znamená, za prvé, hledání spousty podřetězců v jednom průchodu, včetně variant s ohledem na velikost písmen, bez ohledu na velikost písmen, s podporou UTF-8 nebo pouze pro ASCII. Vyberte ten nejefektivnější, který potřebujete.

Také byl přidán vyhledávání několika regulárních výrazů v jednom průchodu. Nemusíte psát X like jeden podřetězec or X like jiný podřetězec. Stačí napsat a vše se provede co nejefektivněji.

Třetí — nyní existuje aproximativní vyhledávání regulárních výrazů a aproximativní vyhledávání podřetězců. Pokud někdo napsal slovo s překlepem, bude hledáno podle maximální shody.

Jak lépe organizovat přístup do ClickHouse pro velké množství uživatelů?

Povězte, jak nejlépe uspořádat přístup pro velké množství spotřebitelů a analytiků. Jak vytvořit frontu, priorizovat dotazy max concurrent queries a jaké nástroje použít?

Pokud je cluster dostatečně velký, dobrým řešením bude nasadit ještě dva servery, které se stanou vstupním bodem pro analytiky. To znamená, že nebudeme pustit analytiky na konkrétní shard clusteru, ale jednoduše vytvoříme dva prázdné servery, bez dat, a na nich nastavíme práva přístupu. Přitom se nastavení uživatelů při rozložených dotazech předávají na vzdálené servery. To znamená, že všechno nastavíte na těchto dvou serverech, a nastavení má efekt na celém clusteru.

V zásadě jsou tyto servery bez dat, ale objem RAM na nich je velmi důležitý pro provádění dotazů. Disk může také sloužit pro dočasná data, pokud je zapnuta externí agregace nebo externí třídění.

Je důležité podívat se na nastavení, která jsou spojena se všemi možnými limity. Pokud nyní vstoupím do clusteru „Yandex.Metriky“ jako analytik a zadám dotaz select count from hits, tak mi okamžitě vyhodí výjimku, že dotaz nemohu vykonat. Maximální počet řádků, které mohu procházet, je sto miliard, a celkově je jich na clusteru padesát bilionů v jedné tabulce. To je první omezení.

Předpokládám, že odstraním omezení na počet řádků a dotaz znovu provedu. Tehdy uvidím následující výjimku – je zapnuta nastavení force index by date. Nemohu provést dotaz, pokud jsem neoznačil časový rozsah. Není potřeba počítat s tím, že analytici ho uvedou ručně. Typický případ – napsán rozsah dat where event date between týden. A pak prostě nebyla na správném místě závorka, a místo and vzniklo or – or URL match. Pokud není omezení, začne skenovat sloupec URL a spotřebuje tak obrovské množství zdrojů.

Kromě toho má ClickHouse dvě nastavení priorit. Bohužel, jsou velmi primitivní. Jedno se nazývá jednoduše priority. Pokud je priorita ≠ 0 a probíhají dotazy s nějakou prioritou, ale současně probíhá dotaz s prioritou, která má menší hodnotu, což znamená vyšší prioritu, pak se dotaz s hodnotou priority vyšší, což označuje nižší prioritu, prostě pozastaví a nebude fungovat po tuto dobu.

To je velmi hrubé nastavení a nehodí se do případů, kdy je v clusteru stálé zatížení. Ale pokud máte krátké, impulzivní důležité dotazy a většinou cluster nevyužíváte, takové nastavení bude vyhovovat.

Další nastavení priorit se nazývá priorita vlákna OS. Toto nastavení jednoduše určuje pro všechna vlákna vykonávající dotazy hodnotu nice pro plánovač Linuxu. Funguje to tak nějak, ale přece jen to funguje. Pokud nastavíte nejnižší hodnotu nice – což je nejvyšší hodnota a tedy nejnižší priorita – a pro dotazy s vysokou prioritou nastavíte -19, pak CPU bude zpracovávat dotazy s nízkou prioritou přibližně čtyřikrát méně než dotazy s vysokou prioritou.

Je také potřeba nastavit maximální dobu vykonávání dotazu – řekněme pět minut. Minimální rychlost vykonávání dotazu – to je to nejlepší. Toto nastavení existuje už dlouho a je potřebné, aby se netvrdilo pouze, že ClickHouse nezpomaluje, ale aby se to vynucovalo.

Představte si, že nastavujete: pokud nějaký dotaz zpracovává méně než milion řádků za sekundu – tak to nesmí být. To poškozuje naše dobré jméno, naši dobrou databázi. Pojďme to jednoduše zakázat. Ve skutečnosti existují dvě nastavení. Jedno se nazývá minimální rychlost vykonávání – v řádcích za sekundu, a druhé se nazývá časový limit před kontrolou minimální rychlosti vykonávání – výchozí hodnota je patnáct sekund. To znamená, že patnáct sekund je povoleno, ale potom, když je to pomalé, tak prostě vyhodíme výjimku – přerušíme dotaz.

Také je potřeba nastavit kvóty. V ClickHouse je vestavěná funkce kvót, která sleduje spotřebu zdrojů. Ale bohužel nehardwarových zdrojů jako CPU a disky, ale logických – počet zpracovaných dotazů, řádků a přečtených bajtů. A můžete nastavit například maximálně sto dotazů během pěti minut a tisíc dotazů za hodinu.

Proč je to důležité? Protože část analytických dotazů bude prováděna ručně přímo z klienta ClickHouse. A všechno bude v pořádku. Ale pokud máte ve firmě pokročilé analytiky, napíšou skript a ve skriptu může být chyba. A tato chyba povede k tomu, že dotaz se provede v nekonečné smyčce. Tomu se musíme bránit.

Lze vrátit výsledky jednoho dotazu deseti klientům?

Máme několik uživatelů, kteří rádi přicházejí s velmi velkými dotazy ve stejném okamžiku. Dotaz je velký, vykonává se v podstatě rychle, ale kvůli tomu, že je takových dotazů najednou hodně, je to velmi bolestné. Můžeme provést jeden a ten samý dotaz, který přišel desetkrát za sebou, jednou a výsledek poskytnout deseti klientům?

Problém je v tom, že nemáme výsledky z cache nebo cache mezidat. Je zde cache stránek operačního systému, která umožní přečíst data z disku opakovaně, ale bohužel, data budou stejně muset být dekomprimována, deserializována a znovu zpracována.

Chtěli bychom se tomu nějakým způsobem vyhnout, buď kešováním mezidat, nebo vybudováním podobných dotazů do nějaké fronty a přidáním cache výsledků. V současnosti máme ve vývoji jeden pull request, který přidává cache dotazů, ale pouze pro poddotazy v sekci in a join — tedy řešení není kompletní.

Nicméně, i u nás nastává tato situace. Zvlášť kanonickým příkladem jsou dotazy s paginací. Máme zprávu, ve které je několik stránek, a dochází k dotazu limit 10. Pak to samé, ale limit 10,10. Poté další stránka. A otázka zní, proč to každýkrát všechno počítáme? Ale nyní není žádné řešení a tomu se nelze vyhnout.

Existuje alternativní řešení, které se instaluje vedle ClickHouse — ClickHouse Proxy.

Kirill Shvakov: V ClickHouse Proxy je vestavěný limiter rychlosti a vestavěná cache výsledků. Je tam provedeno mnoho nastavení, protože byla řešena podobná úloha. Proxy umožňuje omezit dotazy, uspořádat je do fronty a nastavit, jak dlouho cache dotazů žije. Pokud byly dotazy skutečně stejné, Proxy je vrátí mnohokrát, zatímco do ClickHouse se připojí pouze jednou.

V Nginxu je také cache v bezplatné verzi, a to také bude fungovat. Nginx má dokonce nastavení, že pokud přicházejí požadavky současně, zpomalí ostatní, dokud nebude jeden splněn. Ale v ClickHouse Proxy je tato konfigurace provedena mnohem lépe. Byla vyvinuta přímo pro ClickHouse, pro tyto požadavky, takže je mnohem vhodnější. A také se instalace provádí jednoduše.

Jak se vyrovnat s asynchronními operacemi a materializovanými pohledy?

Existuje takový problém, že operace s replikovaným enginem jsou asynchronní – nejprve se data zapisují, poté dochází k jejich sloučení. Pokud pod tabulkou žije materializovaná tabulka s nějakými agregáty, pak se do ní zapíší duplicity. A pokud neexistuje žádná složitá logika, pak budou data zdvojena. Co s tím lze udělat?

Existuje zřejmé řešení – implementovat spouštěč na určitý typ materializovaného pohledu při asynchronní operaci sloučení. Existují nějaké „stříbrné kulky“, plány na realizaci podobných funkcionalit?

Je třeba se podívat na to, jak funguje deduplikace. To, co nyní řeknu, se netýká otázky, ale pro případ by bylo dobré to mít na paměti.

Při vkládání do replikované tabulky dochází k deduplikaci celých vložených bloků. Pokud opakovaně vložíte stejný blok, který obsahuje stejné množství stejných řádků ve stejném pořadí, data se deduplikují. Obdržíte „Ok“ jako odpověď na insert, ale ve skutečnosti bude zapsán pouze jeden blok dat, a ten nebude zdvojen.

To je potřeba pro určení. Pokud během vkládání obdržíte „Ok“, znamená to, že vaše data byla vložena. Pokud dostanete chybu od ClickHouse, znamená to, že nebyla vložena a je třeba vložení opakovat. Ale pokud během vkládání došlo k přerušení spojení, nevíte, zda byla data vložena nebo ne. Jedinou možností je opakovat vložení znovu. Pokud byla data skutečně vložena a vložíte je znovu, existuje deduplikace bloků. Ta je potřebná k předejití duplicit.

A také je důležité, jak to funguje pro materializované pohledy. Pokud byla data deduplikována při vkládání do hlavní tabulky, pak se do materializovaného pohledu také nedostanou.

Nyní k otázce. Máte složitější situaci, protože zapisujete duplicity jednotlivých řádků. To znamená, že celá dávka není zdvojená, ale konkrétní řádky se ve své podstatě zhušťují. Opravdu, data se zhušťují v hlavní tabulce, a do materializovaného pohledu jdou nezhuštěná, a při sloučení se s materializovanými pohledy nic neděje. Protože materializovaný pohled není nic jiného než spouštěč na insert. Při jiných operacích se s ním nic navíc neděje.

A já vás tady nemohu nijak potěšit. Je potřeba jen hledat konkrétní řešení pro tento případ. Například, je možné provést v materializovaném pohledu také jeho nahrazení, a způsob deduplikace by mohl fungovat stejně. Ale bohužel ne vždy. Pokud je to agregační, nebude to možné.

Kirill Shvakov: I my jsme měli v minulosti své vlastní 'kostičkování'. Byla zde otázka, že jsou zobrazení reklamy a některá data, která můžeme prezentovat v reálném čase — jednoduše zobrazení. Ty se zřídka duplikují, ale pokud k tomu dojde, stejně je pak zhušťujeme. A byly věci, které duplikovat nelze — kliknutí a celá tato historie. Ale chtěli jsme je také ukázat prakticky okamžitě.

Jak byly vytvořeny materializované pohledy? Byly pohledy, do kterých se píše přímo — dochází k zápisu do surových dat a zapisuje se to do výhledů. Tam v nějakém okamžiku nejsou data úplně správná, duplikují se atd. A je tu druhá část tabulky, kde vypadají přesně stejně jako materializované pohledy, tedy po struktuře jsou naprosto identické. Každou chvíli znovu přepočítáváme data, dorovnáváme data bez duplikátů a zapisujeme je do těchto tabulek.

Procházeli jsme přes API — v ClickHouse to ručně fungovat nebude. A API sleduje: když mám datum posledního přidání do tabulky, kde jsou již zaručeně správná, spočítaná data, a provede dotaz k jedné tabulce a k druhé tabulce. Z jedné tabulky vybírá do určitého časového úseku a z druhé tabulky doplňuje to, co ještě nebylo spočítáno. A to funguje, ale ne prostředky jednoho ClickHouse.

Pokud máte nějaké API — pro analytiky, pro uživatele — je to v podstatě možnost. Vždycky počítáte, vždycky znovu přepočítáváte. Můžete to dělat jednou denně nebo v nějakou jinou dobu. Sami si zvolíte rozsah, který nepotřebujete a není kritický.

V ClickHouse je spousta logů. Jak mohu vidět všechno, co se s serverem děje v reálném čase?

V ClickHouse je velmi velké množství různých logů, a toto množství stále roste. V nových verzích jsou některé z nich dokonce ve výchozím nastavení zapnuté, ve starších verzích je třeba je zapnout při aktualizaci. Nicméně, je jich stále víc a víc. Rád bych v závěru viděl, co se teď děje na mém serveru, možná na nějakém přehledném dashboardu.

Nemáte ve svém týmu ClickHouse, nebo v týmech vašich přátel, které by podporovaly určitý funkční rámec hotových dashboardů, které by tyto logy zobrazovaly ve formě již připraveného produktu? Jen tak sledovat logy v ClickHouse — to je skvělé. Ale bylo by super, kdyby to už bylo ve formě dashboardu. To by se mi líbilo.

Dashboardy existují, ovšem nejsou standardizované. U nás ve firmě cca 60 týmů používá ClickHouse, a nejpodivnější je, že mnoho z nich má dashboardy, které si udělali sami a jsou trochu jiné. Některé týmy využívají interní instalaci ‚Yandex.Cloud‘. Tam jsou některé hotové reporty, i když ne všechny potřebné. Jiné mají své vlastní.

Moji kolegové z ‚Metрики‘ mají svůj dashboard v Grafaně a já mám svůj podle jejich clusteru. Sleduji tam věci jako kód hits pro cache záznamy. A ještě složitější je, že používáme různé nástroje. Svůj dashboard jsem vytvářel na velmi starém nástroji, který se jmenuje Graphite-web. Je to naprosto ošklivé. A stále ho používám, i když Grafana by byla pravděpodobně pohodlnější a hezčí.

Základní věcí v dashboards je stejná. Jsou to systémové metriky klastru: CPU, paměť, disk, síť. Dalšími jsou počet souběžných dotazů, počet souběžných sloučení, počet dotazů za sekundu, maximální počet částí pro partitiony tabulek MergeTree, zpoždění replikace, velikost replikace fronty, počet vložených řádků za sekundu, počet vložených bloků za sekundu. Toto vše pochází ne z logů, ale z metrik.

Vladimir Kolobajev: Alexi, chtěl bych trochu pozměnit. Existuje Grafana. Grafana má datasource, kterým je ClickHouse. To znamená, že mohu z Grafany posílat dotazy přímo do ClickHouse. V ClickHouse je tabulka s logy, u všech je stejná. Chci, aby v Grafaně bylo možné odkazovat na tuto tabulku logů a vidět ty dotazy, které posílá můj server. Bylo by skvělé mít takový dashboard.

Já jsem si to sám zpracoval. Ale mám otázku – pokud je to všechno standardizované a Grafana se používá všemi, proč v „Jandexu” není takový oficiální dashboard?

Kirill Shvakov: Ve skutečnosti datasource, který je k ClickHouse, nyní podporuje Altinity. A já jen chci naznačit směr, kam se podívat a koho dodat. Můžete se jich zeptat, protože „Jandex” přece jen dělá ClickHouse, ne příběh kolem něj. Altinity je hlavní firma, která nyní ClickHouse propaguje. Neopustí ho, ale budou ho podporovat. Protože v principu, abyste nahráli dashboard na webovou stránku Grafany, stačí se jen zaregistrovat a nahrát ho – nejsou s tím žádné velké problémy.

Alexei Milovidov: Za poslední rok se v ClickHouse přidalo mnoho možností pro analyzování dotazů. Existují metriky pro každý dotaz ohledně využití zdrojů. A zcela nedávno byl přidán také nízkoúrovňový profiler dotazů, abych viděl, kde dotaz stráví každou milisekundu. Ale abych mohl tuto funkčnost využít, musím otevřít konzolového klienta a napsat dotaz, který neustále zapomínám. Někam jsem si ho uložil a neustále zapomínám, kam přesně.

Chtěl bych nástroj, ve kterém by bylo jednoduše napsáno – tady jsou vaše složité dotazy, seskupené podle tříd dotazů. Kliknul bych na nějaký a sdělili by mi, že je složitý kvůli tomu. Takové řešení teď neexistuje. A je docela zvláštní, že když se mě lidé ptají: „Řekněte, existují nějaké hotové dashboardy pro Grafanu?“, odpovídám: „Podívejte se na stránky Grafany, tam je komunita 'Dashboardy', a tam je dashboard od Dímky, je tam dashboard od Kosty. Co to je, nevím, sám jsem je nepoužíval."

Jak ovlivnit merge, aby server nespadl do OOM?

Mám tabulku, ve které je jen jedna partition, je ReplacingMergeTree. Píšu do ní data už čtyři roky. Potřeboval jsem do ní udělat alter a odstranit některá data.

To jsem udělal, a při zpracování tohoto dotazu byla spotřebována veškerá paměť na všech serverech clusteru a všechny servery clusteru se společně dostaly do OOM. Potom se všechny znovu postavily, začaly provádět merge té samé operace, toho bloku dat, a znovu spadly do OOM. Potom se znovu postavily a znovu spadly. A tohle se neopakovalo.

Pak se ukázalo, že to byl ve skutečnosti bug, který kluci opravili. To je skvělé, moc děkuji. Ale pocit zůstal. A teď, když přemýšlím o tom, že bych měl provést nějaký merge v tabulce, objevuje se mi otázka – proč nemohu nějak ovlivnit tyto merge? Například omezit je podle potřebné operační paměti, nebo v zásadě podle jejich počtu, který zpracovává konkrétně tuto tabulku.

Mám tabulku, která se jmenuje 'Metriky', zpracovávej mi ji prosím ve dvou vláknech. Nemusíš vytvářet deset nebo pět merge paralelně, udělej to ve dvou. Myslím, že ve dvou mi paměť stačí, ale na zpracování deseti už nemusí. Proč zůstává strach? Protože tabulka roste a jednou narazím na situaci, kdy už to nebude kvůli bugu, ale proto, že data se změní v tak velkém množství, že mi prostě paměť na serveru nebude stačit. A pak server spadne do OOM při merge. Měnit mutaci mohu zrušit, ale merge už ne.

Víš, při slučování server nespadne do OOM, protože při sloučení se používá množství paměti pouze na jeden malý rozsah dat. Takže vše bude v pořádku, nezávisle na objemu dat.

Vladimir Kolobajev: Dobře. Tady je moment takový, že po provedení opravy chyby jsem si stáhl novou verzi a na jiném, menším, stole, kde je mnoho partií, jsem provedl podobnou operaci. A během sloučení na serveru bylo spáleno asi 100 GB operační paměti. Měl jsem 150 obsazených, 100 snědlo, a zbývá okno na 50 GB, takže jsem nespadl do OOM.

Co mě v tuto chvíli chrání před tím, abych nespadl do OOM, pokud skutečně spotřebovává 100 GB operační paměti? Jak být v situaci, pokud náhle operační paměť u sloučení dojde?

Alexei Milovidov: Je zde problém, že spotřeba operační paměti na sloučení není omezena. A druhý problém spočívá v tom, že pokud bylo nějaké sloučení naplánováno, je nutné je provést, protože je zapsáno v logu replikace. Log replikace jsou ty akce, které jsou potřebné k tomu, aby se replikace dostala do konzistentního stavu. Pokud se neudělají ruční manipulace, které tento log replikace vrátí zpět, sloučení bude muset být provedeno tak či onak.

Samozřejmě, nebylo by na škodu mít omezení na operační paměť, které 'pro každý případ' chrání právě před OOM. To nepomůže sloučení, začne znovu, dosáhne nějakého prahu, vyhodí výjimku a pak začne znovu – z toho nebude nic dobrého. Ale v zásadě by bylo užitečné to omezení zavést.

Jak se bude vyvíjet Golang driver pro ClickHouse?

Golang driver, který napsal Kirill Shvakov, je nyní oficiálně podporován týmem ClickHouse. On v repozitáři ClickHouse, je teď velký a pravý.

Malá poznámka. Existuje úžasné a všemi milované úložiště normálních forem nekonečného pořadí — to je Vertica. Mají také svůj oficiální python ovladač, který je podporován vývojáři Vertica. A několikrát se stalo, že verze úložiště a verze ovladače se dost podstatně lišily, a ovladač v určitém okamžiku přestal fungovat. Druhý bod. Podpora tohoto oficiálního ovladače, mám dojem, funguje systémem „nipple“ — napíšete jim issue a to visí věčně.

Mám dvě otázky. Aktuálně je Golang ovladač Kirilla téměř výchozím způsobem, jak komunikovat z Golangu s ClickHouse. Snad jen někdo stále komunikuje přes http rozhraní, protože mu to tak vyhovuje. Jak bude probíhat vývoj tohoto ovladače? Bude se synchronizovat s nějakými breaking changes v samotném úložišti? A jaký je postup při řešení issue?

Kirill Shvakov: První je, jak to vypadá byrokraticky. Tento bod se téměř nediskutoval, takže na to nemohu odpovědět.

Abych odpověděl na otázku ohledně issue, potřebujeme krátký příběh ovladače. Pracoval jsem ve společnosti, která měla spoustu dat. Byla to reklamní rotace s ohromným počtem událostí, které bylo třeba někde uchovávat. A v určitém okamžiku se objevil ClickHouse. Nalili jsme tam data a na začátku bylo vše v pořádku, ale pak ClickHouse spadl. V tu dobu jsme se rozhodli, že ho nepotřebujeme.

O rok později jsme se vrátili k myšlence využití ClickHouse a potřebovali jsme tam nějakým způsobem psát data. Úvodní podmínka byla taková — hardware je velmi slabý, zdrojů málo. Ale tak jsme vždy fungovali, takže jsme se podívali na nativní protokol.

Při práci na Go bylo jasné, že potřebujeme ovladač na Go. Dělal jsem ho prakticky na plný úvazek — to byla má pracovní úloha. Do určitého okamžiku jsme ho dotáhli a v zásadě nikdo nepředpokládal, že by ho kromě nás někdo používal. Pak přišel CloudFlare se stejným problémem a nějakou dobu jsme s nimi pracovali velmi synchronně, protože měli stejné úkoly. A to jsme dělali jak v ClickHouse samotném, tak v ovladači.

V určitém okamžiku jsem se tomu prostě přestal věnovat, protože moje zapojení ohledně ClickHouse a práce se trochu změnilo. Proto se issues neuzavírají. Občas někdo do repozitáře commitne, protože něco potřebuje. Pak se podívám na pull request a někdy něco sám upravím, ale to se stává zřídka.

Chci se vrátit k ovladači. Před několika lety, když to všechno začínalo, byl ClickHouse také jiný a měl jiné možnosti. Nyní už vím, jak přestavět ovladač, aby to bylo dobré. Pokud k tomu dojde, verze 2 bude v každém případě nekompatibilní kvůli nahromaděným workaroundům.

Jak to zorganizovat, nevím. Sám nemám moc času. Pokud by někdo ovladač zdokonalil, mohl bych mu pomoci a říct, co dělat. Ale aktivní účast „Jandext“ na rozvoji projektu dosud nebyla projednána.

Alexei Milovidov: Ve skutečnosti zatím neexistuje žádná byrokracie ohledně těchto ovladačů. Jediné, co je, že byly přesunuty do oficiální organizace, což znamená, že tento ovladač je považován za oficiální řešení pro Go. Existují nějaké další ovladače, ale ty jsou uvedeny zvlášť.

Uvnitř nemáme žádný vývoj pro tyto ovladače. Otázka zní, zda budeme schopni najmout jednotlivce, ne konkrétně na tento ovladač, ale na rozvoj všech komunitních ovladačů, nebo zda najdeme někoho zvenčí.

Externí slovník se po restartování s povolenou možností lazy_load nezvedá. Co mám dělat?

Máme zapnutou možnost lazy_load a po restartování serveru se slovník sám nezvedá. Zvedá se až poté, co uživatel na tento slovník přistoupí. A při prvním přístupu se objeví chyba. Je možné nějak automaticky prostřednictvím ClickHouse načítat slovníky, nebo je vždy třeba контролovat jejich připravenost, aby uživatelé nedostávali chyby?

Možná máme starou verzi ClickHouse, a proto se slovník automaticky nenahrával. Může to být?

Zaprvé, slovníky lze vynutit načíst pomocí dotazu system reload dictionaries. Zadruhé, ohledně chyby - pokud byl slovník již načten, dotazy budou fungovat na těch datech, která byla načtena. Pokud slovník ještě nebyl načten, začne se načítat přímo během dotazu.

Pro těžké slovníky to není moc pohodlné. Například je třeba stáhnout milion řádků z MySQL. Někdo dělá jednoduchý select, ale ten select bude čekat na ten milion řádků. Existují dvě řešení. První je vypnout lazy_load. Druhé je, když se server spouští, před tím, než se na něj nasadí zátěž, udělat system reload dictionary nebo jednoduše provést dotaz, který používá slovník. Pak bude slovník načten. Je třeba sami kontrolovat dostupnost slovníků se zapnutým nastavením lazy_load, protože ClickHouse je automaticky nepřibarvuje.

Na poslední otázku odpověď je - buď je verze stará, nebo je třeba ladit.

Jak se vypořádat s tím, že system reload dictionaries nezpracovává žádný z mnoha slovníků, pokud alespoň jeden z nich selhal?

Je tu ještě otázka ohledně system reload dictionaries. Máme dva slovníky - jeden se načítá, druhý se nenačítá. System reload dictionaries v takovém případě nenačítá žádný slovník, a je nutné specificky nahrát konkrétní podle jeho názvu pomocí system reload dictionary. Je to také spojeno s verzí ClickHouse?

Chci vás potěšit. Toto chování se měnilo. Pokud aktualizujete ClickHouse, tak se to také změní. Pokud vám aktuální chování nevyhovuje system reload dictionaries, aktualizujte a budeme doufat, že se to změní k lepšímu.

Existuje způsob, jak konfigurovat přihlašovací údaje v konfiguraci ClickHouse, aniž bychom je ukazovali při chybách?

Další otázka se týká chyb spojených se slovníkem, konkrétně přihlašovacích údajů. Zadali jsme přihlašovací údaje v konfiguraci ClickHouse ke slovníku a při chybě dostáváme tyto údaje a heslo jako odpověď.

Vyřešili jsme tuto chybu tím, že jsme přihlašovací údaje přesunuli do konfigurace ovladače ODBC. Existuje nějaký způsob, jak nakonfigurovat údaje v konfiguraci ClickHouse, ale nesvítit tyto údaje při chybách?

Zde je skutečně řešení - uvádět tyto credentials v odbc.ini a v samotném ClickHouse uvádět pouze ODBC Data Source Name. Pro ostatní zdroje slovníků to nebude - ani pro slovník s MySQL, ani pro ostatní byste neměli vidět heslo při zprávě o chybě. Pro ODBC se také podívám - pokud něco takového existuje, je to třeba jednoduše odstranit.

Bonus: pozadí pro Zoom z posezení

Kliknutím na obrázek se pro ty nejúpornější čtenáře otevřou bonusové pozadí z posezení. Uhasíme oheň společně s maskoty technologií Avito, porazíme se s kolegy z místnosti systémového administrátora nebo starobylého počítačového klubu a děláme daily pod mostem na pozadí graffiti.

ClickHouse pro pokročilé uživatele v otázkách a odpovědích

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster