Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Siden ClickHouse er et spesialisert system, er det viktig å ta hensyn til egenskapene til arkitekturen når du bruker det. I denne rapporten vil Alexey snakke om eksempler på vanlige feil ved bruk av ClickHouse, som kan føre til ineffektivt arbeid. Praktiske eksempler vil vise hvordan valg av en eller annen databehandlingsplan kan endre ytelsen i størrelsesordener.

Hei alle sammen! Jeg heter Alexey, jeg lager ClickHouse.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

For det første skynder jeg meg å glede deg med en gang, i dag vil jeg ikke fortelle deg hva ClickHouse er. For å være ærlig er jeg lei av det. Hver gang jeg forteller deg hva det er. Og sikkert alle vet det allerede.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

I stedet vil jeg fortelle deg hvilke mulige feil det er, det vil si hvordan du kan bruke ClickHouse feil. Faktisk er det ingen grunn til å være redd, for vi utvikler ClickHouse som et system som er enkelt, praktisk og fungerer ut av boksen. Jeg installerte det, ingen problemer.

Men du må fortsatt ta i betraktning at dette systemet er spesialisert, og du kan lett komme over en uvanlig bruksak som vil ta dette systemet ut av komfortsonen.

Så, hva slags rake er det? For det meste vil jeg snakke om åpenbare ting. Alt er åpenbart for alle, alle forstår alt og kan være glade for at de er så smarte, og de som ikke forstår vil lære noe nytt.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Det første og enkleste eksempelet, som dessverre ofte forekommer, er et stort antall innsatser med små partier, det vil si et stort antall små innsatser.

Hvis vi vurderer hvordan ClickHouse utfører innsetting, kan du sende minst en terabyte med data i en forespørsel. Det er ikke et problem.

Og la oss se hva den typiske ytelsen vil være. For eksempel har vi en tabell fra Yandex.Metrica-data. Treffer. 105 noen kolonner. 700 byte ukomprimert. Og vi skal sette inn på en god måte i partier på én million rader.

Vi setter inn MergeTree i tabellen, det viser seg en halv million rader per sekund. Flott. I en replikert tabell vil den være litt mindre, omtrent 400 000 rader per sekund.

Og hvis du aktiverer quorumsinnsetting, får du litt mindre, men fortsatt anstendig ytelse, 250 000 termer per sekund. Quorum-innsetting er en udokumentert funksjon i ClickHouse*.

* fra og med 2020, allerede dokumentert.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Hva skjer hvis du gjør noe dårlig? Vi setter inn en rad i MergeTree-tabellen og får 59 rader per sekund. Det er 10 000 ganger tregere. I ReplicatedMergeTree – 6 rader per sekund. Og hvis quorumet er slått på, viser det seg 2 linjer per sekund. Etter min mening er dette en slags absolutt dritt. Hvordan kan du bremse på den måten? Jeg har til og med skrevet på t-skjorten min at ClickHouse ikke bør bremse. Men likevel skjer det noen ganger.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Faktisk er dette vår mangel. Vi kunne lett fått alt til å fungere bra, men det gjorde vi ikke. Og vi gjorde det ikke fordi manuset vårt ikke krevde det. Vi hadde allerede slakt. Vi har nettopp mottatt partier ved inngangen vår, og ingen problemer. Vi setter den inn og alt fungerer bra. Men selvfølgelig er alle slags scenarier mulig. For eksempel når du har en haug med servere som data genereres på. Og de setter ikke inn data så ofte, men de ender likevel opp med hyppige innsettinger. Og vi må på en eller annen måte unngå dette.

Fra et teknisk synspunkt er poenget at når du setter inn i ClickHouse, havner ikke dataene i noen memtable. Vi har ikke engang en ekte loggstruktur MergeTree, men bare en MergeTree, fordi det ikke er verken en logg eller en memTable. Vi skriver ganske enkelt umiddelbart dataene til filsystemet, allerede ordnet i kolonner. Og hvis du har 100 kolonner, må mer enn 200 filer skrives til en egen katalog. Alt dette er veldig tungvint.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Og spørsmålet oppstår: "Hvordan gjøre det riktig?" Hvis situasjonen er slik at du fortsatt trenger å registrere data på en eller annen måte i ClickHouse.

Metode 1. Dette er den enkleste måten. Bruk en slags distribuert kø. For eksempel Kafka. Du trekker ganske enkelt ut data fra Kafka og batcherer dem én gang i sekundet. Og alt blir bra, du spiller inn, alt fungerer bra.

Ulempene er at Kafka er et annet klumpete distribuert system. Jeg forstår også om du allerede har Kafka i bedriften din. Det er bra, det er praktisk. Men hvis det ikke eksisterer, bør du tenke tre ganger før du drar enda et distribuert system inn i prosjektet ditt. Og derfor er det verdt å vurdere alternativer.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Metode 2. Dette er et gammeldags alternativ og samtidig veldig enkelt. Har du en slags server som genererer loggene dine. Og den skriver bare loggene dine til en fil. Og en gang i sekundet gir vi for eksempel nytt navn til denne filen og river av en ny. Og et eget skript, enten via cron eller en demon, tar den eldste filen og skriver den til ClickHouse. Hvis du registrerer logger en gang i sekundet, vil alt være bra.

Men ulempen med denne metoden er at hvis serveren din som loggene genereres på forsvinner et sted, vil dataene også forsvinne.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Metode 3. Det er en annen interessant metode, som ikke krever midlertidige filer i det hele tatt. For eksempel har du en slags reklamespinner eller en annen interessant demon som genererer data. Og du kan samle en haug med data direkte i RAM-en, i bufferen. Og når nok tid har gått, legger du denne bufferen til side, oppretter en ny, og i en egen tråd setter du inn det som allerede har samlet seg i ClickHouse.

