ClickHouse pentru utilizatori avansați în întrebări și răspunsuri

În aprilie, inginerii Avito s-au adunat pentru întâlniri online cu principalul dezvoltator ClickHouse Alexey Milovidov și Kirill Shvakov, un dezvoltator Golang de la Integros. Am discutat despre cum folosim un sistem de gestionare a bazelor de date și ce dificultăți întâmpinăm.

Pe baza întâlnirii, am compilat un articol cu ​​răspunsurile experților la întrebările noastre și ale publicului despre backup-uri, redistribuirea datelor, dicționare externe, driverul Golang și actualizarea versiunilor ClickHouse. Poate fi util pentru dezvoltatorii care lucrează deja activ cu DBMS Yandex și sunt interesați de prezentul și viitorul acestuia. În mod implicit, răspunsurile sunt ale lui Alexey Milovidov, dacă nu este scris altfel.

Atenție, există mult text sub tăietură. Sperăm că conținutul cu întrebări vă va ajuta să navigați.

ClickHouse pentru utilizatori avansați în întrebări și răspunsuri

Conținut

Dacă nu doriți să citiți textul, puteți urmări înregistrarea adunărilor pe canalul nostru de YouTube. Timecodes sunt în primul comentariu de sub videoclip.

ClickHouse este actualizat constant, dar datele noastre nu sunt. Ce să faci în privința asta?

ClickHouse este actualizat constant, iar datele noastre, care au fost optimizate final procesate, nu sunt actualizate și se află într-o copie de rezervă.

Să presupunem că am avut o problemă și s-au pierdut datele. Am decis să restaurăm și s-a dovedit că vechile partiții, care sunt stocate pe serverele de rezervă, sunt foarte diferite de versiunea utilizată în prezent de ClickHouse. Ce să faci într-o astfel de situație și este posibil?

O situație în care ai restaurat date dintr-o copie de rezervă într-un format vechi, dar nu se conectează la noua versiune, este imposibilă. Ne asigurăm că formatul de date din ClickHouse rămâne întotdeauna compatibil cu versiunea inversă. Acest lucru este mult mai important decât compatibilitatea inversă în funcționalitate dacă comportamentul unei funcții utilizate rar s-a schimbat. Noua versiune de ClickHouse ar trebui să poată citi întotdeauna datele care sunt stocate pe disc. Aceasta este legea.

Care sunt cele mai bune practici actuale pentru copierea de rezervă a datelor din ClickHouse?

Cum să facem copii de rezervă, ținând cont de faptul că avem operațiuni finale de optimizare, o bază de date uriașă de teraocteți și date care sunt actualizate, să zicem, în ultimele trei zile, și apoi nu i se întâmplă nicio procedură?

Putem face propria noastră soluție și scrie pe bash: colectați aceste copii de rezervă într-un fel sau altul. Poate că nu este nevoie să cârje nimic, iar bicicleta a fost inventată de mult?

Să începem cu cele mai bune practici. Colegii mei sfătuiesc întotdeauna, ca răspuns la întrebări despre backup, să le reamintească despre serviciul Yandex.Cloud, unde această problemă a fost deja rezolvată. Așa că folosește-l dacă este posibil.

Nu există o soluție completă pentru backup, sută la sută integrată în ClickHouse. Există câteva spații libere care pot fi folosite. Pentru a obține o soluție completă, va trebui fie să modificați puțin manual, fie să creați învelișuri sub formă de scripturi.

Voi începe cu cele mai simple soluții și voi încheia cu cele mai sofisticate, în funcție de volumul de date și de dimensiunea clusterului. Cu cât clusterul este mai mare, cu atât soluția devine mai complexă.

Dacă tabelul cu date ocupă doar câțiva gigaocteți, backup-ul se poate face astfel:

  1. Salvați definiția tabelului, adică metadate − arată creați tabel.
  2. Faceți o descărcare folosind clientul ClickHouse - selecta * de la masă la dosar. În mod implicit, veți primi un fișier în format TabSeparated. Dacă vrei să fii mai eficient, o poți face în format Nativ.

Dacă cantitatea de date este mai mare, atunci backup-ul va dura mai mult timp și mult spațiu. Aceasta se numește o copie de rezervă logică; nu este legată de formatul de date ClickHouse. Dacă este, atunci, ca ultimă soluție, puteți face o copie de rezervă și o puteți încărca în MySQL pentru recuperare.

Pentru cazuri mai avansate, ClickHouse are o capacitate încorporată de a crea un instantaneu al partițiilor în sistemul de fișiere local. Această caracteristică este disponibilă la cerere modificarea partiției de înghețare a mesei. Sau pur și simplu alterează înghețarea mesei - acesta este un instantaneu al întregului tabel.

Instantaneul va fi creat în mod consecvent pentru un tabel pe un fragment, adică este imposibil să creați un instantaneu consistent al întregului cluster în acest fel. Dar pentru majoritatea sarcinilor nu există o astfel de nevoie și este suficient să executați o solicitare pe fiecare fragment și să obțineți un instantaneu consistent. Este creat sub formă de hardlink și, prin urmare, nu ocupă spațiu suplimentar. Apoi, copiați acest instantaneu pe serverul de rezervă sau în spațiul de stocare pe care îl utilizați pentru copii de rezervă.

Restaurarea unei astfel de copii de siguranță este destul de ușoară. Mai întâi, creați tabele folosind definițiile existente ale tabelelor. Apoi, copiați instantaneele salvate ale partițiilor în Directory-Detached pentru aceste tabele și rulați interogarea atașați partiția. Această soluție este destul de potrivită pentru cele mai serioase volume de date.

Uneori aveți nevoie de ceva și mai tare - în cazurile în care aveți zeci sau chiar sute de terabytes pe fiecare server și sute de servere. Există aici o soluție pe care am luat-o de la colegii mei de la Yandex.Metrica. Nu l-aș recomanda tuturor – citiți-l și decideți singur dacă este potrivit sau nu.

Mai întâi trebuie să creați mai multe servere cu rafturi de discuri mari. Apoi, pe aceste servere, ridicați mai multe servere ClickHouse și configurați-le astfel încât să funcționeze ca o altă replică pentru aceleași fragmente. Și apoi utilizați un sistem de fișiere sau un instrument pe aceste servere care vă permite să creați instantanee. Există două opțiuni aici. Prima opțiune este instantanee LVM, a doua opțiune este ZFS pe Linux.

După aceea, în fiecare zi trebuie să creați un instantaneu, acesta va minți și va ocupa puțin spațiu. Desigur, dacă datele se modifică, spațiul va crește în timp. Acest instantaneu poate fi scos în orice moment și datele restaurate, o soluție atât de ciudată. În plus, trebuie să limităm aceste replici în configurație, astfel încât să nu încerce să devină lideri.

Va fi posibil să se organizeze un lag controlat al replicilor în arbori?

Anul acesta plănuiți să faceți arbori în ClickHouse. Va fi posibil să se organizeze un decalaj controlat al replicilor în ele? Am dori să-l folosim pentru a ne proteja de scenarii negative cu modificări și alte schimbări.

Este posibil să faci un fel de derulare înapoi pentru modificări? De exemplu, într-un ax existent, luați și spuneți că până în acest moment aplicați modificările, iar din acest moment încetați să aplicați modificările?

Dacă o comandă a venit la clusterul nostru și a rupt-o, atunci avem o replică condiționată cu o întârziere de oră, unde putem spune că să o folosim în acest moment, dar nu îi vom aplica modificări în ultimele zece minute?

În primul rând, despre decalajul controlat al replicilor. A existat o astfel de solicitare din partea utilizatorilor și am creat o problemă pe Github cu solicitarea: „Dacă cineva are nevoie de asta, îi place, pune o inimă.” Nimeni nu a livrat, iar problema a fost închisă. Cu toate acestea, puteți beneficia deja de această oportunitate prin configurarea ClickHouse. Adevărat, doar începând cu versiunea 20.3.

ClickHouse efectuează în mod constant fuziunea datelor în fundal. Când o îmbinare este finalizată, un anumit set de date este înlocuit cu o bucată mai mare. În același timp, bucăți de date care au existat înainte continuă să rămână pe disc pentru ceva timp.

În primul rând, ele continuă să fie stocate atâta timp cât există interogări selectate care le folosesc, pentru a oferi o operație neblocante. Interogările selectate sunt ușor de citit din bucăți vechi.

În al doilea rând, există și un prag de timp - bucăți vechi de date zac pe disc timp de opt minute. Aceste opt minute pot fi personalizate și chiar transformate într-o singură zi. Acest lucru va costa spațiu pe disc: în funcție de fluxul de date, se dovedește că în ultima zi datele nu numai că se vor dubla, ci ar putea deveni de cinci ori mai multe. Dar dacă există o problemă serioasă, puteți opri serverul ClickHouse și puteți rezolva totul.

Acum se pune întrebarea cum protejează acest lucru împotriva modificărilor. Merită să aruncați o privire mai profundă aici, deoarece în versiunile mai vechi ale ClickHouse, alterul a funcționat în așa fel încât pur și simplu a schimbat piesele direct. Există o bucată de date cu unele fișiere și, de exemplu, facem alter drop coloana. Apoi, această coloană este eliminată fizic din toate bucățile.

Dar începând cu versiunea 20.3, mecanismul de modificare a fost complet schimbat, iar acum bucăți de date sunt întotdeauna imuabile. Nu se schimbă deloc - modificările funcționează acum aproape în același mod ca fuziunile. În loc să înlocuim o piesă pe loc, creăm una nouă. În noua bucată, fișierele care nu s-au schimbat devin hardlink-uri, iar dacă ștergem o coloană, pur și simplu va lipsi din noua bucată. Piesa veche va fi ștearsă implicit după opt minute, iar aici puteți modifica setările menționate mai sus.