På den annen side forsvinner også dataene med kill -9. Hvis serveren din krasjer, vil du miste disse dataene. Og et annet problem er at hvis du ikke var i stand til å skrive til databasen, vil dataene dine samle seg i RAM-en. Og enten vil RAM-en gå tom, eller du vil rett og slett miste data.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Metode 4. En annen interessant metode. Har du en slags serverprosess. Og den kan sende data til ClickHouse umiddelbart, men gjør det i én forbindelse. For eksempel sendte jeg en http-forespørsel med transfer-encoding: chunked with insert. Og det genererer biter ikke så sjelden, du kan sende hver linje, selv om det vil være overhead for innramming av disse dataene.

Men i dette tilfellet vil dataene bli sendt til ClickHouse umiddelbart. Og ClickHouse vil buffere dem selv.

Men det oppstår også problemer. Nå vil du miste data, inkludert når prosessen din er drept og hvis ClickHouse-prosessen er drept, fordi det vil være en ufullstendig innsetting. Og i ClickHouse er innlegg atomære opp til en viss spesifisert terskel i størrelsen på rader. I prinsippet er dette en interessant måte. Kan også brukes.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Metode 5. Her er en annen interessant metode. Dette er en slags fellesskapsutviklet server for databatching. Jeg har ikke sett på det selv, så jeg kan ikke garantere noe. Det gis imidlertid ingen garantier for selve ClickHouse. Dette er også åpen kildekode, men på den annen side kan du være vant til en kvalitetsstandard som vi prøver å gi. Men for denne tingen - jeg vet ikke, gå til GitHub, se på koden. Kanskje de skrev noe normalt.

* fra og med 2020, bør også legges til vurdering KittenHouse.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Metode 6. En annen metode er å bruke buffertabeller. Fordelen med denne metoden er at den er veldig enkel å begynne å bruke. Lag en buffertabell og sett den inn i den.

Ulempen er at problemet ikke er fullstendig løst. Hvis du i en rate som MergeTree må gruppere data med én batch per sekund, må du gruppere minst opptil flere tusen per sekund i en rate i en buffertabell. Hvis det er mer enn 10 000 per sekund, vil det fortsatt være dårlig. Og hvis du setter det inn i partier, så du at det viser seg å være hundre tusen linjer per sekund. Og dette er allerede på ganske tunge data.

Og buffertabeller har heller ikke en logg. Og hvis det er noe galt med serveren din, vil dataene gå tapt.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Og som en bonus fikk vi nylig muligheten hos ClickHouse til å hente data fra Kafka. Det er en bordmotor - Kafka. Du bare skaper. Og du kan henge materialiserte representasjoner på den. I dette tilfellet vil den selv trekke ut data fra Kafka og sette den inn i tabellene du trenger.

Og det som er spesielt gledelig med denne muligheten er at det ikke var vi som gjorde det. Dette er en fellesskapsfunksjon. Og når jeg sier «fellesskapstrekk», mener jeg det uten noen forakt. Vi leste koden, gjorde en anmeldelse, den burde fungere bra.

* Fra og med 2020 har lignende støtte dukket opp for Kanin MQ.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Hva annet kan være upraktisk eller uventet når du setter inn data? Hvis du gjør en forespørsel om å sette inn verdier og skrive noen beregnede uttrykk i verdier. For eksempel er now() også et beregnet uttrykk. Og i dette tilfellet er ClickHouse tvunget til å starte tolken av disse uttrykkene på hver linje, og ytelsen vil falle i størrelsesordener. Det er bedre å unngå dette.

* for øyeblikket er problemet fullstendig løst, det er ikke lenger noen ytelsesregresjon ved bruk av uttrykk i VALUES.

Et annet eksempel er når det kan være noen problemer når du har data på en batch som tilhører en haug med partisjoner. Som standard er ClickHouse-partisjoner etter måned. Og hvis du setter inn en gruppe på en million rader, og det er data i flere år, vil du ha flere dusin partisjoner der. Og dette tilsvarer det faktum at det vil være partier flere titalls ganger mindre i størrelse, fordi innvendig er de alltid først delt inn i skillevegger.

* Nylig, i eksperimentell modus, la ClickHouse til støtte for det kompakte formatet av biter og biter i RAM med skrive-forut-logg, som nesten fullstendig løser problemet.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

La oss nå se på den andre typen problem - dataskriving.

Dataskriving kan være streng eller streng. String er når du nettopp tok den og erklærte at alle feltene dine er av typen streng. Dette suger. Det er ikke nødvendig å gjøre dette.

La oss finne ut hvordan du gjør det riktig i de tilfellene du vil si at vi har et felt, en streng, og la ClickHouse finne ut av det på egen hånd, og jeg vil ikke bry meg. Men det er fortsatt verdt å anstrenge seg.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

For eksempel har vi en IP-adresse. I ett tilfelle lagret vi den som en streng. For eksempel 192.168.1.1. Og i et annet tilfelle vil det være en rekke av typen UInt32*. 32 bits er nok for en IPv4-adresse.

For det første vil dataene merkelig nok bli komprimert omtrent likt. Det vil være en forskjell, selvfølgelig, men ikke så stor. Så det er ingen spesielle problemer med disk I/O.

Men det er en alvorlig forskjell i prosessortid og utføringstid for spørringer.

La oss telle antall unike IP-adresser hvis de er lagret som tall. Det blir 137 millioner linjer per sekund. Hvis det samme er i form av strenger, så 37 millioner linjer per sekund. Jeg vet ikke hvorfor denne tilfeldigheten skjedde. Jeg utførte disse forespørslene selv. Men fortsatt ca 4 ganger tregere.

Og hvis du regner ut forskjellen i diskplass, så er det også en forskjell. Og forskjellen er omtrent en fjerdedel, fordi det er ganske mange unike IP-adresser. Og hvis det var linjer med et lite antall forskjellige betydninger, ville de lett bli komprimert i henhold til ordboken til omtrent samme volum.

Og den firedoble tidsforskjellen ligger ikke på veien. Kanskje du ikke bryr deg, selvfølgelig, men når jeg ser en slik forskjell, blir jeg trist.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

La oss se på forskjellige tilfeller.

1. Ett tilfelle når du har få forskjellige unike verdier. I dette tilfellet bruker vi en enkel praksis som du sannsynligvis kjenner og kan bruke for alle DBMS. Alt dette gir mening ikke bare for ClickHouse. Bare skriv numeriske identifikatorer inn i databasen. Og du kan konvertere til strenger og tilbake på siden av programmet.

For eksempel har du en region. Og du prøver å lagre den som en streng. Og det vil bli skrevet der: Moskva og Moskva-regionen. Og når jeg ser at det står "Moskva", er det ingenting, men når det er Moskva, blir det på en eller annen måte helt trist. Dette er hvor mange byte.

I stedet skriver vi bare ned tallet Ulnt32 og 250. Vi har 250 i Yandex, men ditt kan være annerledes. Bare i tilfelle vil jeg si at ClickHouse har en innebygd evne til å jobbe med en geobase. Du skriver ganske enkelt ned en katalog med regioner, inkludert en hierarkisk, dvs. det vil være Moskva, Moskva-regionen og alt du trenger. Og du kan konvertere på forespørselsnivå.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Det andre alternativet er omtrent det samme, men med støtte inne i ClickHouse. Dette er Enum-datatypen. Du skriver ganske enkelt alle verdiene du trenger inne i Enum. For eksempel, type enhet og skriv der: desktop, mobil, nettbrett, TV. Det er 4 alternativer totalt.

Ulempen er at du må endre den med jevne mellomrom. Bare ett alternativ lagt til. La oss endre tabellen. Faktisk er endringstabell i ClickHouse gratis. Spesielt gratis for Enum fordi dataene på disken ikke endres. Men likevel får alter en lås* på bordet og må vente til alle valg er utført. Og først etter at denne endringen vil bli utført, det vil si at det fortsatt er noen ulemper.

* i de nyeste versjonene av ClickHouse er ALTER laget fullstendig ikke-blokkerende.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Et annet alternativ som er ganske unikt for ClickHouse er å koble til eksterne ordbøker. Du kan skrive tall i ClickHouse, og holde katalogene dine i et hvilket som helst system som passer deg. Du kan for eksempel bruke: MySQL, Mongo, Postgres. Du kan til og med lage din egen mikrotjeneste som sender disse dataene via http. Og på ClickHouse-nivå skriver du en funksjon som vil konvertere disse dataene fra tall til strenger.

Dette er en spesialisert, men veldig effektiv måte å utføre en sammenføyning på et eksternt bord. Og det er to alternativer. I en utførelsesform vil disse dataene være fullstendig bufret, fullstendig tilstede i RAM og oppdatert med en viss frekvens. Og i et annet alternativ, hvis disse dataene ikke passer inn i RAM, kan du delvis cache dem.

Her er et eksempel. Det er Yandex.Direct. Og det er et reklameselskap og bannere. Det er trolig rundt titalls millioner reklameselskaper. Og de passer omtrent inn i RAM-en. Og det er milliarder av bannere, de passer ikke. Og vi bruker en bufret ordbok fra MySQL.

Det eneste problemet er at den hurtigbufrede ordboken vil fungere bra hvis treffraten er nær 100 %. Hvis den er mindre, må du faktisk ta de manglende nøklene og hente dataene fra MySQL når du behandler forespørsler for hver batch med data. Om ClickHouse kan jeg fortsatt garantere at - ja, det går ikke langsommere, jeg vil ikke snakke om andre systemer.

Og som en bonus er ordbøker en veldig enkel måte å retroaktivt oppdatere data i ClickHouse. Det vil si at du hadde en rapport om reklameselskaper, brukeren endret ganske enkelt reklameselskapet og i alle de gamle dataene, i alle rapporter, endret også disse dataene seg. Hvis du skriver rader direkte til tabellen, vil det være umulig å oppdatere dem.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

En annen måte når du ikke vet hvor du skal hente identifikatorene for strengene dine. du kan bare hash det. Dessuten er det enkleste alternativet å ta en 64-bits hash.

Det eneste problemet er at hvis hashen er 64-bit, vil du nesten helt sikkert ha kollisjoner. For hvis det er en milliard linjer der, så blir sannsynligheten allerede merkbar.

Og det ville ikke vært særlig bra å hash navnene på annonseselskaper på denne måten. Hvis annonsekampanjene til ulike selskaper blandes sammen, vil det være noe uforståelig.

Og det er et enkelt triks. Riktignok er det heller ikke veldig egnet for seriøse data, men hvis noe ikke er veldig seriøst, så er det bare å legge til klientidentifikatoren i ordboknøkkelen. Og da vil du ha kollisjoner, men bare innenfor én klient. Og vi bruker denne metoden for lenkekart i Yandex.Metrica. Vi har nettadresser der, vi lagrer hashes. Og vi vet at det selvfølgelig er kollisjoner. Men når siden vises, kan sannsynligheten for at på én side til en bruker noen URL-er sitter fast og dette blir lagt merke til, neglisjeres.