Același lucru este valabil și în cazul modificărilor, cum ar fi mutațiile. Când o faci alter ștergere sau modifica actualizarea, nu schimbă piesa, ci creează una nouă. Și apoi îl șterge pe cel vechi.

Ce se întâmplă dacă structura tabelului s-a schimbat?

Cum să restabiliți o copie de rezervă care a fost făcută cu vechea schemă? Și a doua întrebare este despre cazul instantaneelor ​​și instrumentelor de sistem de fișiere. Este Btrfs bun aici în loc de ZFS pe Linux LVM?

Dacă faci atașați partiția partiții cu o structură diferită, atunci ClickHouse vă va spune că acest lucru nu este posibil. Aceasta este soluția. Primul este să creați un tabel temporar de tip MergeTree cu structura veche, să atașați date acolo folosind atașare și să faceți o interogare de modificare. Apoi puteți fie să copiați sau să transferați aceste date și să le atașați din nou, fie să utilizați o solicitare alter table muta partiția.

Acum, a doua întrebare este dacă Btrfs poate fi folosit. Pentru început, dacă aveți LVM, atunci instantaneele LVM sunt suficiente, iar sistemul de fișiere poate fi ext4, nu contează. Cu Btrts, totul depinde de experiența dvs. în utilizarea acestuia. Acesta este un sistem de fișiere matur, dar există încă unele suspiciuni cu privire la modul în care totul va funcționa în practică într-un anumit scenariu. Nu aș recomanda să utilizați acest lucru decât dacă aveți Btrfs în producție.

Care sunt cele mai bune practici actuale în redistribuirea datelor?

Problema redistribuirii este complexă și cu mai multe fațete. Există mai multe răspunsuri posibile aici. Puteți merge dintr-o parte și spune acest lucru - ClickHouse nu are o funcție de reharding încorporată. Dar mă tem că acest răspuns nu se potrivește nimănui. Prin urmare, puteți merge din cealaltă parte și spuneți că ClickHouse are multe modalități de a reîncărca datele.

Dacă clusterul rămâne fără spațiu sau nu poate gestiona încărcarea, adăugați servere noi. Dar aceste servere sunt goale în mod implicit, nu există date pe ele, nu există încărcare. Trebuie să rearanjați datele astfel încât să fie distribuite uniform în noul cluster mai mare.

Primul mod în care se poate face acest lucru este să copiați o parte din partiții pe servere noi folosind o solicitare alter table fetch partition. De exemplu, ați avut partiții pe lună și luați prima lună a anului 2017 și o copiați pe un server nou, apoi copiați a treia lună pe un alt server nou. Și faci asta până devine mai mult sau mai puțin uniform.

Transferul poate fi efectuat numai pentru acele partiții care nu se schimbă în timpul înregistrării. Pentru partițiile noi, înregistrarea va trebui să fie dezactivată, deoarece transferul lor nu este atomic. În caz contrar, veți ajunge cu duplicate sau lacune în date. Cu toate acestea, această metodă este practică și funcționează destul de eficient. Partițiile comprimate gata făcute sunt transmise prin rețea, adică datele nu sunt comprimate sau re-codificate.

Această metodă are un dezavantaj și depinde de schema de fragmentare, dacă v-ați angajat la această schemă de fragmentare, ce cheie de fragmentare ați avut. În exemplul dvs. pentru cazul valorilor, cheia de fragmentare este hash-ul căii. Când selectați un tabel distribuit, acesta merge la toate fragmentele din cluster simultan și preia date de acolo.

Aceasta înseamnă că de fapt nu contează pentru tine ce date au ajuns pe ce fragment. Principalul lucru este că datele de-a lungul unei căi ajung pe un fragment, dar care nu este important. În acest caz, transferul partițiilor gata făcute este perfect, deoarece cu interogări selectate veți primi și date complete - fie înainte de reîncărcare, fie după, schema nu contează cu adevărat.

Dar sunt cazuri care sunt mai complexe. Dacă la nivelul logicii aplicației te bazezi pe o schemă specială de sharding, că acest client este localizat pe un astfel de shard, iar cererea poate fi trimisă direct acolo, și nu către tabelul Distribuit. Sau utilizați o versiune destul de recentă de ClickHouse și ați activat setarea optimizați ignora fragmentele neutilizate. În acest caz, în timpul interogării de selectare, expresia din secțiunea unde va fi analizată și se va calcula ce shard-uri trebuie utilizate conform schemei de sharding. Acest lucru funcționează cu condiția ca datele să fie partiționate exact în conformitate cu această schemă de fragmentare. Dacă le-ați rearanjat manual, corespondența se poate schimba.

Deci aceasta este metoda numărul unu. Și aștept răspunsul tău, dacă metoda este potrivită sau să mergem mai departe.

Vladimir Kolobaev, administrator principal de sistem la Avito: Alexey, metoda pe care ai menționat-o nu funcționează foarte bine atunci când trebuie să împrăștii încărcătura, inclusiv citirea. Putem lua o partiție care este lunară și poate duce luna anterioară la alt nod, dar când vine o solicitare pentru aceste date, o vom încărca doar. Dar am dori să încărcăm întregul cluster, deoarece altfel, de ceva timp întreaga încărcare de citire va fi procesată de două shard-uri.

Alexey Milovidov: Răspunsul aici este ciudat - da, este rău, dar ar putea funcționa. O să explic exact cum. Merită să priviți scenariul de încărcare care se află în spatele datelor dvs. Dacă este vorba de date de monitorizare, atunci aproape sigur putem spune că marea majoritate a solicitărilor sunt pentru date proaspete.

Ați instalat servere noi, ați migrat partiții vechi, dar ați modificat și modul în care sunt înregistrate datele proaspete. Și date noi vor fi răspândite în întreg cluster. Astfel, după doar cinci minute, cererile din ultimele cinci minute vor încărca uniform clusterul; după o zi, cererile pentru 24 de ore vor încărca uniform clusterul. Iar cererile pentru luna precedentă, din păcate, vor ajunge doar la o parte din serverele clusterului.

Dar de multe ori nu veți avea cereri în mod special pentru februarie 2019. Cel mai probabil, dacă cererile intră în 2019, atunci vor fi pentru întregul 2019 - pentru o perioadă mare de timp și nu pentru o gamă mică. Și astfel de solicitări vor putea, de asemenea, să încarce clusterul în mod uniform. Dar, în general, observația dvs. este absolut corectă că aceasta este o soluție ad-hoc care nu distribuie datele complet uniform.

Mai am câteva puncte pentru a răspunde la întrebare. Unul dintre ele este despre cum să proiectați inițial o schemă de fragmentare, astfel încât refacerea să provoace mai puțină durere. Acest lucru nu este întotdeauna posibil.

De exemplu, aveți date de monitorizare. Datele de monitorizare cresc din trei motive. Prima este acumularea de date istorice. Al doilea este creșterea traficului. Iar a treia este o creștere a numărului de lucruri care sunt supuse monitorizării. Există noi microservicii și valori care trebuie salvate.

Este posibil ca dintre acestea, cea mai mare creștere să fie asociată cu al treilea motiv - creșterea utilizării monitorizării. Și în acest caz, merită să vă uitați la natura încărcării, care sunt principalele interogări selectate. Interogările de selectare de bază se vor baza cel mai probabil pe un subset de valori.

De exemplu, utilizarea CPU pe unele servere de către un serviciu. Se pare că există un anumit subset de chei prin care obțineți aceste date. Și cererea în sine pentru aceste date este cel mai probabil destul de simplă și este finalizată în zeci de milisecunde. Folosit pentru serviciile de monitorizare și tablouri de bord. Sper că am înțeles corect acest lucru.

Vladimir Kolobaev: Cert este că de foarte multe ori apelăm la date istorice, deoarece comparăm situația actuală cu cea istorică în timp real. Și este important pentru noi să avem acces rapid la o cantitate mare de date, iar ClickHouse face o treabă excelentă în acest sens.

Aveți perfectă dreptate, majoritatea solicitărilor de citire le întâlnim în ultima zi, ca orice sistem de monitorizare. Dar, în același timp, încărcarea datelor istorice este, de asemenea, destul de mare. Este, practic, de la un sistem de alertă care circulă la fiecare treizeci de secunde și îi spune lui ClickHouse: „Dă-mi datele pentru ultimele șase săptămâni. Acum construiește-mi un fel de medie mobilă din ele și hai să comparăm valoarea actuală cu cea istorică.”

Aș dori să spun că pentru astfel de solicitări foarte recente avem un alt tabel mic în care stocăm doar două zile de date, iar cererile principale zboară în el. Trimitem doar interogări istorice mari către tabelul mare fragmentat.

Alexey Milovidov: Din păcate, se dovedește a fi slab aplicabil pentru scenariul dvs., dar vă voi spune o descriere a două scheme de sharding proaste și complexe care nu trebuie folosite, dar care sunt folosite în serviciul prietenilor mei.

Există un cluster principal cu evenimente Yandex.Metrica. Evenimentele sunt vizualizări de pagină, clicuri și conversii. Cele mai multe solicitări ajung către un anumit site web. Deschideți serviciul Yandex.Metrica, aveți un site web - avito.ru, accesați raportul și se face o solicitare pentru site-ul dvs.