Som en bonus, for mange operasjoner er hash alene tilstrekkelig og strengene i seg selv trenger ikke å lagres noe sted.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Et annet eksempel er hvis strengene er korte, for eksempel nettsteddomener. De kan lagres som de er. Eller for eksempel nettleserspråket ru er 2 byte. Selvfølgelig synes jeg virkelig synd på bytene, men ikke bekymre deg, 2 byte er ikke synd. Vennligst hold det som det er, ikke bekymre deg.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Et annet tilfelle er når det tvert imot er mange linjer og det er mange unike i dem, og til og med settet er potensielt ubegrenset. Et typisk eksempel er søkefraser eller nettadresser. Søkefraser, inkludert skrivefeil. La oss se hvor mange unike søkefraser det er per dag. Og det viser seg at de er nesten halvparten av alle arrangementer. Og i dette tilfellet tror du kanskje at du må normalisere dataene, telle identifikatorene og legge dem i en egen tabell. Men du trenger ikke gjøre det. Bare behold disse linjene som de er.

Det er bedre å ikke finne opp noe, for hvis du lagrer det separat, må du bli med. Og denne sammenføyningen er i beste fall en tilfeldig tilgang til minnet, hvis det fortsatt passer i minnet. Hvis det ikke passer, så blir det problemer.

Og hvis dataene er lagret på plass, blir de ganske enkelt lest i ønsket rekkefølge fra filsystemet og alt er i orden.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Hvis du har nettadresser eller en annen kompleks lang streng, er det verdt å vurdere at du kan beregne et slags utdrag på forhånd og skrive det i en egen kolonne.

For URL-er, for eksempel, kan du lagre domenet separat. Og hvis du virkelig trenger et domene, bruk bare denne kolonnen, og URL-ene vil ligge der, og du vil ikke engang røre dem.

La oss se hva forskjellen er. ClickHouse har en spesialisert funksjon som beregner domenet. Det er veldig raskt, vi har optimalisert det. Og, for å være ærlig, samsvarer den ikke engang med RFC, men likevel vurderer den alt vi trenger.

Og i ett tilfelle vil vi ganske enkelt få URL-ene og beregne domenet. Det fungerer til 166 millisekunder. Og hvis du tar et ferdig domene, viser det seg å være bare 67 millisekunder, det vil si nesten tre ganger raskere. Og det er raskere, ikke fordi vi trenger å gjøre noen beregninger, men fordi vi leser mindre data.

Det er derfor en forespørsel, som er tregere, har en høyere hastighet på gigabyte per sekund. Fordi den leser flere gigabyte. Dette er helt unødvendige data. Forespørselen ser ut til å kjøre raskere, men det tar lengre tid å fullføre.

Og hvis du ser på mengden data på disken, viser det seg at URL-en er 126 megabyte, og domenet er bare 5 megabyte. Det viser seg 25 ganger mindre. Men ikke desto mindre utføres forespørselen bare 4 ganger raskere. Men det er fordi dataene er varme. Og hvis det var kaldt, ville det sannsynligvis vært 25 ganger raskere på grunn av disk I/O.

Forresten, hvis du anslår hvor mye mindre et domene er enn en URL, viser det seg å være omtrent 4 ganger mindre.Men av en eller annen grunn tar dataene opp 25 ganger mindre på disken. Hvorfor? På grunn av kompresjon. Og URL-en er komprimert, og domenet er komprimert. Men ofte inneholder nettadressen en haug med søppel.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Og selvfølgelig lønner det seg å bruke de riktige datatypene som er designet spesifikt for de ønskede verdiene eller som passer. Hvis du er i IPv4, lagre UInt32*. Hvis IPv6, så FixedString(16), fordi IPv6-adressen er 128 biter, dvs. lagret direkte i binært format.

Men hva om du noen ganger har IPv4-adresser og noen ganger IPv6? Ja, du kan lagre begge deler. En kolonne for IPv4, en annen for IPv6. Selvfølgelig er det et alternativ for å vise IPv4 i IPv6. Dette vil også fungere, men hvis du ofte trenger en IPv4-adresse i forespørsler, så ville det vært fint å sette det i en egen kolonne.

* ClickHouse har nå separate IPv4, IPv6 datatyper som lagrer data like effektivt som tall, men representerer dem like praktisk som strenger.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Det er også viktig å merke seg at det er verdt å forhåndsbehandle dataene på forhånd. For eksempel mottar du noen rålogger. Og kanskje du ikke bare bør legge dem i ClickHouse med en gang, selv om det er veldig fristende å ikke gjøre noe og alt vil fungere. Men det er fortsatt verdt å gjennomføre de beregningene som er mulig.

For eksempel nettleserversjon. I en nærliggende avdeling, som jeg ikke ønsker å peke på, lagres nettleserversjonen slik, det vil si som en streng: 12.3. Og så, for å lage en rapport, tar de denne strengen og deler den inn i en matrise, og deretter inn i det første elementet i matrisen. Naturligvis bremser alt. Jeg spurte hvorfor de gjør dette. De fortalte meg at de ikke liker for tidlig optimalisering. Og jeg liker ikke for tidlig pessimisering.

Så i dette tilfellet vil det være mer riktig å dele inn i 4 kolonner. Ikke vær redd her, for dette er ClickHouse. ClickHouse er en kolonneformet database. Og jo mer pene små søyler, jo bedre. Det vil være 5 nettleserversjoner, lag 5 kolonner. Dette er greit.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

La oss nå se på hva du skal gjøre hvis du har mange veldig lange strenger, veldig lange arrays. De trenger ikke å lagres i ClickHouse i det hele tatt. I stedet kan du bare lagre en identifikator i ClickHouse. Og legg disse lange linjene inn i et annet system.

For eksempel har en av våre analysetjenester noen hendelsesparametere. Og hvis det er mange parametere for hendelser, lagrer vi rett og slett de første 512 som kommer over. For 512 er ikke synd.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Og hvis du ikke kan bestemme deg for datatypene dine, kan du også registrere data i ClickHouse, men i en midlertidig tabell av typen Logg, spesielt for midlertidige data. Etter dette kan du analysere hvilken fordeling av verdier du har der, hva som er der generelt, og lage de riktige typene.

*ClickHouse har nå en datatype Lav kardinalitet som lar deg lagre strenger effektivt med mindre innsats.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

La oss nå se på en annen interessant sak. Noen ganger fungerer ting rart for folk. Jeg kommer inn og ser dette. Og det ser umiddelbart ut til at dette ble gjort av en veldig erfaren, smart admin som har lang erfaring med å sette opp MySQL versjon 3.23.

Her ser vi tusen tabeller, som hver registrerer resten av å dele hvem som vet hva med tusen.

I prinsippet respekterer jeg andres opplevelse, inkludert forståelsen av lidelsen som kan oppnås gjennom denne opplevelsen.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Og årsakene er mer eller mindre klare. Dette er gamle stereotypier som kan ha akkumulert under arbeid med andre systemer. For eksempel har ikke MyISAM-tabeller en gruppert primærnøkkel. Og denne måten å dele data på kan være et desperat forsøk på å få samme funksjonalitet.

En annen grunn er at det er vanskelig å gjøre endringer på store bord. Alt vil bli blokkert. Selv om dette problemet ikke lenger er så alvorlig i moderne versjoner av MySQL.

Eller for eksempel microsharding, men mer om det senere.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Det er ikke nødvendig å gjøre dette i ClickHouse, fordi for det første er primærnøkkelen gruppert, dataene er sortert etter primærnøkkelen.

Og noen ganger spør folk meg: "Hvordan varierer ytelsen til rekkeviddespørringer i ClickHouse avhengig av tabellstørrelsen?" Jeg sier at det ikke endrer seg i det hele tatt. For eksempel har du en tabell med en milliard rader og du leser en rekkevidde på en million rader. Alt er bra. Hvis det er en billion rader i en tabell og du leser én million rader, vil det være nesten det samme.

Og for det andre er det ikke nødvendig med alle slags ting som manuelle partisjoner. Hvis du går inn og ser på hva som er på filsystemet, vil du se at tabellen er en ganske stor sak. Og det er noe som skillevegger inni. Det vil si at ClickHouse gjør alt for deg, og du trenger ikke å lide.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Alter i ClickHouse er gratis hvis endre legg til/slipp kolonne.

Og du bør ikke lage små tabeller, for hvis du har 10 rader eller 10 000 rader i en tabell, spiller det ingen rolle i det hele tatt. ClickHouse er et system som optimerer gjennomstrømning, ikke ventetid, så det gir ingen mening å behandle 10 linjer.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Det er riktig å bruke ett stort bord. Bli kvitt gamle stereotypier, alt blir bra.

Og som en bonus, i den nyeste versjonen har vi nå muligheten til å lage en vilkårlig partisjoneringsnøkkel for å utføre alle slags vedlikeholdsoperasjoner på individuelle partisjoner.

For eksempel trenger du mange små tabeller, for eksempel når det er behov for å behandle noen mellomliggende data, mottar du biter og du må utføre en transformasjon på dem før du skriver til finalebordet. For dette tilfellet er det en fantastisk bordmotor - StripeLog. Det er litt som TinyLog, bare bedre.

* nå har også ClickHouse tabellfunksjonsinngang.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Et annet antimønster er mikrosharding. For eksempel må du sønderdele data og du har 5 servere, og i morgen vil det være 6 servere. Og du tenker på hvordan du rebalanserer disse dataene. Og i stedet bryter du ikke i 5 skår, men i 1 skår. Og så tilordner du hver av disse mikroshardene til en separat server. Og du får for eksempel 000 ClickHouses på én server, for eksempel. Separate forekomster på separate porter eller separate databaser.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Men dette er ikke veldig bra i ClickHouse. Fordi selv én ClickHouse-instans prøver å bruke alle tilgjengelige serverressurser til å behandle én forespørsel. Det vil si at du har en slags server og den har for eksempel 56 prosessorkjerner. Du kjører en spørring som tar ett sekund og den vil bruke 56 kjerner. Og hvis du plasserte 200 ClickHouses der på én server, så viser det seg at 10 000 tråder vil starte. Generelt vil alt være veldig dårlig.

En annen årsak er at arbeidsfordelingen på tvers av disse instansene vil være ujevn. Noen blir ferdige tidligere, noen blir ferdige senere. Hvis alt dette skjedde i en instans, ville ClickHouse selv finne ut hvordan de skulle distribuere dataene riktig mellom trådene.

Og en annen grunn er at du vil ha interprosessorkommunikasjon via TCP. Dataene må serialiseres, deserialiseres, og dette er et stort antall mikroshards. Det vil rett og slett ikke fungere effektivt.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Et annet antimønster, selv om det neppe kan kalles et antimønster. Dette er en stor mengde pre-aggregering.

Generelt er pre-aggregering bra. Du hadde en milliard rader, du samlet den og det ble 1 rader, og nå utføres spørringen umiddelbart. Alt er flott. Du får til dette. Og for dette har til og med ClickHouse en spesiell tabelltype, AggregatingMergeTree, som utfører inkrementell aggregering etter hvert som data settes inn.

Men det er tider når du tror at vi vil samle data som dette og aggregere data som dette. Og i noen naboavdelinger vil jeg heller ikke si hvilken, de bruker SummingMergeTree-tabeller for å oppsummere etter primærnøkkelen, og omtrent 20 kolonner brukes som primærnøkkel. Bare i tilfelle endret jeg navnene på noen kolonner for hemmelighold, men det er stort sett det.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Og slike problemer oppstår. For det første reduseres ikke datavolumet for mye. For eksempel reduseres det tre ganger. Tre ganger vil være en god pris for å ha råd til de ubegrensede analysemulighetene som oppstår hvis dataene dine ikke er aggregert. Hvis dataene er aggregerte, får du i stedet for analyser bare ynkelig statistikk.