Dar există și alte solicitări - analitice și globale - care sunt făcute de analiști interni. Pentru orice eventualitate, observ că analiștii interni fac cereri doar pentru serviciile Yandex. Dar, cu toate acestea, chiar și serviciile Yandex ocupă o parte semnificativă din toate datele. Acestea sunt cereri nu pentru contoare specifice, ci pentru filtrare mai amplă.

Cum să organizezi datele în așa fel încât totul să funcționeze eficient pentru un singur contor și pentru interogări globale? O altă dificultate este că numărul de solicitări din ClickHouse pentru clusterul Metrics este de câteva mii pe secundă. În același timp, un server ClickHouse nu poate gestiona solicitări non-triviale, de exemplu, câteva mii pe secundă.

Dimensiunea clusterului este de șase sute de servere. Dacă pur și simplu trageți un tabel distribuit peste acest cluster și trimiteți câteva mii de solicitări acolo, va deveni chiar mai rău decât trimiterea lor către un singur server. Pe de altă parte, opțiunea ca datele să fie distribuite în mod uniform, iar noi mergem și solicităm de la toate serverele, este imediat respinsă.

Există o opțiune care este diametral opusă. Imaginați-vă dacă împărțim datele între site-uri și o solicitare pentru un site ajunge la un fragment. Acum clusterul va putea gestiona zece mii de solicitări pe secundă, dar pe un fragment orice cerere va funcționa prea lent. Nu se va mai scala în ceea ce privește debitul. Mai ales dacă acesta este site-ul avito.ru. Nu voi dezvălui secretul dacă spun că Avito este unul dintre cele mai vizitate site-uri din RuNet. Iar procesarea lui pe un ciob ar fi o nebunie.

Prin urmare, schema de fragmentare este concepută într-un mod mai viclean. Întregul cluster este împărțit într-un număr de clustere, pe care le numim straturi. Fiecare cluster conține de la o duzină la câteva zeci de cioburi. Există treizeci și nouă de astfel de grupuri în total.

Cum se scalează toate acestea? Numărul de clustere nu se schimbă - așa cum era acum treizeci și nouă de ani, rămâne așa. Dar în fiecare dintre ele, creștem treptat numărul de fragmente pe măsură ce acumulăm date. Și schema de sharding în ansamblu este astfel: aceste clustere sunt împărțite în site-uri web și, pentru a înțelege ce site web se află pe ce cluster, se folosește o metabază separată în MySQL. Un singur site - pe un singur cluster. Și în interiorul acestuia, sharding-ul are loc în funcție de ID-urile vizitatorilor.

Când înregistrăm, le împărțim la restul diviziunii ID-ului vizitatorului. Dar atunci când adăugați un nou shard, schema de sharding se schimbă; continuăm să împărțim, dar cu un rest al împărțirii cu un alt număr. Aceasta înseamnă că un vizitator este deja localizat pe mai multe servere și nu vă puteți baza pe acest lucru. Acest lucru se face numai pentru a se asigura că datele sunt mai bine comprimate. Și când facem solicitări, mergem la tabelul Distribuit, care se uită la cluster și accesează zeci de servere. Aceasta este o schemă atât de stupidă.

Dar povestea mea va fi incompletă dacă nu spun că am abandonat această schemă. În noua schemă, am schimbat totul și am copiat toate datele folosind clickhouse-copier.

În noua schemă, toate site-urile sunt împărțite în două categorii - mari și mici. Nu știu cum a fost ales pragul, dar rezultatul a fost că site-urile mari sunt înregistrate pe un singur cluster, unde există 120 de fragmente cu trei replici fiecare - adică 360 de servere. Și schema de fragmentare este de așa natură încât orice solicitare ajunge la toate fragmentele simultan. Dacă deschideți acum orice pagină de raport pentru avito.ru în Yandex.Metrica, cererea va ajunge la 120 de servere. Există puține site-uri mari în RuNet. Iar cererile nu sunt o mie pe secundă, ci chiar mai puțin de o sută. Toate acestea sunt mestecate în liniște de Tabelul Distribuit, pe care fiecare dintre ele îl procesează cu 120 de servere.

Iar al doilea cluster este pentru site-uri mici. Iată o schemă de fragmentare bazată pe ID-ul site-ului, iar fiecare solicitare se îndreaptă către exact un fragment.

ClickHouse are un utilitar clickhouse-copier. Ne poți spune despre ea?

Voi spune imediat că această soluție este mai greoaie și oarecum mai puțin productivă. Avantajul este că întinde datele complet conform modelului pe care îl specificați. Dar dezavantajul utilitarului este că nu se reîncarcă deloc. Copiază datele dintr-o schemă de cluster în altă schemă de cluster.

Aceasta înseamnă că pentru ca acesta să funcționeze trebuie să aveți două clustere. Acestea pot fi localizate pe aceleași servere, dar, cu toate acestea, datele nu vor fi mutate incremental, ci vor fi copiate.

De exemplu, erau patru servere, acum sunt opt. Creați un nou tabel distribuit pe toate serverele, noi tabele locale și lansați clickhouse-copier, indicând în el schema de lucru pe care ar trebui să o citească de acolo, acceptați noua schemă de sharding și transferați datele acolo. Și pe serverele vechi veți avea nevoie de o ori și jumătate mai mult spațiu decât există acum, pentru că datele vechi trebuie să rămână pe ele, iar peste ele vor ajunge jumătate din aceleași date vechi. Dacă v-ați gândit în avans că datele trebuie redistribuite și că există spațiu, atunci această metodă este potrivită.

Cum funcționează clickhouse-copier în interior? Împarte toată munca într-un set de sarcini pentru procesarea unei partiții a unui tabel pe un fragment. Toate aceste sarcini pot fi executate în paralel, iar clickhouse-copier poate fi rulat pe diferite mașini în mai multe instanțe, dar ceea ce face pentru o partiție nu este altceva decât o selecție de inserare. Datele sunt citite, decomprimate, repartiționate, apoi comprimate din nou, scrise undeva și resortate. Aceasta este o decizie mai grea.

Ai avut o chestie pilot numită resharding. Ce cu ea?

În 2017, ai avut un lucru pilot numit resharding. Există chiar și o opțiune în ClickHouse. Din câte am înțeles, nu a decolat. Îmi poți spune de ce s-a întâmplat asta? Pare a fi foarte relevant.

Întreaga problemă este că, dacă este necesar să reîncărcați datele în loc, este necesară o sincronizare foarte complexă pentru a face acest lucru atomic. Când am început să ne uităm la modul în care funcționează această sincronizare, a devenit clar că există probleme fundamentale. Și aceste probleme fundamentale nu sunt doar teoretice, ci au început imediat să se arate în practică sub forma a ceva care poate fi explicat foarte simplu - nimic nu funcționează.

Este posibil să îmbinați toate piesele de date înainte de a le muta pe discuri lente?

Întrebare despre TTL cu opțiunea de mutare pe disc lent în contextul îmbinărilor. Există o altă modalitate, în afară de cron, de a îmbina toate părțile într-una singură înainte de a le muta pe discuri lente?

Răspunsul la întrebare este posibil să lipiți cumva automat toate piesele într-una singură înainte de a le transfera - nu. Nu cred că acest lucru este necesar. Nu trebuie să îmbinați toate părțile într-una singură, ci pur și simplu contați pe faptul că acestea vor fi transferate automat pe discuri lente.

Avem două criterii pentru regulile de transfer. Prima este așa cum este umplută. Dacă nivelul de stocare actual are mai puțin de un anumit procent de spațiu liber, selectăm o bucată și o mutăm la o stocare mai lentă. Sau, mai degrabă, nu mai lent, ci următorul - pe măsură ce configurați.

Al doilea criteriu este dimensiunea. Este vorba despre mutarea pieselor mari. Puteți ajusta pragul în funcție de spațiul liber de pe discul rapid, iar datele vor fi transferate automat.

Cum să migrați la versiuni noi de ClickHouse dacă nu există nicio modalitate de a verifica compatibilitatea în avans?

Acest subiect este discutat în mod regulat în chat-ul telegramei ClickHouse ținând cont de diferite versiuni și totuși. Cât de sigur este să faceți upgrade de la versiunea 19.11 la 19.16 și, de exemplu, de la 19.16 la 20.3. Care este cel mai bun mod de a migra la versiuni noi fără a putea verifica în prealabil compatibilitatea în sandbox?

Există mai multe reguli „de aur” aici. În primul rând - citește jurnalul de modificări. Este mare, dar există paragrafe separate despre modificări incompatibile cu înapoi. Nu tratați aceste puncte ca pe un steag roșu. Acestea sunt de obicei incompatibilități minore care implică anumite funcționalități de vârf pe care foarte probabil nu le utilizați.

În al doilea rând, dacă nu există nicio modalitate de a verifica compatibilitatea în sandbox și doriți să actualizați imediat în producție, recomandarea este că nu trebuie să faceți acest lucru. Mai întâi creați un sandbox și testați. Dacă nu există un mediu de testare, atunci cel mai probabil nu aveți o companie foarte mare, ceea ce înseamnă că puteți copia o parte din date pe laptop și să vă asigurați că totul funcționează corect pe acesta. Puteți chiar să ridicați mai multe replici local pe mașina dvs. Sau puteți ridica o nouă versiune de undeva în apropiere și încărcați unele dintre date acolo - adică, creați un mediu de testare improvizat.

O altă regulă este să nu actualizați timp de o săptămână după lansarea versiunii din cauza prinderii erorilor în producție și a remedierii rapide ulterioare. Să ne dăm seama de numerotarea versiunilor ClickHouse pentru a nu ne confunda.