Og hva er så spesielt med det? Faktum er at disse personene fra naboavdelingen noen ganger går og ber om å få legge til en kolonne til i primærnøkkelen. Det vil si at vi samlet dataene slik, men nå vil vi ha litt mer. Men ClickHouse har ikke en alter primærnøkkel. Derfor må vi skrive noen skript i C++. Og jeg liker ikke skript, selv om de er i C++.

Og hvis du ser på hva ClickHouse ble opprettet for, så er ikke-aggregerte data nøyaktig scenariet det ble født for. Hvis du bruker ClickHouse for ikke-aggregerte data, gjør du det riktig. Hvis du samler, er dette noen ganger tilgivelig.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Et annet interessant tilfelle er spørringer i en uendelig sløyfe. Noen ganger går jeg til en produksjonsserver og ser på vis prosesslisten der. Og hver gang oppdager jeg at noe forferdelig skjer.

For eksempel slik. Det er umiddelbart klart at alt kan gjøres på én forespørsel. Bare skriv inn url og listen der.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Hvorfor er mange slike spørsmål i en endeløs løkke dårlige? Hvis en indeks ikke brukes, vil du ha mange passeringer over de samme dataene. Men hvis indeksen brukes, for eksempel, har du en primærnøkkel for ru og du skriver url = noe der. Og du tror at hvis bare én URL leses fra tabellen, vil alt være bra. Men egentlig nei. Fordi ClickHouse gjør alt i grupper.

Når han trenger å lese en viss rekke data, leser han litt mer, fordi indeksen i ClickHouse er sparsom. Denne indeksen lar deg ikke finne én enkelt rad i tabellen, bare en rekke av et eller annet slag. Og dataene er komprimert i blokker. For å lese en linje, må du ta hele blokken og løsne den. Og hvis du gjør en haug med spørringer, vil du ha mye overlapping, og du vil ha mye arbeid å gjøre om og om igjen.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Og som en bonus kan du merke deg at i ClickHouse bør du ikke være redd for å overføre enda megabyte og til og med hundrevis av megabyte til IN-delen. Jeg husker fra vår praksis at hvis vi i MySQL overfører en haug med verdier til IN-delen, for eksempel overfører vi 100 megabyte av noen tall dit, så spiser MySQL opp 10 gigabyte minne og ingenting annet skjer med det, alt fungerer dårlig.

Og det andre er at i ClickHouse, hvis forespørslene dine bruker en indeks, er det alltid ikke tregere enn en full skanning, det vil si at hvis du trenger å lese nesten hele tabellen, vil den gå sekvensielt og lese hele tabellen. Generelt vil han finne ut av det på egen hånd.

Men det er likevel noen vanskeligheter. For eksempel det faktum at IN med en underspørring ikke bruker indeksen. Men dette er vårt problem, og vi må fikse det. Det er ikke noe grunnleggende her. Vi fikser det*.

Og en annen interessant ting er at hvis du har en veldig lang forespørsel og distribuert forespørselsbehandling pågår, vil denne veldig lange forespørselen bli sendt til hver server uten komprimering. For eksempel 100 megabyte og 500 servere. Og følgelig vil du ha 50 gigabyte overført over nettverket. Det vil bli overført og deretter vil alt bli fullført.

* bruker allerede; Alt ble fikset som lovet.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Og et ganske vanlig tilfelle er når forespørsler kommer fra API. For eksempel opprettet du en slags egen tjeneste. Og hvis noen trenger tjenesten din, åpner du API og bokstavelig talt to dager senere ser du at noe uforståelig skjer. Alt er overbelastet og det kommer inn noen forferdelige forespørsler som aldri skulle ha skjedd.

Og det er bare én løsning. Hvis du har åpnet API-en, må du kutte den. Innfør for eksempel en slags kvoter. Det er ingen andre normale alternativer. Ellers vil de umiddelbart skrive et manus og det blir problemer.

Og ClickHouse har en spesiell funksjon - kvoteberegning. Dessuten kan du overføre kvotenøkkelen din. Dette er for eksempel den interne bruker-IDen. Og kvoter vil bli beregnet uavhengig for hver av dem.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Nå en annen interessant ting. Dette er manuell replikering.

Jeg kjenner til mange tilfeller der folk replikerer ClickHouse manuelt, til tross for at ClickHouse har innebygd replikeringsstøtte.

Hva er prinsippet? Du har en databehandlingspipeline. Og det fungerer uavhengig, for eksempel i forskjellige datasentre. Du skriver de samme dataene på samme måte i ClickHouse. Riktignok viser praksis at dataene fortsatt vil avvike på grunn av noen funksjoner i koden din. Jeg håper den er i din.

Og fra tid til annen må du fortsatt synkronisere manuelt. For eksempel, en gang i måneden gjør administratorer rsync.

Faktisk er det mye enklere å bruke replikeringen innebygd i ClickHouse. Men det kan være noen kontraindikasjoner, for for dette må du bruke ZooKeeper. Jeg skal ikke si noe dårlig om ZooKeeper, i prinsippet fungerer systemet, men det hender at folk ikke bruker det på grunn av java-fobi, fordi ClickHouse er et så bra system, skrevet i C++, som du kan bruke og alt blir bra. Og ZooKeeper er i java. Og på en eller annen måte vil du ikke engang se, men da kan du bruke manuell replikering.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

ClickHouse er et praktisk system. Hun tar hensyn til dine behov. Hvis du har manuell replikering, kan du opprette en distribuert tabell som ser på de manuelle replikaene dine og gjør en failover mellom dem. Og det er til og med et spesielt alternativ som lar deg unngå flopper, selv om linjene dine divergerer systematisk.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Ytterligere problemer kan oppstå hvis du bruker primitive bordmotorer. ClickHouse er en konstruktør som har en haug med forskjellige bordmotorer. For alle alvorlige saker, som skrevet i dokumentasjonen, bruk tabeller fra MergeTree-familien. Og alt det andre - dette er slik, for individuelle tilfeller eller for tester.

I en MergeTree-tabell trenger du ikke ha noen dato og klokkeslett. Du kan fortsatt bruke den. Hvis det ikke er noen dato og klokkeslett, skriv at standard er 2000. Dette vil fungere og vil ikke kreve ressurser.

Og i den nye versjonen av serveren kan du til og med spesifisere at du har tilpasset partisjonering uten en partisjonsnøkkel. Det blir det samme.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

På den annen side kan du bruke primitive bordmotorer. Fyll for eksempel inn dataene én gang og se, vri og slett. Du kan bruke Log.

Eller lagring av små volumer for mellombehandling er StripeLog eller TinyLog.

Minne kan brukes hvis datamengden er liten og du ganske enkelt kan vri noe i RAM-en.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

ClickHouse liker egentlig ikke renormaliserte data.

Her er et typisk eksempel. Dette er et stort antall nettadresser. Du legger dem i neste tabell. Og så bestemte de seg for å gjøre JOIN med dem, men dette vil som regel ikke fungere, fordi ClickHouse kun støtter Hash JOIN. Hvis det ikke er nok RAM for mye data som må kobles til, vil ikke JOIN fungere*.

Hvis dataene er av høy kardinalitet, så ikke bekymre deg, lagre dem i en denormalisert form, URL-ene er direkte på plass i hovedtabellen.

* og nå har ClickHouse også en merge join, og den fungerer under forhold der mellomdata ikke passer inn i RAM. Men dette er ineffektivt, og anbefalingen forblir i kraft.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Et par eksempler til, men jeg tviler allerede på om de er anti-mønster eller ikke.

ClickHouse har en kjent feil. Den vet ikke hvordan den skal oppdatere*. På noen måter er dette til og med bra. Hvis du har noen viktige data, for eksempel regnskap, vil ingen kunne sende det, fordi det ikke er noen oppdateringer.

* støtte for oppdatering og sletting i batch-modus har blitt lagt til for lenge siden.

Men det er noen spesielle måter som tillater oppdateringer som i bakgrunnen. For eksempel tabeller som ReplaceMergeTree. De gjør oppdateringer under bakgrunnssammenslåinger. Du kan tvinge dette ved å bruke optimaliseringstabell. Men ikke gjør dette for ofte, fordi det vil overskrive partisjonen fullstendig.

Distribuerte JOINs i ClickHouse håndteres også dårlig av spørringsplanleggeren.

Dårlig, men noen ganger ok.

Bruker kun ClickHouse for å lese tilbake data ved å bruke select*.

Jeg vil ikke anbefale å bruke ClickHouse for tungvinte beregninger. Men dette er ikke helt sant, for vi går allerede bort fra denne anbefalingen. Og vi har nylig lagt til muligheten til å bruke maskinlæringsmodeller i ClickHouse - Catboost. Og det plager meg fordi jeg tenker: «For en redsel. Dette er hvor mange sykluser per byte det blir! Jeg hater virkelig å kaste bort klokker på bytes.

Effektiv bruk av ClickHouse. Alexey Milovidov (Yandex)

Men ikke vær redd, installer ClickHouse, alt blir bra. Om noe så har vi et fellesskap. Forresten, fellesskapet er deg. Og hvis du har noen problemer, kan du i det minste gå til chatten vår, og forhåpentligvis vil de hjelpe deg.

spørsmål

Takk for rapporten! Hvor kan jeg klage på at ClickHouse krasjer?

Du kan klage til meg personlig akkurat nå.

Jeg har nylig begynt å bruke ClickHouse. Jeg droppet umiddelbart cli-grensesnittet.

For en poengsum.

Litt senere krasjet jeg serveren med et lite utvalg.

Du har talent.

Jeg åpnet en GitHub-feil, men den ble ignorert.

Vi får se.

Alexey lurte meg til å delta på rapporten, og lovet å fortelle meg hvordan du får tilgang til dataene inni.

Veldig enkelt.

Jeg skjønte dette i går. Mer spesifikt.

Det er ingen forferdelige triks der. Det er bare blokk-for-blokk-komprimering. Standard er LZ4, du kan aktivere ZSTD*. Blokkerer fra 64 kilobyte til 1 megabyte.

* det er også støtte for spesialiserte komprimeringskodeker som kan brukes i en kjede med andre algoritmer.

Er blokkene bare rådata?

Ikke helt rått. Det er matriser. Hvis du har en numerisk kolonne, plasseres tall i en rad i en matrise.

Det er klart.

Alexey, et eksempel som var med uniqExact over IP-er, dvs. det faktum at uniqExact tar lengre tid å beregne med linjer enn med tall, og så videre. Hva om vi bruker en finte med ørene og gips ved korrekturlesing? Det vil si at du ser ut til å ha sagt at på vår disk er det ikke veldig annerledes. Hvis vi leser linjer fra disk og cast, vil aggregatene våre være raskere eller ikke? Eller vil vi fortsatt vinne litt her? Det ser ut til at du har testet dette, men av en eller annen grunn ikke indikerte det i benchmarken.

Jeg tror det blir tregere enn uten casting. I dette tilfellet må IP-adressen analyseres fra strengen. Hos ClickHouse er selvfølgelig også vår IP-adresseparsing optimalisert. Vi prøvde veldig hardt, men der har du tallene skrevet på ti tusendel. Veldig ubehagelig. På den annen side vil uniqExact-funksjonen fungere langsommere på strenger, ikke bare fordi dette er strenger, men også fordi en annen spesialisering av algoritmen er valgt. Strenger behandles ganske enkelt annerledes.

Hva om vi tar en mer primitiv datatype? For eksempel skrev vi ned bruker-IDen, som vi har i, skrev den ned som en linje, og så scramblet den, blir det morsommere eller ikke?