Există versiunea 20.3.4. Numărul 20 indică anul de fabricație - 2020. Din punctul de vedere a ceea ce este în interior, acest lucru nu contează, așa că nu îi vom acorda atenție. Următorul - 20.3. Creștem al doilea număr - în acest caz 3 - de fiecare dată când lansăm o versiune cu unele funcționalități noi. Dacă vrem să adăugăm o funcție la ClickHouse, trebuie să creștem acest număr. Adică, în versiunea 20.4 ClickHouse va funcționa și mai bine. A treia cifră este 20.3.4. Iată 4 numărul de lansări de patch-uri în care nu am adăugat funcții noi, dar am remediat unele erori. Și 4 înseamnă că am făcut-o de patru ori.

Să nu credeți că acesta este ceva groaznic. De obicei, utilizatorul poate instala cea mai recentă versiune și va funcționa fără probleme cu timpul de funcționare pe an. Dar imaginați-vă că într-o funcție de procesare a bitmap-urilor, care a fost adăugată de tovarășii noștri chinezi, serverul se blochează atunci când transmite argumente incorecte. Avem responsabilitatea de a remedia acest lucru. Vom lansa o nouă versiune de patch și ClickHouse va deveni mai stabil.

Dacă aveți ClickHouse care rulează în producție și o nouă versiune de ClickHouse apare cu funcții suplimentare - de exemplu, 20.4.1 este prima, nu vă grăbiți să o puneți în producție chiar în prima zi. De ce este chiar nevoie? Dacă nu utilizați deja ClickHouse, atunci îl puteți instala și, cel mai probabil, totul va fi bine. Dar dacă ClickHouse funcționează deja stabil, atunci fiți cu ochii pe patch-uri și actualizări pentru a vedea ce probleme remediam.

Kiril Șvakov: Aș dori să adaug puțin despre mediile de testare. Toată lumea se teme foarte mult de mediile de testare și dintr-un motiv oarecare cred că, dacă aveți un cluster ClickHouse foarte mare, atunci mediul de testare ar trebui să fie de cel puțin zece ori mai mic. Nu este deloc așa.

Vă pot spune din propriul meu exemplu. Am un proiect și există ClickHouse. Mediul nostru de testare este doar pentru el - aceasta este o mică mașină virtuală în Hetzner pentru douăzeci de euro, unde absolut totul este implementat. Pentru a face acest lucru, avem automatizare completă în Ansible și, prin urmare, în principiu, nu are nicio diferență unde să mergem - la servere hardware sau doar implementați în mașini virtuale.

Ce se poate face? Ar fi bine să oferiți un exemplu în documentația ClickHouse despre cum să implementați un cluster mic în propria dvs. casă - în Docker, în LXC, poate creați un manual Ansible, deoarece diferiți oameni au implementări diferite. Acest lucru va simplifica foarte mult. Când luați și implementați un cluster în cinci minute, este mult mai ușor să încercați să vă dați seama de ceva. Acest lucru este mult mai convenabil, deoarece introducerea într-o versiune de producție pe care nu ați testat-o ​​este un drum spre nicăieri. Uneori funcționează și alteori nu. Și, prin urmare, speranța succesului este rău.

Maxim Kotyakov, inginer senior backend Avito: Voi adăuga puțin despre mediile de testare dintr-o serie de probleme cu care se confruntă marile companii. Avem un cluster de acceptare ClickHouse cu drepturi depline; în ceea ce privește schemele și setările de date, este o copie exactă a ceea ce este în producție. Acest cluster este implementat în containere destul de degradate, cu un minim de resurse. Scriem un anumit procent din datele de producție acolo, din fericire, este posibil să reproducem fluxul în Kafka. Totul acolo este sincronizat și scalat - atât în ​​ceea ce privește capacitatea și fluxul, cât și, în teorie, toate celelalte lucruri fiind egale, ar trebui să se comporte ca producția din punct de vedere al metricii. Tot ceea ce este potențial exploziv este mai întâi aruncat pe acest suport și lăsat acolo câteva zile până când este gata. Dar, firește, această soluție este costisitoare, dificilă și are costuri de suport diferite de zero.

Alexey Milovidov: Vă voi spune cum este mediul de testare al prietenilor noștri de la Yandex.Metrica. Un cluster avea 600 de servere, altul avea 360 și există un al treilea și mai multe clustere. Mediul de testare pentru unul dintre ele este pur și simplu două fragmente cu două replici în fiecare. De ce două cioburi? Ca să nu fii singur. Și ar trebui să existe și replici. Doar o anumită sumă minimă pe care ți-o poți permite.

Acest mediu de testare vă permite să verificați dacă interogările dvs. funcționează și dacă ceva important este întrerupt. Dar adesea apar probleme de o natură complet diferită, când totul funcționează, dar există câteva mici modificări ale încărcăturii.

Să vă dau un exemplu. Am decis să instalăm o nouă versiune de ClickHouse. A fost postat într-un mediu de testare, au fost finalizate teste automate în Yandex.Metrica în sine, care compară datele despre versiunea veche și cea nouă, rulând întreaga conductă. Și, desigur, teste ecologice ale CI. Altfel nici nu am fi propus această versiune.

Totul e bine. Începem să trecem în producție. Primesc un mesaj că încărcarea graficelor a crescut de mai multe ori. Reducem versiunea. Mă uit la grafic și văd: de fapt, sarcina a crescut de câteva ori în timpul lansării și a scăzut înapoi când au fost lansate. Apoi am început să refacem versiunea. Și încărcătura a crescut în același mod și a căzut înapoi în același mod. Deci concluzia este aceasta: sarcina a crescut din cauza aspectului, nimic surprinzător.

Apoi a fost greu să-i convingi pe colegi să instaleze noua versiune. Eu spun: „Este în regulă, lansează. Ține-ți degetele încrucișate, totul va funcționa. Acum sarcina pe grafice a crescut, dar totul este bine. Stai acolo.” În general, am făcut asta și asta este - versiunea a fost lansată pentru producție. Dar aproape cu fiecare aspect apar probleme similare.

Kill query ar trebui să distrugă interogările, dar nu o face. De ce?

Un utilizator, un fel de analist, a venit la mine și a creat o solicitare care a pus clusterul meu ClickHouse. Un nod sau un întreg cluster, în funcție de replică sau fragment la care a fost trimisă cererea. Văd că toate resursele CPU de pe acest server sunt într-un raft, totul este roșu. În același timp, ClickHouse însuși răspunde solicitărilor. Și scriu: „Te rog să-mi arăți, lista de procese, ce cerere a generat această nebunie.”

Găsesc această cerere și îi scriu kill. Și văd că nu se întâmplă nimic. Serverul meu este într-un raft, ClickHouse îmi dă apoi niște comenzi, arată că serverul este în viață și totul este grozav. Dar am degradare în toate solicitările utilizatorilor, degradarea începe cu înregistrările în ClickHouse și interogarea mea de eliminare nu funcționează. De ce? Am crezut că kill query ar trebui să elimine interogările, dar nu o face.

Acum va fi un răspuns destul de ciudat. Ideea este că kill query nu ucide interogările.

Opriți interogarea bifează o căsuță numită „Vreau ca această interogare să fie eliminată”. Și cererea în sine se uită la acest flag atunci când procesează fiecare bloc. Dacă este setat, cererea nu mai funcționează. Se pare că nimeni nu ucide cererea, el însuși trebuie să verifice totul și să se oprească. Și acest lucru ar trebui să funcționeze în toate cazurile în care cererea este în starea de procesare a blocurilor de date. Acesta va procesa următorul bloc de date, va verifica marcajul și va opri.

Acest lucru nu funcționează în cazurile în care cererea este blocată pentru o anumită operațiune. Adevărat, cel mai probabil nu este cazul tău, pentru că, după tine, folosește o tonă de resurse de server. Este posibil ca acest lucru să nu funcționeze în cazul sortării externe și în alte detalii. Dar, în general, acest lucru nu ar trebui să se întâmple, este o eroare. Și singurul lucru pe care îl pot recomanda este să actualizez ClickHouse.

Cum se calculează timpul de răspuns la sarcina de citire?

Există un tabel care stochează agregate de articole - diverse contoare. Numărul de linii este de aproximativ o sută de milioane. Este posibil să contați pe un timp de răspuns previzibil dacă turnați 1K RPS pentru 1K articole?

Judecând după context, vorbim despre sarcina de citire, deoarece nu există probleme cu scrierea - chiar și o mie, chiar o sută de mii și, uneori, câteva milioane de rânduri pot fi inserate.

Solicitările de lectură sunt foarte diferite. În selectarea 1, ClickHouse poate efectua aproximativ zeci de mii de solicitări pe secundă, așa că chiar și cererile pentru o cheie vor necesita deja unele resurse. Și astfel de interogări de puncte vor fi mai dificile decât în ​​unele baze de date cheie-valoare, deoarece pentru fiecare citire este necesar să citiți un bloc de date după index. Indexul nostru se referă nu la fiecare înregistrare, ci la fiecare interval. Adică, va trebui să citiți întregul interval - acesta este implicit de 8192 de linii. Și va trebui să decomprimați blocul de date comprimat de la 64 KB la 1 MB. De obicei, astfel de interogări direcționate durează câteva milisecunde pentru a fi finalizate. Dar aceasta este cea mai simplă opțiune.

Să încercăm niște calcule aritmetice simple. Dacă înmulțiți câteva milisecunde cu o mie, obțineți câteva secunde. Parcă este imposibil să ținem pasul cu o mie de solicitări pe secundă, dar de fapt este posibil, pentru că avem mai multe nuclee de procesor. Așadar, în principiu, ClickHouse poate deține uneori 1000 RPS, dar pentru cereri scurte, anume vizate.