Jeg tviler. Jeg tror det blir enda tristere, for tross alt er det å analysere tall et alvorlig problem. Det ser ut til at denne kollegaen til og med ga en rapport om hvor vanskelig det er å analysere tall i ti tusendel, men kanskje ikke.

Alexey, tusen takk for rapporten! Og tusen takk for ClickHouse! Jeg har et spørsmål om planene. Er det noen planer for en funksjon for å oppdatere ordbøker ufullstendig?

Det vil si en delvis omstart?

Ja Ja. Som muligheten til å sette et MySQL-felt der, dvs. oppdatere etter slik at kun disse dataene lastes hvis ordboken er veldig stor.

En veldig interessant funksjon. Og jeg tror noen foreslo det i chatten vår. Kanskje det til og med var deg.

Jeg tror ikke det.

Flott, nå viser det seg at det er to forespørsler. Og du kan sakte begynne å gjøre det. Men jeg vil advare deg med en gang om at denne funksjonen er ganske enkel å implementere. Det vil si at du i teorien bare trenger å skrive versjonsnummeret i tabellen og så skrive: versjon mindre enn slik og slik. Dette betyr at vi mest sannsynlig vil tilby dette til entusiaster. Er du en entusiast?

Ja, men dessverre ikke i C++.

Vet kollegene dine hvordan de skal skrive i C++?

Jeg finner noen.

Flott*.

* funksjonen ble lagt til to måneder etter rapporten - forfatteren av spørsmålet utviklet den og sendte sin trekk forespørsel.

Takk!

Hallo! Takk for rapporten! Du nevnte at ClickHouse er veldig flinke til å konsumere alle ressursene som er tilgjengelige for den. Og foredragsholderen ved siden av Luxoft snakket om sin løsning for Russian Post. Han sa at de virkelig likte ClickHouse, men de brukte det ikke i stedet for hovedkonkurrenten sin, nettopp fordi det spiste opp all CPU. Og de kunne ikke koble den inn i arkitekturen deres, i ZooKeeperen deres med havnearbeidere. Er det mulig å begrense ClickHouse på en eller annen måte slik at den ikke forbruker alt som blir tilgjengelig for den?

Ja, det er mulig og veldig enkelt. Hvis du ønsker å konsumere færre kjerner, så er det bare å skrive set max_threads = 1. Og det er det, den vil utføre forespørselen i en kjerne. I tillegg kan du angi forskjellige innstillinger for forskjellige brukere. Så ikke noe problem. Og fortell kollegene dine fra Luxoft at det ikke er bra at de ikke fant denne innstillingen i dokumentasjonen.

Alexey, hei! Jeg vil gjerne spørre om dette spørsmålet. Dette er ikke første gang jeg har hørt at mange begynner å bruke ClickHouse som lagring for logger. I rapporten sa du ikke å gjøre dette, det vil si at du ikke trenger å lagre lange strenger. Hva synes du om det?

For det første er tømmerstokker som regel ikke lange strenger. Det finnes selvfølgelig unntak. For eksempel, noen tjenester skrevet i java kaster et unntak, det blir logget. Og så videre i en endeløs loop, og plassen på harddisken går tom. Løsningen er veldig enkel. Hvis linjene er veldig lange, kutt dem. Hva betyr lang? Titalls kilobyte er dårlige*.

* i de nyeste versjonene av ClickHouse er "adaptiv indeksgranularitet" aktivert, noe som eliminerer problemet med å lagre lange rader for det meste.

Er en kilobyte normalt?

Det er normalt.

Hallo! Takk for rapporten! Jeg har allerede spurt om dette i chatten, men jeg husker ikke om jeg fikk svar. Er det planer om å utvide WITH-delen på samme måte som CTE?

Ikke ennå. Vår WITH-seksjon er noe useriøs. Det er som en liten funksjon for oss.

Jeg forstår. Takk skal du ha!

Takk for rapporten! Veldig interessant! Globalt spørsmål. Er det noen planer om å endre sletting av data, kanskje i form av noen form for stubber?

Nødvendigvis. Dette er vår første oppgave i køen vår. Vi tenker nå aktivt på hvordan vi skal gjøre alt riktig. Og du bør begynne å trykke på tastaturet*.

* trykket på knappene på tastaturet og gjorde alt.

Vil dette på en eller annen måte påvirke systemytelsen eller ikke? Vil innsettingen gå like raskt som nå?

Kanskje selve slettingene og selve oppdateringene vil være veldig tunge, men dette vil ikke påvirke ytelsen til utvalg eller ytelsen til innlegg.

Og et lite spørsmål til. På presentasjonen snakket du om primærnøkkel. Følgelig har vi partisjonering, som er månedlig som standard, ikke sant? Og når vi setter en datoperiode som passer inn i en måned, er det vel bare denne partisjonen som leses?

Ja.

Et spørsmål. Hvis vi ikke kan velge noen primærnøkkel, er det da riktig å gjøre det spesifikt i henhold til "Dato"-feltet slik at det i bakgrunnen er mindre omorganisering av disse dataene slik at de passer på en mer ryddig måte? Hvis du ikke har rekkeviddespørringer og du ikke engang kan velge en primærnøkkel, er det verdt å sette inn en dato i primærnøkkelen?

Ja.

Kanskje det er fornuftig å legge inn et felt i primærnøkkelen som vil komprimere dataene bedre hvis de er sortert etter dette feltet. For eksempel bruker-ID. Bruker, for eksempel, går til samme nettsted. I dette tilfellet, angi bruker-ID og tid. Og da blir dataene dine bedre komprimert. Når det gjelder datoen, hvis du virkelig ikke har og aldri har rekkeviddespørringer på datoer, trenger du ikke å legge inn datoen i primærnøkkelen.

Ok takk så mye!

Kilde: www.habr.com

Legg til en kommentar