Dacă trebuie să scalați un cluster ClickHouse după numărul de solicitări simple, atunci vă recomand cel mai simplu lucru - creșteți numărul de replici și trimiteți cereri către o replică aleatorie. Dacă o replică deține cinci sute de solicitări pe secundă, ceea ce este complet realist, atunci trei replici vor gestiona o mie și jumătate.

Uneori, desigur, puteți configura ClickHouse pentru numărul maxim de citiri de puncte. Ce este nevoie pentru asta? Primul este de a reduce granularitatea indicelui. În acest caz, nu ar trebui redus la unul, ci pe baza faptului că numărul de intrări în index va fi de câteva milioane sau zeci de milioane pe server. Dacă tabelul are o sută de milioane de rânduri, atunci granularitatea poate fi setată la 64.

Puteți reduce dimensiunea blocului comprimat. Există setări pentru asta dimensiunea minimă a blocului de comprimare, dimensiunea maximă a blocului de compresie. Acestea pot fi reduse, completate cu date, iar apoi interogările vizate vor fi mai rapide. Dar totuși, ClickHouse nu este o bază de date cheie-valoare. Un număr mare de cereri mici este un antimodel de încărcare.

Kiril Șvakov: O sa dau sfaturi in cazul in care sunt conturi obisnuite acolo. Aceasta este o situație destul de standard când ClickHouse stochează un fel de contor. Am un utilizator, el este dintr-o astfel de țară și un al treilea domeniu și trebuie să măresc ceva treptat. Luați MySQL, faceți o cheie unică - în MySQL este o cheie duplicată, iar în PostgreSQL este un conflict - și adăugați un semn plus. Acest lucru va funcționa mult mai bine.

Când nu aveți multe date, nu are prea mult rost să folosiți ClickHouse. Există baze de date obișnuite și fac acest lucru bine.

Ce pot modifica în ClickHouse, astfel încât mai multe date să fie în cache?

Să ne imaginăm o situație - serverele au 256 GB de RAM, în rutina zilnică ClickHouse durează aproximativ 60-80 GB, la vârf - până la 130. Ce poate fi activat și ajustat astfel încât mai multe date să fie în cache și, în consecință, sunt mai puține călătorii pe disc?

De obicei, memoria cache a paginilor sistemului de operare face o treabă bună în acest sens. Dacă deschideți doar partea de sus, uitați-vă acolo în cache sau liber - scrie și cât de mult este în cache - atunci veți observa că toată memoria liberă este folosită pentru cache. Și când citiți aceste date, acestea vor fi citite nu de pe disc, ci de pe RAM. În același timp, pot spune că memoria cache este folosită eficient, deoarece datele comprimate sunt stocate în cache.

Cu toate acestea, dacă doriți să accelerați și mai mult unele interogări simple, este posibil să activați un cache în datele decomprimate din interiorul ClickHouse. Se numeste cache necomprimat. În fișierul de configurare config.xml, setați dimensiunea cache-ului necomprimat la valoarea de care aveți nevoie - recomand nu mai mult de jumătate din memoria RAM liberă, deoarece restul va merge sub cache-ul paginii.

În plus, există două setări de nivel de solicitare. Prima setare - utilizați memoria cache necomprimată - include utilizarea acestuia. Este recomandat să îl activați pentru toate solicitările, cu excepția celor grele, care pot citi toate datele și pot goli memoria cache. Și a doua setare este ceva de genul numărului maxim de linii pentru a utiliza memoria cache. Limitează automat interogările mari, astfel încât acestea să ocolească memoria cache.

Cum pot configura storage_configuration pentru stocarea în RAM?

În noua documentație ClickHouse am citit secțiunea aferentă cu stocarea datelor. Descrierea conține un exemplu cu SSD rapid.

Mă întreb cum se poate configura același lucru cu memoria caldă de volum. Și încă o întrebare. Cum funcționează select cu această organizare de date, va citi întregul set sau numai pe cel care se află pe disc și aceste date sunt comprimate în memorie? Și cum funcționează secțiunea prewhere cu o astfel de organizare de date?

Această setare afectează stocarea bucăților de date, iar formatul acestora nu se schimbă în niciun fel.
Să aruncăm o privire mai atentă.

Puteți configura stocarea datelor în RAM. Tot ceea ce este configurat pentru disc este calea acestuia. Creați o partiție tmpfs care este montată pe o cale în sistemul de fișiere. Specificați această cale ca cale pentru stocarea datelor pentru cea mai fierbinte partiție, bucăți de date încep să sosească și să fie scrise acolo, totul este în regulă.

Dar nu recomand să faceți acest lucru din cauza fiabilității scăzute, deși dacă aveți cel puțin trei replici în centre de date diferite, atunci este posibil. Dacă se întâmplă ceva, datele vor fi restaurate. Să ne imaginăm că serverul a fost oprit brusc și repornit. Partiția a fost montată din nou, dar nu era nimic acolo. Când serverul ClickHouse pornește, vede că nu are aceste piese, deși, conform metadatelor ZooKeeper, ar trebui să fie acolo. Se uită la ce replici le au, le solicită și le descarcă. În acest fel datele vor fi restaurate.

În acest sens, stocarea datelor în RAM nu este fundamental diferită de stocarea lor pe disc, deoarece atunci când datele sunt scrise pe disc, acestea ajung mai întâi în cache-ul paginii și sunt scrise fizic ulterior. Aceasta depinde de opțiunea de montare a sistemului de fișiere. Dar pentru orice eventualitate, voi spune că ClickHouse nu fsync la inserare.

În acest caz, datele din RAM sunt stocate exact în același format ca și pe disc. Interogarea de selectare selectează în același mod piesele care trebuie citite, selectează intervalele de date necesare în bucăți și le citește. Și prewhere funcționează exact la fel, indiferent dacă datele erau în RAM sau pe disc.

Până la ce număr de valori unice este eficientă Cardinalitatea scăzută?

Cardinalitatea scăzută este proiectată inteligent. Compilează dicționare de date, dar sunt locale. În primul rând, există dicționare diferite pentru fiecare piesă, iar în al doilea rând, chiar și într-o singură bucată, acestea pot fi diferite pentru fiecare gamă. Când numărul de valori unice atinge un număr prag - un milion, cred - dicționarul este pur și simplu pus la raft și este creat unul nou.

Răspunsul este în general: pentru fiecare interval local - să zicem, pentru fiecare zi - undeva până la un milion de valori unice Cardinalitatea scăzută este eficientă. După aceea, va exista pur și simplu o alternativă, în care vor fi folosite multe dicționare diferite, și nu doar unul. Va funcționa aproximativ la fel ca o coloană de șir obișnuită, poate puțin mai puțin eficientă, dar nu va exista o degradare serioasă a performanței.

Care sunt cele mai bune practici pentru căutarea textului integral într-un tabel cu cinci miliarde de rânduri?

Există răspunsuri diferite. Primul este să spunem că ClickHouse nu este un motor de căutare full-text. Există sisteme speciale pentru aceasta, de exemplu, Elasticsearch и Sfinx. Cu toate acestea, văd din ce în ce mai mulți oameni spunând că trec de la Elasticsearch la ClickHouse.

De ce se întâmplă asta? Ei explică acest lucru prin faptul că Elasticsearch încetează să facă față sarcinii la unele volume, începând cu construirea de indici. Indecșii devin prea greoi, iar dacă pur și simplu transferați datele în ClickHouse, se dovedește că acestea sunt stocate de câteva ori mai eficient din punct de vedere al volumului. În același timp, interogările de căutare nu au fost adesea de așa natură încât să fie necesar să se găsească o frază în întregul volum de date, ținând cont de morfologie, dar cu totul diferite. De exemplu, găsiți o secvență secundară de octeți în jurnalele din ultimele ore.

În acest caz, creați un index în ClickHouse, primul câmp al căruia va fi data și ora. Și cea mai mare limită de date se va baza pe intervalul de date. În intervalul de date selectat, de regulă, este deja posibilă efectuarea unei căutări full-text, chiar și folosind metoda forței brute folosind like. Operatorul like din ClickHouse este cel mai eficient operator like pe care îl puteți găsi. Dacă găsești ceva mai bun, spune-mi.

Dar totuși, așa cum este o scanare completă. Și scanarea completă poate fi lentă nu numai pe CPU, ci și pe disc. Dacă brusc aveți un terabyte de date pe zi și căutați un cuvânt în timpul zilei, atunci va trebui să scanați terabyte. Și probabil că se află pe hard disk-uri obișnuite, iar în cele din urmă vor fi încărcate în așa fel încât să nu poți accesa acest server prin SSH.

În acest caz, sunt gata să vă ofer încă un mic truc. Este experimental - s-ar putea să funcționeze, s-ar putea să nu. ClickHouse are indexuri full-text sub formă de filtre trigrame Bloom. Colegii noștri de la Arenadata au încercat deja acești indici și adesea funcționează exact așa cum s-a intenționat.

Pentru a le folosi corect, ar trebui să înțelegeți exact cum funcționează: ce este un filtru Bloom trigram și cum să-i alegeți dimensiunea. Pot spune că vor ajuta la interogări pe unele fraze rare, subșiruri care se găsesc rar în date. În acest caz, subintervalele vor fi selectate prin indici și vor fi citite mai puține date.

Recent, ClickHouse a adăugat și mai multe funcții avansate pentru căutarea full-text. Aceasta este, în primul rând, o căutare pentru o grămadă de subșiruri deodată într-o singură trecere, inclusiv opțiuni care sunt sensibile la majuscule, nu sunt sensibile la majuscule, cu suport pentru UTF-8 sau numai pentru ASCII. Alege-l pe cel mai eficient de care ai nevoie.

A apărut și căutarea mai multor expresii regulate într-o singură trecere. Nu trebuie să scrieți X ca un subșir sau X ca un alt subșir. Scrieți imediat și totul se face cât mai eficient posibil.

În al treilea rând, există acum o căutare aproximativă pentru expresii regulate și o căutare aproximativă pentru subșiruri. Dacă cineva a scris greșit un cuvânt, acesta va fi căutat pentru potrivirea maximă.

Care este cea mai bună modalitate de a organiza accesul la ClickHouse pentru un număr mare de utilizatori?

Spuneți-ne cum să organizați cel mai bine accesul pentru un număr mare de consumatori și analiști. Cum se formează o coadă, se prioritizează numărul maxim de interogări simultane și cu ce instrumente?

Dacă clusterul este suficient de mare, atunci o soluție bună ar fi să ridicați încă două servere, care vor deveni un punct de intrare pentru analiști. Adică, nu permiteți analiștilor să acceseze anumite fragmente din cluster, ci pur și simplu creați două servere goale, fără date, și configurați drepturile de acces asupra acestora. În acest caz, setările utilizatorului pentru cererile distribuite sunt transferate către servere la distanță. Adică configurați totul pe aceste două servere, iar setările au efect asupra întregului cluster.

În principiu, aceste servere nu au date, dar cantitatea de RAM de pe ele este foarte importantă pentru executarea solicitărilor. Discul poate fi folosit și pentru date temporare dacă este activată agregarea externă sau sortarea externă.

Este important să ne uităm la setările care sunt asociate cu toate limitele posibile. Dacă acum merg la clusterul Yandex.Metrica ca analist și cer o solicitare selectați numărul dintre accesări, atunci mi se va da imediat o exceptie ca nu pot executa cererea. Numărul maxim de rânduri pe care am voie să le scanez este de o sută de miliarde și, în total, sunt cincizeci de trilioane dintr-un singur tabel de pe cluster. Aceasta este prima limitare.

Să presupunem că elimin limita de rând și rulez din nou interogarea. Apoi voi vedea următoarea excepție - setarea activată indice de forță după dată. Nu pot finaliza interogarea dacă nu am specificat un interval de date. Nu trebuie să vă bazați pe analiști pentru a specifica acest lucru manual. Un caz tipic este atunci când este scris un interval de date unde data evenimentului este între săptămână. Și apoi au specificat pur și simplu o paranteză în locul greșit și, în loc de și, s-a dovedit a fi sau - sau potrivire URL. Dacă nu există nicio limită, va accesa cu crawlere coloana URL și va risipi o mulțime de resurse.

În plus, ClickHouse are două setări de prioritate. Din păcate, sunt foarte primitivi. Unul este pur și simplu numit prioritate. Dacă prioritatea ≠ 0 și cererile cu o anumită prioritate sunt executate, dar se execută o cerere cu o valoare de prioritate mai mică decât, ceea ce înseamnă o prioritate mai mare, atunci o solicitare cu o valoare de prioritate mai mare, ceea ce înseamnă o prioritate mai mică , este pur și simplu suspendat și nu va funcționa deloc în acest timp.

Aceasta este o setare foarte brută și nu este potrivită pentru cazurile în care clusterul are o sarcină constantă. Dar dacă aveți solicitări scurte, în rafale, care sunt importante, iar clusterul este în mare parte inactiv, această configurare este potrivită.

Următoarea setare de prioritate este apelată Prioritatea firului de operare. Pur și simplu setează valoarea bună pentru toate firele de execuție a cererilor pentru planificatorul Linux. Funcționează așa și așa, dar încă funcționează. Dacă setați valoarea minimă nice - este cea mai mare ca valoare și, prin urmare, cea mai scăzută prioritate - și setați -19 pentru cererile cu prioritate mare, atunci CPU-ul va consuma cereri cu prioritate scăzută de aproximativ patru ori mai puțin decât cele cu prioritate ridicată.

De asemenea, trebuie să configurați timpul maxim de execuție a cererii - să zicem, cinci minute. Viteza minimă de execuție a interogării este cel mai tare lucru. Această setare există de mult timp și este necesar nu numai pentru a afirma că ClickHouse nu încetinește, ci și pentru a o forța.

Imaginați-vă, ați configurat: dacă o anumită interogare procesează mai puțin de un milion de rânduri pe secundă, nu puteți face asta. Acest lucru ne dezonorează numele bun, baza noastră de date bună. Să interzicem asta. Există de fapt două setări. Unul este numit viteza minima de executie - în linii pe secundă, iar al doilea se numește timeout înainte de a verifica viteza minimă de execuție - 15 secunde implicit. Adică, sunt posibile cincisprezece secunde și apoi, dacă este lent, atunci doar aruncați o excepție și anulați cererea.

De asemenea, trebuie să stabiliți cote. ClickHouse are o funcție de cotă încorporată care contorizează consumul de resurse. Dar, din păcate, nu resurse hardware precum CPU, discuri, ci cele logice - numărul de cereri procesate, linii și octeți citiți. Și puteți configura, de exemplu, maximum o sută de solicitări în cinci minute și o mie de solicitări pe oră.

De ce este important? Deoarece unele interogări de analiză vor fi efectuate manual direct de la clientul ClickHouse. Și totul va fi bine. Dar dacă aveți analiști avansați în compania dvs., aceștia vor scrie un script și poate exista o eroare în script. Și această eroare va face ca cererea să fie executată într-o buclă infinită. De asta trebuie să ne protejăm.

Este posibil să oferiți rezultatele unei interogări la zece clienți?

Avem mai mulți utilizatori cărora le place să vină cu solicitări foarte mari în același moment. Solicitarea este mare si, in principiu, executata rapid, dar datorita faptului ca sunt multe astfel de solicitari in acelasi timp, devine foarte dureroasa. Este posibil să executăm aceeași cerere, care a sosit de zece ori la rând, o dată, și să dai rezultatul la zece clienți?

Problema este că nu avem rezultatele cache-ului sau cache-ului datelor intermediare. Există o pagină cache a sistemului de operare, care vă va împiedica să citiți din nou datele de pe disc, dar, din păcate, datele vor fi în continuare decomprimate, deserializate și reprocesate.

Aș dori să evit cumva acest lucru, fie prin memorarea în cache a datelor intermediare, fie prin alinierea interogărilor similare într-un fel de coadă și adăugând un cache de rezultate. În prezent, avem o cerere de extragere în dezvoltare care adaugă un cache de cereri, dar numai pentru subinterogări din secțiunile in și join - adică soluția este incompletă.

Cu toate acestea, ne confruntăm și cu o astfel de situație. Un exemplu deosebit de canonic sunt interogările paginate. Există un raport, are mai multe pagini, și există o cerere pentru limita 10. Atunci același lucru, dar limită 10,10. Apoi o altă pagină următoare. Și întrebarea este, de ce numărăm toate acestea de fiecare dată? Dar acum nu există nicio soluție și nu există nicio modalitate de a o evita.

Există o soluție alternativă care este plasată ca sidecar lângă ClickHouse - ClickHouse Proxy.

Kiril Șvakov: ClickHouse Proxy are un limitator de rată încorporat și un cache de rezultate încorporat. S-au făcut multe setări acolo pentru că se rezolva o problemă similară. Proxy vă permite să limitați cererile punându-le în coadă și să configurați cât timp durează memoria cache a cererilor. Dacă solicitările au fost într-adevăr aceleași, Proxy le va trimite de mai multe ori, dar va merge la ClickHouse o singură dată.

Nginx are și un cache în versiunea gratuită, iar acest lucru va funcționa. Nginx are chiar setări care, dacă solicitările ajung în același timp, le va încetini pe altele până când una este finalizată. Dar configurarea se face mult mai bine în ClickHouse Proxy. A fost făcut special pentru ClickHouse, special pentru aceste solicitări, deci este mai potrivit. Ei bine, este ușor de instalat.

Dar operațiunile asincrone și vederile materializate?

Există o problemă că operațiunile cu motorul de reluare sunt asincrone - mai întâi datele sunt scrise, apoi se prăbușesc. Dacă o tabletă materializată cu unele agregate trăiește sub semn, atunci vor fi scrise duplicate pe ea. Și dacă nu există o logică complexă, atunci datele vor fi duplicate. Ce poți face în privința asta?

Există o soluție evidentă - să implementați un declanșator pe o anumită clasă de matview-uri în timpul unei operații de colaps asincron. Există niște gloanțe de argint sau planuri pentru a implementa funcționalități similare?

Merită să înțelegeți cum funcționează deduplicarea. Ceea ce vă voi spune acum nu este relevant pentru întrebare, dar în cazul în care merită amintit.

La inserarea într-un tabel replicat, există o deduplicare a întregului bloc inserat. Dacă reinserați același bloc care conține același număr de aceleași rânduri în aceeași ordine, atunci datele sunt deduplicate. Veți primi „Ok” ca răspuns la inserare, dar de fapt un pachet de date va fi scris și nu va fi duplicat.

Acest lucru este necesar pentru certitudine. Dacă primiți „Ok” în timpul inserării, atunci datele dumneavoastră au fost introduse. Dacă primiți o eroare de la ClickHouse, înseamnă că nu au fost introduse și trebuie să repetați inserarea. Dar dacă conexiunea se pierde în timpul inserării, atunci nu știi dacă datele au fost introduse sau nu. Singura opțiune este să repetați inserarea din nou. Dacă datele au fost efectiv introduse și le-ați reinserat, există deduplicare bloc. Acest lucru este necesar pentru a evita duplicatele.

Și este, de asemenea, important cum funcționează pentru vederile materializate. Dacă datele au fost deduplicate atunci când au fost introduse în tabelul principal, atunci nu vor intra nici în vizualizarea materializată.

Acum despre întrebare. Situația dvs. este mai complicată deoarece înregistrați duplicate ale liniilor individuale. Adică, nu întregul pachet este duplicat, ci linii specifice și se prăbușesc în fundal. Într-adevăr, datele se vor prăbuși în tabelul principal, dar datele nerestrânse vor merge în vizualizarea materializată, iar în timpul îmbinărilor nu se va întâmpla nimic cu vederile materializate. Pentru că o vedere materializată nu este altceva decât un declanșator de inserare. În timpul altor operațiuni, nu i se întâmplă nimic suplimentar.

Și nu te pot face fericit aici. Trebuie doar să cauți o soluție specifică pentru acest caz. De exemplu, este posibil să o redați într-o vizualizare materializată, iar metoda de deduplicare ar putea funcționa în același mod. Dar, din păcate, nu întotdeauna. Dacă se adună, nu va funcționa.

Kiril Șvakov: Am avut și construcție de cârje pe vremea aceea. A existat o problemă că există afișări publicitare și există unele date pe care le putem afișa în timp real - acestea sunt doar afișări. Ele sunt rareori duplicate, dar dacă se întâmplă acest lucru, oricum le vom prăbuși mai târziu. Și erau lucruri care nu puteau fi duplicate - clicuri și toată povestea asta. Dar am vrut să le arăt aproape imediat.

Cum au fost realizate vederile materializate? Au fost vizualizări în care a fost scris direct - a fost scris în date brute și scris în vizualizări. Acolo, la un moment dat datele nu sunt foarte corecte, sunt duplicate, și așa mai departe. Și există o a doua parte a tabelului, în care arată exact la fel ca vederile materializate, adică sunt absolut identice ca structură. Din când în când recalculăm datele, numărăm datele fără duplicate, scriem în acele tabele.

Am trecut prin API - aceasta nu va funcționa manual în ClickHouse. Și API-ul arată: când am data ultimei adăugări la tabel, unde este garantat că datele corecte au fost deja calculate și face o cerere către un tabel și către alt tabel. Dintr-una cererea selectează până la o anumită perioadă de timp, iar din cealaltă primește ceea ce nu a fost încă calculat. Și funcționează, dar nu numai prin ClickHouse.

Dacă aveți un fel de API - pentru analiști, pentru utilizatori - atunci, în principiu, aceasta este o opțiune. Numărați mereu, numărați mereu. Acest lucru se poate face o dată pe zi sau la un alt moment. Îți alegi singur o gamă de care nu ai nevoie și nu este critică.

ClickHouse are o mulțime de jurnale. Cum pot vedea dintr-o privire tot ce se întâmplă cu serverul?

ClickHouse are un număr foarte mare de jurnale diferite, iar acest număr este în creștere. În versiunile noi, unele dintre ele sunt chiar activate implicit; în versiunile mai vechi, acestea trebuie să fie activate la actualizare. Cu toate acestea, sunt din ce în ce mai mulți. În cele din urmă, aș dori să văd ce se întâmplă cu serverul meu acum, poate pe un fel de tablou de bord rezumat.

Aveți o echipă ClickHouse sau echipe ale prietenilor dvs. care acceptă unele funcționalități de tablouri de bord gata făcute care ar afișa aceste jurnale ca un produs finit? În cele din urmă, doar să te uiți la jurnalele în ClickHouse este grozav. Dar ar fi foarte tare dacă ar fi deja pregătit sub forma unui tablou de bord. Aș primi o lovitură din asta.

Există tablouri de bord, deși nu sunt standardizate. În compania noastră, aproximativ 60 de echipe folosesc ClickHouse, iar cel mai ciudat lucru este că multe dintre ele au tablouri de bord pe care le-au făcut singuri și puțin diferite. Unele echipe folosesc o instalare internă Yandex.Cloud. Există câteva rapoarte gata făcute, deși nu toate sunt necesare. Alții le au pe ale lor.

Colegii mei de la Metrica au propriul lor tablou de bord în Grafana, iar eu îl am pe al meu pentru clusterul lor. Mă uit la lucruri precum lovitura cache pentru memoria cache serif. Și și mai dificil este că folosim instrumente diferite. Mi-am creat tabloul de bord folosind un instrument foarte vechi numit Graphite-web. E complet urât. Și încă îl folosesc așa, deși Grafana ar fi probabil mai comodă și mai frumoasă.

Lucrul de bază în tablourile de bord este același. Acestea sunt metrici de sistem pentru cluster: CPU, memorie, disc, rețea. Altele - numărul de solicitări simultane, numărul de îmbinări simultane, numărul de solicitări pe secundă, numărul maxim de bucăți pentru partițiile de tabel MergeTree, decalajul de replicare, dimensiunea cozii de replicare, numărul de rânduri inserate pe secundă, numărul de blocuri inserate pe secundă. Acesta este tot ceea ce se obține nu din jurnale, ci din metrici.

Vladimir Kolobaev: Alexey, aș vrea să o corectez puțin. Există Grafana. Grafana are o sursă de date, care este ClickHouse. Adică pot face cereri de la Grafana direct către ClickHouse. ClickHouse are un tabel cu jurnalele, este același pentru toată lumea. Ca urmare, vreau să accesez acest tabel de jurnal în Grafana și să văd solicitările pe care le face serverul meu. Ar fi grozav să ai un tablou de bord ca acesta.

Am mers eu cu bicicleta. Dar am o întrebare - dacă totul este standardizat și Grafana este folosit de toată lumea, de ce nu are Yandex un astfel de tablou de bord oficial?

Kiril Șvakov: De fapt, sursa de date care merge la ClickHouse acceptă acum Altinity. Și vreau doar să dau un vector unde să sape și pe cine să împingă. Le puteți întreba, pentru că Yandex face încă ClickHouse, și nu povestea din jurul lui. Altinity este principala companie care promovează în prezent ClickHouse. Nu îl vor abandona, ci îl vor sprijini. Pentru că, în principiu, pentru a încărca un tablou de bord pe site-ul Grafana, trebuie doar să îl înregistrați și să îl încărcați - nu există probleme speciale.

Alexey Milovidov: În ultimul an, ClickHouse a adăugat multe capabilități de profilare a interogărilor. Există valori pentru fiecare solicitare privind utilizarea resurselor. Și recent, am adăugat un profiler de interogări chiar de nivel inferior pentru a vedea unde cheltuiește o interogare la fiecare milisecundă. Dar pentru a folosi această funcționalitate, trebuie să deschid clientul consolă și să introduc o cerere, pe care o uit mereu. L-am salvat undeva și tot uit unde anume.

Mi-aș dori să existe un instrument care tocmai a spus, iată interogările tale grele, grupate după clasa de interogări. Am apăsat pe una și mi-au spus că de aceea este grea. Nu există o astfel de soluție acum. Și este destul de ciudat că atunci când oamenii mă întreabă: „Spune-mi, există tablouri de bord gata făcute pentru Grafana?”, spun: „Mergi pe site-ul web Grafana, există o comunitate „Tablouri de bord” și există un tablou de bord. de la Dimka, există un tablou de bord de la Kostyan. Nu știu ce este, nu l-am folosit eu însumi.”

Cum să influențezi fuziunile, astfel încât serverul să nu se blocheze în OOM?

Am un tabel, există o singură partiție în tabel, este ReplacingMergeTree. Am scris date în el de patru ani. Trebuia să fac o modificare în el și să șterg câteva date.

Am făcut asta și, în timpul procesării acestei solicitări, toată memoria de pe toate serverele din cluster a fost consumată și toate serverele din cluster au intrat în OOM. Apoi s-au ridicat cu toții împreună, au început să fuzioneze aceeași operațiune, acest bloc de date și au căzut din nou în OOM. Apoi s-au ridicat din nou și au căzut din nou. Și chestia asta nu s-a oprit.

Apoi s-a dovedit că acesta a fost de fapt o eroare pe care băieții l-au remediat. Este foarte tare, mulțumesc foarte mult. Dar a rămas un reziduu. Și acum, când mă gândesc să fac un fel de îmbinare în tabel, am o întrebare - de ce nu pot influența cumva aceste îmbinări? De exemplu, limitați-le la cantitatea de RAM necesară sau, în principiu, la cantitatea care va procesa acest tabel special.

Am un tabel numit „Metrici”, vă rog să-l procesați în două fire. Nu este nevoie să creați zece sau cinci îmbinări în paralel, faceți-o în două. Cred că am suficientă memorie pentru doi, dar poate să nu fie suficientă pentru a procesa zece. De ce rămâne frica? Pentru că tabelul crește, iar cândva mă voi confrunta cu o situație care, în principiu, nu se mai datorează unui bug, ci pentru că datele se vor schimba într-o cantitate atât de mare încât pur și simplu nu voi avea suficientă memorie pe Server. Și apoi serverul se va prăbuși în OOM la fuzionare. Mai mult, pot anula mutația, dar Merji nu mai este acolo.

Știi, la îmbinare, serverul nu va cădea în OOM, deoarece la îmbinare, cantitatea de RAM este utilizată doar pentru o gamă mică de date. Deci totul va fi bine indiferent de cantitatea de date.

Vladimir Kolobaev: Amenda. Aici momentul este așa încât, după ce eroarea a fost remediată, am descărcat o nouă versiune pentru mine, iar pe o altă masă, una mai mică, unde există multe partiții, am efectuat o operație similară. Și în timpul îmbinării, aproximativ 100 GB de RAM au fost arși pe server. Aveam 150 ocupate, 100 mâncate și o fereastră de 50 GB rămase, așa că nu am căzut în OOM.

Ce mă protejează în prezent să nu cad în OOM dacă consumă efectiv 100 GB de RAM? Ce să faci dacă brusc RAM-ul de pe îmbinări se epuizează?

Alexey Milovidov: Există o astfel de problemă încât consumul de RAM special pentru fuziune nu este limitat. Și a doua problemă este că, dacă a fost atribuit un fel de îmbinare, atunci aceasta trebuie executată deoarece este înregistrată în jurnalul de replicare. Jurnalul de replicare este acțiunile necesare pentru a aduce replica într-o stare consecventă. Dacă nu faceți manipulări manuale care vor derula înapoi acest jurnal de replicare, îmbinarea va trebui efectuată într-un fel sau altul.

Desigur, nu ar fi de prisos să existe o limitare a memoriei RAM care „pentru orice eventualitate” protejează împotriva OOM. Nu va ajuta fuzionarea să se finalizeze, va începe din nou, va atinge un anumit prag, va arunca o excepție și apoi va începe din nou - nu va ieși nimic bun din asta. Dar, în principiu, ar fi util să se introducă această restricție.

Cum va fi dezvoltat driverul Golang pentru ClickHouse?

Șoferul Golang, care a fost scris de Kirill Shvakov, este acum susținut oficial de echipa ClickHouse. El în depozitul ClickHouse, el este acum mare și real.

O mică notă. Există un depozit minunat și iubit de forme normale de ordine infinită - acesta este Vertica. De asemenea, au propriul driver oficial python, care este susținut de dezvoltatorii Vertica. Și de mai multe ori s-a întâmplat ca versiunile de stocare și versiunile de driver să diverge destul de dramatic, iar șoferul să nu mai funcționeze la un moment dat. Și al doilea punct. Sprijinul pentru acest șofer oficial, mi se pare, este realizat de sistemul „mamelon” - le scrieți o problemă și se blochează pentru totdeauna.

Am două întrebări. Acum driverul Golang al lui Kirill este aproape modalitatea implicită de a comunica de la Golang cu ClickHouse. Doar dacă cineva încă comunică prin interfața http pentru că îi place așa. Cum va decurge dezvoltarea acestui driver? Va fi sincronizat cu orice modificări ulterioare din depozitul în sine? Și care este procedura de examinare a unei probleme?

Kiril Șvakov: Primul este modul în care totul este organizat birocratic. Acest punct nu a fost discutat, așa că nu am nimic de răspuns.

Pentru a răspunde la întrebarea despre problemă, avem nevoie de puțin istoric al șoferului. Am lucrat pentru o companie care avea multe date. Era un spinner de publicitate cu un număr mare de evenimente care trebuiau stocate undeva. Și la un moment dat a apărut ClickHouse. L-am umplut cu date și la început totul a fost bine, dar apoi ClickHouse s-a prăbușit. În acel moment am decis că nu avem nevoie.

Un an mai târziu, am revenit la ideea de a folosi ClickHouse și trebuia să scriem date acolo cumva. Mesajul introductiv a fost următorul: hardware-ul este foarte slab, există puține resurse. Dar întotdeauna am lucrat în acest fel și, prin urmare, ne-am uitat către protocolul nativ.

Din moment ce lucram în Go, era clar că avem nevoie de un șofer Go. Am făcut-o aproape cu normă întreagă - era sarcina mea de muncă. L-am adus la un anumit punct și, în principiu, nimeni nu a presupus că altcineva decât noi îl va folosi. Apoi CloudFlare a venit cu exact aceeași problemă și de ceva timp am lucrat cu ei foarte bine, pentru că aveau aceleași sarcini. Mai mult, am făcut asta atât în ​​ClickHouse, cât și în șofer.

La un moment dat, pur și simplu am încetat să o mai fac, pentru că activitatea mea în ceea ce privește ClickHouse și munca s-a schimbat puțin. Prin urmare, problemele nu sunt închise. Periodic, oamenii care au nevoie de ceva se angajează ei înșiși în depozit. Apoi mă uit la cererea de extragere și uneori chiar editez ceva eu, dar acest lucru se întâmplă rar.

Vreau să mă întorc la șofer. În urmă cu câțiva ani, când a început toată treaba, ClickHouse era și el diferit și cu capacități diferite. Acum înțelegem cum să refacem driverul, astfel încât să funcționeze bine. Dacă se întâmplă acest lucru, versiunea 2 va fi în orice caz incompatibilă din cauza cârjelor acumulate.

Nu știu cum să organizez chestia asta. Eu nu prea am timp. Dacă unii termină șoferul, îi pot ajuta și le spun ce să facă. Dar participarea activă a Yandex la dezvoltarea proiectului nu a fost încă discutată.

Alexey Milovidov: De fapt, nu există încă nicio birocrație cu privire la acești șoferi. Singurul lucru este că sunt depuse unei organizații oficiale, adică acest driver este recunoscut ca soluție implicită oficială pentru Go. Există și alți șoferi, dar vin separat.

Nu avem nicio dezvoltare internă pentru acești drivere. Întrebarea este dacă putem angaja o persoană individuală, nu pentru acest șofer anume, ci pentru dezvoltarea tuturor șoferilor comunitari, sau putem găsi pe cineva din exterior.

Dicționarul extern nu se încarcă după o repornire cu setarea lazy_load activată. Ce să fac?

Avem setarea lazy_load activată, iar după ce serverul este repornit, dicționarul nu se încarcă singur. Este ridicată numai după ce utilizatorul accesează acest dicționar. Și prima dată când îl accesez, dă o eroare. Este posibil să încărcați cumva automat dicționare folosind ClickHouse sau trebuie să controlați întotdeauna pregătirea acestora, astfel încât utilizatorii să nu primească erori?

Poate că avem o versiune veche de ClickHouse, așa că dicționarul nu s-a încărcat automat. Ar putea fi cazul?

În primul rând, dicționarele pot fi încărcate forțat folosind o interogare dicționare de reîncărcare a sistemului. În al doilea rând, în ceea ce privește eroarea - dacă dicționarul este deja încărcat, atunci interogările vor funcționa pe baza datelor care au fost încărcate. Dacă dicționarul nu a fost încă încărcat, acesta va fi încărcat direct în timpul solicitării.

Acest lucru nu este foarte convenabil pentru dicționare grele. De exemplu, trebuie să extrageți un milion de rânduri din MySQL. Cineva face o simplă selectare, dar această selecție va aștepta același milion de rânduri. Există două soluții aici. Prima este dezactivarea lazy_load. În al doilea rând, când serverul este pornit, înainte de a pune sarcina pe el, faceți dicționar de reîncărcare a sistemului sau pur și simplu faceți o interogare care folosește un dicționar. Apoi dicționarul va fi încărcat. Trebuie să controlați disponibilitatea dicționarelor cu setarea lazy_load activată, deoarece ClickHouse nu le încarcă automat.

Răspunsul la ultima întrebare este fie că versiunea este veche, fie trebuie depanată.

Ce să faci cu faptul că sistemul de reîncărcare dicționare nu încarcă niciunul dintre numeroasele dicționare dacă cel puțin unul dintre ele se blochează cu o eroare?

Există o altă întrebare despre dicționarele de reîncărcare a sistemului. Avem două dicționare - unul nu este încărcat, al doilea este încărcat. În acest caz, dicționarele de reîncărcare sistem nu încarcă niciun dicționar și trebuie să încărcați punct cu punct un anumit dicționar după numele său folosind dicționarul de reîncărcare a sistemului. Are legătură și cu versiunea ClickHouse?

Vreau să te fac fericit. Acest comportament se schimba. Aceasta înseamnă că dacă actualizați ClickHouse, se va schimba și el. Dacă nu ești mulțumit de comportamentul tău actual dicționare de reîncărcare a sistemului, actualizați și să sperăm că se va schimba în bine.

Există o modalitate de a configura detaliile în configurația ClickHouse, dar să nu le afișați în caz de erori?

Următoarea întrebare este despre erori legate de dicționar și anume detalii. Am specificat detaliile conexiunii în configurația ClickHouse pentru dicționar și, dacă există o eroare, primim aceste detalii și parola ca răspuns.

Am rezolvat această eroare adăugând detalii la configurația driverului ODBC. Există vreo modalitate de a configura detaliile din configurația ClickHouse, dar să nu afișați aceste detalii în caz de erori?

Soluția reală aici este să specificați aceste acreditări în odbc.ini, iar în ClickHouse în sine specificați doar Numele sursei de date ODBC. Acest lucru nu se va întâmpla pentru alte surse de dicționar - nici pentru dicționarul cu MySQL, nici pentru celelalte, nu ar trebui să vedeți parola când primiți un mesaj de eroare. Pentru ODBC, voi căuta și - dacă există, trebuie doar să-l eliminați.

Bonus: fundaluri pentru Zoom de la reuniuni

Făcând clic pe imagine, fundalurile bonus de la adunări se vor deschide pentru cei mai persistenti cititori. Am stins focul împreună cu mascotele tehnologiei Avito, ne discutăm cu colegii din camera administratorului de sistem sau din clubul de computere din vechime școală și facem întâlniri zilnice sub pod pe fundalul graffiti-urilor.

ClickHouse pentru utilizatori avansați în întrebări și răspunsuri

Sursa: www.habr.com

Adauga un comentariu