ClickHouse dla zaawansowanych użytkowników w pytaniach i odpowiedziach

W kwietniu inżynierowie Avito spotkali się na online'em z głównym programistą ClickHouse, Aleksejem Milowidowem oraz Kirillem Szwakowem, programistą Golang z firmy Integros. Dyskutowali o tym, jak wykorzystujemy system zarządzania bazami danych i jakie trudności napotykamy.

Na podstawie spotkania zebraliśmy artykuł z odpowiedziami ekspertów na nasze oraz widzów pytania dotyczące kopii zapasowych, reshardingu danych, zewnętrznych słowników, sterownika Golang i aktualizacji wersji ClickHouse. Może być przydatny dla programistów, którzy już aktywnie pracują z bazą danych "Yandeks" i interesują się jej teraźniejszością oraz przyszłością. Domyślnie odpowiedzi Alekseja Milowidowa, chyba że zaznaczone jest inaczej.

Uwaga, pod tym opisem znajduje się dużo tekstu. Mamy nadzieję, że zawartość z pytaniami pomoże wam się zorientować.

ClickHouse dla zaawansowanych użytkowników w pytaniach i odpowiedziach

Spis treści

Jeśli nie chcesz czytać tekstu, możesz obejrzeć nagranie spotkania. na naszym kanale youtube. Czas kody – w pierwszym komentarzu pod filmem.

ClickHouse jest ciągle aktualizowany, a nasze dane nie. Co z tym zrobić?

ClickHouse jest ciągle aktualizowany, a nasze dane, które były ostatecznie zoptymalizowane, nie są aktualizowane i leżą w kopii zapasowej.

Załóżmy, że mamy jakiś problem i dane zostały utracone. Postanowiliśmy się odbudować i okazało się, że stare partycje, które leżą na serwerach kopii zapasowej, znacznie różnią się od używanej na ten moment wersji ClickHouse. Co w takiej sytuacji robić i czy jest to możliwe?

Sytuacja, w której przywracasz z kopii zapasowej dane w starym formacie, a w nowej wersji nie są one ładowane, jest niemożliwa. Dbamy o to, aby format danych w ClickHouse zawsze pozostawał wstecznie kompatybilny. Jest to znacznie ważniejsze niż wsteczna kompatybilność funkcji, jeśli zmieniło się działanie jakiejś rzadko używanej funkcji. Nowa wersja ClickHouse zawsze powinna być w stanie odczytać dane przechowywane na dysku. To zasada.

Jakie są obecnie najlepsze praktyki dotyczące tworzenia kopii zapasowych danych z ClickHouse?

Jak robić kopie zapasowe biorąc pod uwagę, że mamy operacje optymalizacji finalnej, ogromną bazę danych na terabajty i dane, które są aktualizowane, powiedzmy, przez ostatnie trzy dni, a później z nimi nie wykonuje się żadnych procedur?

Możemy stworzyć własne rozwiązanie i na bashu napisać: zbieraj te kopie zapasowe tak i tak. Może nie trzeba niczego tworzyć od podstaw, a rower już wymyślono?

Na początek w sprawie najlepszych praktyk. Moi koledzy zawsze radzą, aby w odpowiedzi na pytania dotyczące kopii zapasowych przypominać o usłudze „Yandex.Cloud”, gdzie to zadanie już zostało rozwiązane. Korzystaj z niej, jeśli masz taką możliwość.

Nie ma pełnego rozwiązania, w stu procentach zintegrowanego z ClickHouse, do backupów. Są pewne szablony, które można wykorzystać. Aby uzyskać pełne rozwiązanie, trzeba będzie albo trochę ręcznie się pobawić, albo stworzyć opakowania w postaci skryptów.

Zacznę od najprostszych rozwiązań i skończę na najbardziej zaawansowanych, w zależności od objętości danych i rozmiaru klastra. Im większy klaster, tym bardziej skomplikowane staje się rozwiązanie.

Jeśli tabela z danymi zajmuje zaledwie kilka gigabajtów, backup można wykonać tak:

  1. Zachowaj definicję tabeli, czyli metadane — show create table.
  2. Wykonaj zrzut za pomocą klienta ClickHouse — select * z tabeli do pliku. Domyślnie otrzymasz plik w formacie TabSeparated. Jeśli chcesz bardziej efektywnego rozwiązania — można w formacie Native.

Jeśli objętość danych jest większa, to backup zajmie więcej czasu i wiele miejsca. Nazywa się to backupem logicznym, nie jest on związany z formatem danych ClickHouse. Jeśli to masz, to w ostateczności możesz wziąć backup i załadować go do MySQL, aby go przywrócić.

Dla bardziej zaawansowanych przypadków w ClickHouse wbudowana jest możliwość tworzenia migawki partycji w lokalnym systemie plików. Ta opcja dostępna jest w formie zapytania alter table freeze partition. Lub po prostu alter table freeze — to migawka całej tabeli.

Migawka będzie tworzona jako spójna dla jednej tabeli na jednym shardzie, tzn. nie jest możliwe stworzenie spójnej migawki całego klastra w ten sposób. Jednak dla większości zadań taka potrzeba nie istnieje, i wystarczy wykonać zapytanie na każdym shardzie, aby uzyskać spójną migawkę. Tworzy się ją w formie hardlinków, więc nie zajmuje dodatkowego miejsca. Następnie tę migawkę kopiujesz na serwer backupowy lub do repozytorium, które wykorzystujesz do backupów.

Przywrócenie takiego backupu jest dość łatwe. Najpierw — tworzysz tabele według mających się definicji tabel. Następnie kopiujesz zapisane migawki partycji do Directory-Detached dla danego tabel i wykonujesz zapytanie attach partition. Takie rozwiązanie jest w pełni odpowiednie dla najbardziej poważnych objętości danych.

Czasami potrzebne jest coś jeszcze lepszego — w takich przypadkach, gdy na każdym serwerze masz dziesiątki lub nawet setki terabajtów, a serwerów jest setki. Istnieje rozwiązanie, które podpatrzyłem u kolegów z „Yandex.Metrics”. Nie polecałbym go każdemu — przeczytaj i sam zdecyduj, czy jest odpowiednie czy nie.

Najpierw musisz stworzyć kilka serwerów z dużymi półkami dyskowymi. Następnie na tych serwerach uruchomić kilka serwerów ClickHouse i skonfigurować je tak, aby działały jak kolejna replika dla tych samych shardów. Następnie korzystaj na tych serwerach z systemu plików lub jakiegoś narzędzia, które pozwala na tworzenie migawków. Są dwie opcje. Pierwsza opcja — to migawki LVM, druga opcja — ZFS na Linuksie.

Po tym każdego dnia należy tworzyć migawkę, która będzie zajmować jakieś miejsce. Oczywiście, jeśli dane się zmieniają, to z biegiem czasu objętość zajmowanego miejsca będzie rosła. Tę migawkę można odzyskać w dowolnym momencie i przywrócić dane, to dość dziwne rozwiązanie. Dodatkowo musisz ograniczyć te repliki w konfiguracji, aby nie próbowały stać się liderami.

Czy można zorganizować kontrolowane opóźnienie replik w walcach?

W tym roku planujesz zaimplementować w ClickHouse mechanizmy walidacji. Czy będzie można w nich zorganizować kontrolowane opóźnienie replik? Chcielibyśmy użyć tego, aby zabezpieczyć się przed negatywnymi scenariuszami związanymi z alternatywami i innymi zmianami.

Czy można zrealizować jakieś roll backi dla alternatyw? Na przykład, w istniejącym wale wziąć i powiedzieć, że do tego momentu stosuj zmiany, a od tego momentu przestań stosować zmiany?

Jeśli do naszego klastra dotarł zespół i go uszkodził, to mamy zazwyczaj replikę z opóźnieniem godzinowym, w której możemy powiedzieć, że użyjmy jej na ten moment, ale ostatnich dziesięciu minut zmian w niej nie zastosujemy?

Na początek o kontrolowanym opóźnieniu replik. Taki wniosek wystąpił od użytkowników, więc stworzyliśmy zgłoszenie na GitHubie z prośbą: „Jeśli ktoś tego potrzebuje, dajcie znać, polubcie, wrzućcie serduszko”. Nikt tego nie polubił, więc zgłoszenie zamknięto. Niemniej jednak, już teraz można uzyskać taką możliwość, konfigurując ClickHouse. Prawda, tylko począwszy od wersji 20.3.

ClickHouse stale na bieżąco łączy dane – merge. Po wykonaniu merge, pewien zbiór fragmentów danych jest zastępowany większym fragmentem. Przy tym kawałki danych, które były wcześniej, nadal pozostają na dysku przez pewien czas.

Po pierwsze, są one przechowywane tak długo, jak długo istnieją zapytania select, które z nich korzystają, aby zapewnić nieblokującą pracę. Zapytania select mogą w spokoju odczytywać ze starych fragmentów.

Po drugie, istnieje również próg czasowy – stare fragmenty danych leżą na dysku przez osiem minut. Te osiem minut można dostosować i przekształcić nawet w jeden dzień. Będzie to kosztować miejsce na dysku: w zależności od przepływu danych okaże się, że dane z ostatniego dnia nie tylko się podwajają, mogą stać się pięć razy większe. Ale w przypadku poważnego problemu możesz zatrzymać serwer ClickHouse i naprawić wszystko.

Teraz pojawia się pytanie, jak to chroni przed alterami. Tutaj warto spojrzeć głębiej, ponieważ w starych wersjach ClickHouse alter działał w ten sposób, że po prostu bezpośrednio zmieniał fragmenty. Jest fragment danych z jakimiś plikami i robimy na przykład alter drop column. Wtedy ta kolumna jest fizycznie usuwana ze wszystkich fragmentów.

Jednak od wersji 20.3 mechanizm alterów został całkowicie zmieniony i teraz fragmenty danych są zawsze niemutowalne. Nie zmieniają się w ogóle – altery teraz działają podobnie jak merge. Zamiast zmieniać fragment w miejscu, tworzymy nowy. W nowym fragmencie pliki, które się nie zmieniły, stają się hardlinkami, a jeśli usunęliśmy jakąś kolumnę, po prostu nie będzie jej w nowym fragmencie. Stary fragment zostanie usunięty domyślnie po ośmiu minutach, a tutaj można dostosować ustawienia, o których mowa powyżej.

To samo dotyczy alterów typu mutacji. Kiedy robisz alter delete lub alter update, nie zmienia fragmentu, a tworzy nowy. A potem usuwa stary.

Co robić, jeśli struktura tabeli się zmieniła?

Jak przywrócić kopię zapasową, która została wykonana ze starą schemą? I drugie pytanie dotyczące przypadków ze snapshotami i środkami systemu plików. Czy Btrfs nadaje się tutaj zamiast ZFS na Linux LVM?

Jeśli wykonujesz attach partition jeśli masz partycje o innej strukturze, ClickHouse powie ci, że nie można tego zrobić. Rozwiązanie jest następujące. Po pierwsze, utwórz tymczasową tabelę typu MergeTree o starej strukturze, podłącz tam dane przy pomocy attach, a następnie wykonaj zapytanie alter. Potem możesz albo skopiować lub przenieść te dane i ponownie wykonać attach, albo użyć zapytania alter table move partition.

Teraz drugie pytanie - czy można używać Btrfs. Na początek, jeśli masz LVM, wystarczą migawki LVM, a system plików może być ext4, to nie ma znaczenia. W przypadku Btrfs wszystko zależy od twojego doświadczenia w jej eksploatacji. Jest to dojrzały system plików, ale nadal pojawiają się pewne wątpliwości co do tego, jak wszystko zadziała w praktyce w konkretnym scenariuszu. Nie polecałbym tego używać, jeśli nie masz Btrfs w produkcji.

Jakie są obecnie najlepsze praktyki w reshardingu danych?

Pytanie o przeszardowanie jest trudne i wieloaspektowe. Można odpowiedzieć na nie od razu kilkoma wariantami. Można podejść z jednej strony i powiedzieć, że w ClickHouse nie ma wbudowanej możliwości przeszardowania. Ale obawiam się, że ta odpowiedź nikogo nie zadowoli. Dlatego można podejść z drugiej strony i powiedzieć, że w ClickHouse istnieje wiele sposobów przeszardowania danych.

Jeśli kończy się miejsce na klastrze lub nie radzi sobie on z obciążeniem, dodajesz nowe serwery. Ale te serwery są domyślnie puste, nie ma na nich danych, nie ma żadnego obciążenia. Musisz przenieść dane, aby były równomiernie rozłożone na nowym, powiększonym klastrze.

Pierwszy sposób, w jaki można to zrobić, to skopiować część partycji na nowe serwery przy pomocy zapytania alter table fetch partition. Na przykład, jeśli miałeś partycje według miesięcy, bierzesz pierwszy miesiąc 2017 roku i kopiujesz na nowy serwer, potem - trzeci miesiąc kopiujesz na jeszcze inny nowy serwer. I tak robisz, aż stanie się to bardziej lub mniej równomierne.

Przenoszenie można realizować tylko dla tych partycji, które nie zmieniają się podczas zapisu. Dla świeżych partycji zapis będzie musiał być wyłączony, ponieważ ich przeniesienie nie jest atomowe. W przeciwnym razie otrzymasz duplikaty lub pominięcia w danych. Niemniej jednak, ten sposób jest praktyczny i działa dość efektywnie. Po sieci przesyłane są już gotowe skompresowane partycje, to znaczy dane nie są ponownie kompresowane ani dekodowane.

Ten sposób ma jedną wadę, która zależy od schematu shardingu — czy byłeś na niego nastawiony oraz jaki klucz shardingu zastosowałeś. W twoim przykładzie, dla przypadku metryk, kluczem shardingu jest hasz ścieżki. Gdy wykonujesz zapytanie select na Distributed tabeli, trafia ono od razu do wszystkich shardów klastra i pobiera stamtąd dane.

Oznacza to, że de facto nie ma dla ciebie znaczenia, jakie dane znalazły się na którym shardzie. Najważniejsze jest to, że dane po jednej ścieżce znajdują się na jednym shardzie, a który to dokładnie, nie ma znaczenia. W tym przypadku przeniesienie gotowych partycji jest świetnym rozwiązaniem, ponieważ przy zapytaniach select ty także — czy przed przeszardowaniem, czy po, schemat nie ma większego znaczenia — będziesz otrzymywać pełne dane.

Jednak zdarzają się również bardziej złożone przypadki. Jeśli na poziomie logiki aplikacji zakładasz specjalny schemat shardingu, gdzie ten klient znajduje się na tym a tym shardzie, a zapytanie można wysłać od razu tam, a nie do Distributed tabeli. Lub używasz dość nowej wersji ClickHouse i włączyłeś ustawienie optimize skip unused shards. W takim przypadku, podczas zapytania select, wyrażenie w sekcji where zostanie przeanalizowane, a na jakie shardy należy udać się zgodnie z tym schematem shardingu. To działa pod warunkiem, że dane są rozłożone zgodnie z tym schematem shardingu. Jeśli przeniosłeś je ręcznie, dopasowanie może się zmienić.

Tak więc, to sposób numer jeden. Czekam na twoją odpowiedź, czy rozwiązanie jest odpowiednie, czy idziemy dalej.

Włodzimierz Kołobaev, główny administrator systemu w Avito: Alieksiej, sposób, który wspomniałeś, nie najlepiej sprawdza się, gdy trzeba rozłożyć obciążenie także na operacje odczytu. Możemy wziąć partycję miesięczną i przenieść poprzedni miesiąc na inną nodę, ale gdy nadejdzie zapytanie po te dane, obciążymy tylko ją. A chcielibyśmy obciążać cały klaster, ponieważ w przeciwnym razie przez jakiś czas całe obciążenie odczytu będzie obsługiwane przez dwa shardy.

Alieksiej Miłowidow: Odpowiedź tutaj jest dziwna — tak, źle, ale może się udać. Wyjaśnię, jak dokładnie. Należy spojrzeć na scenariusz obciążenia, który towarzyszy Twoim danym. Jeśli są to dane monitoringu, to niemal na pewno można powiedzieć, że przytłaczająca większość zapytań dotyczy świeżych danych.

Postawiłeś nowe serwery, przeniosłeś stare partycje, ale także zmieniłeś sposób zapisywania świeżych danych. A świeże dane będą rozproszone po całym klastrze. W ten sposób już po pięciu minutach zapytania za ostatnie pięć minut będą równomiernie obciążać klaster, po dniu zapytania za całą dobę będą równomiernie obciążać klaster. Niestety zapytania za poprzedni miesiąc trafią tylko na część serwerów klastra.

Jednak często nie będziesz miał zapytań dokładnie za luty 2019 roku. Bardziej prawdopodobne jest, że jeśli zapytania dotyczą roku 2019, to będą za cały 2019 rok — za długi okres czasu, a nie za mały przedział. I takie zapytania również będą mogły równomiernie obciążyć klaster. Ale ogólnie Twoja uwaga jest całkowicie słuszna, że jest to rozwiązanie ad hoc, które nie rozkłada danych całkowicie równomiernie.

Mam jeszcze kilka punktów do odpowiedzi na pytanie. Jeden z nich dotyczy tego, jak początkowo stworzyć schemat shardingu, aby ograniczyć ból związany z przeszacowaniem. Niestety nie zawsze jest to możliwe.

Na przykład, masz dane monitoringu. Dane monitoringu rosną z trzech powodów. Pierwszy – akumulacja danych historycznych. Drugi – wzrost ruchu. A trzeci – zwiększenie liczby rzeczy, które podlegają monitoringowi. Nowe mikroserwisy i metryki, które muszą być przechowywane, pojawiają się na horyzoncie.

Możliwe, że największy wzrost związany jest właśnie z trzecim powodem — to zwiększenie wykorzystania monitoringu. W takim przypadku należy spojrzeć na charakter obciążenia, jakie są główne zapytania na select. Główne zapytania na select prawdopodobnie będą dotyczyć pewnego podzbioru metryk.

Na przykład, wykorzystanie CPU na niektórych serwerach przez niektóre usługi. Okazuje się, że istnieje pewien podzbiór kluczy, według którego te dane są pobierane. A sam zapytanie o te dane jest prawdopodobnie całkiem proste i wykonywane w dziesiątkach milisekund. Używane do usług monitorujących, do pulpitów nawigacyjnych. Mam nadzieję, że dobrze to rozumiem.

Władimir Kołobaew: Chodzi o to, że bardzo często odwołujemy się do danych historycznych, ponieważ w czasie rzeczywistym porównujemy aktualną sytuację z historyczną. I dla nas ważny jest szybki dostęp do dużej ilości danych, a ClickHouse świetnie sobie z tym radzi.

Ma Pan absolutnie rację, większość zapytań o odczyt odczuwamy za ostatni dzień, jak w każdej systemie monitorującym. Ale jednocześnie obciążenie danych historycznych również jest dość duże. Pochodzi głównie z systemu alertów, który co trzydzieści sekund pyta ClickHouse: „Daj mi dane za ostatnie sześć tygodni. A teraz zbuduj mi jakąś średnią ruchomą na ich podstawie i porównaj aktualną wartość z historyczną”.

Chciałbym powiedzieć, że mamy dla takich bardzo świeżych zapytań jeszcze jedną małą tabelkę, w której przechowujemy tylko dwa dni danych, a główne zapytania lecą do niej. Do dużej zshardowanej tabeli wysyłamy tylko duże historyczne zapytania.

Alieksiej Miłowidow: Niestety, dla twojego scenariusza jest to źle zastosowane, ale opowiem o dwóch złych i skomplikowanych schematach shardowania, których nie należy stosować, ale które są wykorzystywane w usłudze moich przyjaciół.

Istnieje główny klaster z wydarzeniami „Yandex.Metrica”. Wydarzenia to wyświetlenia stron, kliknięcia i przejścia. Większość zapytań dotyczy konkretnej witryny. Otwierasz usługę „Yandex.Metrica”, masz stronę — avito.ru, wchodzisz w raport, a zapytanie idzie do twojej strony.

Ale są też inne zapytania — analityczne i globalne, które wykonują wewnętrzni analitycy. Na wszelki wypadek zaznaczam, że wewnętrzni analitycy wykonują zapytania tylko dla usług „Yandexa”. Niemniej jednak, nawet usługi „Yandexa” zajmują znaczną część wszystkich danych. To zapytania nie dotyczące konkretnych liczników, lecz dotyczące szerszej filtracji.

Jak zorganizować dane w taki sposób, aby działały efektywnie zarówno przy jednym liczniku, jak i przy globalnych zapytaniach? Problem polega również na tym, że liczba zapytań w ClickHouse na klastrze „Metryki” wynosi kilka tysięcy na sekundę. Przy tym, złożone zapytania, na przykład kilka tysięcy na sekundę, jeden serwer ClickHouse nie udźwignie.

Rozmiar klastra to ponad sześciuset serwerów. Jeśli na tym klastrze po prostu nałożymy tabelę rozproszoną i wyślemy tam kilka tysięcy zapytań, sytuacja będzie jeszcze gorsza niż wysyłanie ich na jeden serwer. Z drugiej strony odrzucamy opcję, w której dane są równomiernie rozłożone, a my idziemy i zapraszamy ze wszystkich serwerów.

Jest opcja diametralnie przeciwna. Wyobraźcie sobie, jeśli dane będziemy dzielić na shardach według stron, a zapytanie dla jednej strony trafi na jeden shard. Teraz klaster będzie mógł obsłużyć dziesięć tysięcy zapytań na sekundę, ale na jednym sharding zapytanie może działać zbyt wolno. Nie będzie już skalowalne pod względem przepustowości. Szczególnie jeśli to jest strona avito.ru. Nie będzie tajemnicą, jeśli powiem, że Avito to jedna z najbardziej odwiedzanych stron w Rosji. Obsługiwanie jej na jednym sharding byłoby szaleństwem.

Dlatego schemat shardingu jest bardziej skomplikowany. Cały klaster jest podzielony na pewną liczbę mikrklastrów, które nazywamy warstwami. Wewnątrz każdego mikrklastra znajduje się od kilku do kilkudziesięciu shardów. A takich mikrklastrów jest w sumie trzydzieści dziewięć.

Jak to wszystko się skaluje? Liczba mikrklastrów nie zmienia się – jak było kilka lat temu trzydzieści dziewięć, tak i pozostało. Ale wewnątrz każdego z nich stopniowo zwiększamy liczbę shardów w miarę gromadzenia danych. Ogólny schemat shardingu jest taki – podział na te mikrklastry odbywa się według stron internetowych, a aby zrozumieć, która strona znajduje się w którym mikrklastrze, używana jest specjalna baza metadanych w MySQL. Jedna strona – w jednym mikrklastrze. A wewnątrz niego sharding odbywa się według identyfikatorów odwiedzających.

Podczas zapisu dzielimy je według reszty z dzielenia identyfikatora odwiedzającego. Ale przy dodawaniu nowego shardu schemat shardowania się zmienia; nadal dzielimy, ale według reszty z dzielenia przez inną liczbę. Oznacza to, że jeden odwiedzający jest już umiejscowiony na kilku serwerach, co należy mieć na uwadze. Jest to zrobione wyłącznie po to, aby dane lepiej się kompresowały. A podczas zapytań idziemy do tabeli Distributed, która sprawdza klastry i zwraca się do dziesiątek serwerów. Taki jest ten skomplikowany schemat.

Jednak moja opowieść byłaby niepełna, gdybym nie wspomniał, że z tego schematu zrezygnowaliśmy. W nowym schemacie wszystko zmieniliśmy, a wszystkie dane skopiowaliśmy za pomocą clickhouse-copier.

W nowym schemacie wszystkie strony dzielą się na dwie kategorie — duże i małe. Nie wiem, jak tam wybrano próg, ale w rezultacie tak się stało, że duże strony są zapisywane na jeden klaster z 120 shardami, z trzema replikami w każdym — czyli 360 serwerami. I schemat shardowania jest taki, że każde zapytanie idzie od razu do wszystkich shardów. Jeśli teraz w „Yandex.Metrice” otworzysz dowolną stronę raportu dla avito.ru, zapytanie pójdzie na 120 serwerów. Dużych stron w Runet jest mało. I zapytań jest nie tysiąc na sekundę, a nawet mniej niż sto. Wszystko to spokojnie przetwarza tabela Distributed, której każdy z nich obsługuje 120 serwerów.

A drugi klaster — dla małych stron. Tutaj schemat shardowania jest według identyfikatora strony, a każde zapytanie idzie dokładnie na jeden shard.

W ClickHouse istnieje narzędzie clickhouse-copier. Możecie o nim opowiedzieć?

Od razu powiem, że to rozwiązanie jest bardziej skomplikowane i nieco mniej wydajne. Zaleta polega na tym, że rozkłada dane całkowicie zgodnie z tą schematyką, którą wskażesz. Ale wadą narzędzia jest to, że w ogóle nie prowadzi do przeszardowania. Kopiuje dane z jednego schematu klastra do innego schematu klastra.

Oznacza to, że dla jej działania musisz mieć dwa klastry. Mogą znajdować się na tych samych serwerach, ale mimo to dane nie będą przenoszone inkrementalnie, lecz będą skopiowane.

Na przykład, było cztery serwery, a teraz jest osiem. Tworzysz nową tabelę Distributed na wszystkich serwerach, nowe lokalne tabele i uruchamiasz clickhouse-copier, określając w nim schemat działania, który ma odczytać stamtąd, przyjąć nową schemę shardingową i przenieść dane tam. Na starych serwerach potrzebujesz miejsca półtora razy więcej, niż obecnie, ponieważ stare dane muszą na nich pozostać, a na to przyjedzie połowa tych samych starych danych. Jeśli wcześniej pomyślałeś o tym, że dane trzeba przeszardować i miejsce jest dostępne, to taki sposób będzie odpowiedni.

Jak działa clickhouse-copier w środku? Dzieli całą pracę na zestaw zadań do przetworzenia jednej partycji jednej tabeli na jednym shardzie. Wszystkie te zadania mogą być wykonywane równolegle, a clickhouse-copier może być uruchomiony na różnych maszynach w kilku instancjach, ale to, co robi dla jednej partycji, to nic innego jak insert select. Dane są odczytywane, dekompresowane, re-shardowane, a następnie ponownie kompresowane, zapisywane gdzieś, a następnie ponownie sortowane. To jest bardziej złożone rozwiązanie.

Mieliście pilotażową funkcjonalność, która nazywała się resharding. Co z nią?

Miałeś jeszcze w 2017 roku pilotażową rzecz, która nazywała się resharding. Jest nawet opcja w ClickHouse. Rozumiem, że to nie wypaliło. Możesz powiedzieć, dlaczego tak się stało? Wydaje się to bardzo aktualne.

Cały problem polega na tym, że w przypadku konieczności przeszardowania danych na miejscu wymagana jest dość skomplikowana synchronizacja, aby zrobić to atomowo. Kiedy zaczęliśmy patrzeć na to, jak ta synchronizacja działa, stało się jasne, że są fundamentalne problemy. A te fundamentalne problemy nie są tylko teoretyczne, ale od razu zaczęły się ujawniać w praktyce w postaci, którą można wyjaśnić bardzo prosto — nic nie działa.

Czy można połączyć wszystkie części danych w całość przed przeniesieniem na wolne dyski?

Pytanie dotyczące TTL z opcją przeniesienia na wolny dysk w kontekście merge. Czy jest jakiś sposób, oprócz cron, aby zlewać wszystkie części w jedną przed przeniesieniem na wolne dyski?

Odpowiedź na pytanie, czy można w jakiś sposób automatycznie złączyć wszystkie kawałki w jeden przed ich przeniesieniem — nie. Wydaje mi się, że nie ma takiej potrzeby. Można też nie łączyć wszystkich części w jedną, a po prostu zakładać, że będą przenoszone na wolne dyski automatycznie.

Mamy dwa kryteria przenoszenia danych. Pierwsze – w zależności od stopnia zapełnienia. Jeśli na obecnym poziomie magazynu pozostało mniej niż określony procent wolnego miejsca, wybieramy jeden fragment i przenosimy go na wolniejszy magazyn. Właściwie nie na wolniejszy, a na następny – jak to skonfigurujesz.

Drugie kryterium – według rozmiaru. Dotyczy przenoszenia dużych fragmentów. Możesz dostosować próg wolnego miejsca na szybkim dysku, a dane będą przenoszone automatycznie.

Jak przechodzić na nowe wersje ClickHouse, jeśli nie ma możliwości z góry sprawdzić kompatybilności?

Ten temat jest regularnie omawiany na czacie Telegram ClickHouse z uwzględnieniem różnych wersji, i mimo to. Jak bardzo bezpieczne jest aktualizowanie z wersji 19.11 na 19.16 i na przykład z 19.16 na 20.3? Jak najlepiej przechodzić na nowe wersje, nie mając możliwości wcześniejszego sprawdzenia zgodności w środowisku testowym?

Tutaj jest kilka „złotych” zasad. Pierwsza – czytaj changelog. Jest obszerny, ale zawiera oddzielne punkty dotyczące niekompatybilnych zmian. Nie należy traktować tych punktów jako czerwonej flagi. Zwykle są to drobne niekompatybilności, które związane są z pewnymi skrajnymi funkcjonalnościami, które, prawdopodobnie, nie są przez Ciebie używane.

Druga – jeśli nie ma możliwości sprawdzenia zgodności w środowisku testowym, a chcesz zaktualizować się od razu w produkcji, taka jest rekomendacja – nie rób tego. Najpierw stwórz środowisko testowe i sprawdź. Jeśli nie masz środowiska testowego, to prawdopodobnie nie jesteś dużą firmą, więc można skopiować część danych na swój laptop i na nim upewnić się, że wszystko działa poprawnie. Możesz nawet uruchomić kilka replik lokalnie na swoim komputerze. Możesz też gdzieś obok uruchomić nową wersję i załadować tam część danych – to znaczy stworzyć improwizowane środowisko testowe.

Jeszcze jedna zasada – nie aktualizować w ciągu tygodnia po wydaniu wersji z powodu łapania błędów w produkcji i późniejszych szybkich poprawek. Przyjrzyjmy się numeracji wersji ClickHouse, aby się nie zagubić.

Jest wersja 20.3.4. Liczba 20 oznacza rok wydania — 2020. Z punktu widzenia tego, co w środku, nie ma to żadnego znaczenia, więc nie będziemy na to zwracać uwagi. Dalej — 20.3. Drugą cyfrę — w tym przypadku 3 — zwiększamy za każdym razem, gdy wydajemy wersję z jakąś nową funkcjonalnością. Jeśli chcemy dodać jakąś możliwość do ClickHouse, musimy zwiększyć tę liczbę. To znaczy, że w wersji 20.4 ClickHouse będzie działać jeszcze lepiej. Trzecia cyfra — 20.3.4. Tutaj 4 to liczba wydań poprawkowych, w których nie dodawaliśmy nowych możliwości, ale naprawialiśmy jakieś błędy. A 4 oznacza, że zrobiliśmy to cztery razy.

Nie ma co myśleć, że to coś strasznego. Zazwyczaj użytkownik może zainstalować najnowszą wersję, i będzie ona działać bez żadnych problemów przez rok. Ale wyobraźcie sobie, że w jakiejś funkcji do przetwarzania bitmap, która została dodana przez naszych chińskich kolegów, przy przekazywaniu nieprawidłowych argumentów serwer pada. Musimy to naprawić. Wydamy nową wersję poprawkową, a ClickHouse stanie się bardziej stabilny.

Jeśli macie ClickHouse działający w produkcji, a wychodzi nowa wersja ClickHouse z dodatkowymi funkcjami — na przykład 20.4.1 — nie spieszcie się, aby ją wprowadzać do produkcji w pierwszym dniu. Po co ona w ogóle jest potrzebna? Jeśli jeszcze nie korzystacie z ClickHouse, to możecie ją zainstalować i najprawdopodobniej wszystko będzie dobrze. Ale jeśli ClickHouse już stabilnie działa, to śledźcie poprawki i aktualizacje — jakie problemy naprawiamy.

Kirill Shvakov: Chcę dodać kilka słów na temat środowisk testowych. Wszyscy bardzo się boją środowisk testowych i z jakiegoś powodu uważają, że jeśli macie bardzo duży klaster ClickHouse, to i środowisko testowe powinno być nie mniejsze, a przynajmniej dziesięć razy mniejsze. To zdecydowanie nieprawda.

Mogę powiedzieć na swoim przykładzie. Mam projekt, i tam jest ClickHouse. Nasze środowisko testowe właśnie dla niego to mała wirtualna maszyna w Hetzner za dwadzieścia euro, gdzie absolutnie wszystko jest uruchomione. Aby to zrobić, mamy pełną automatyzację w Ansible, więc generalnie nie ma znaczenia, gdzie to uruchamiamy — na fizycznych serwerach czy po prostu na wirtualnych maszynach.

Co można zrobić? Byłoby dobrze dodać do dokumentacji ClickHouse przykład, jak uruchomić mały klaster u siebie – w Dockerze, w LXC, ewentualnie stworzyć playbooka Ansible, ponieważ różni ludzie mają różne wdrożenia. To znacznie ułatwiłoby sprawę. Gdy bierzesz i w pięć minut uruchamiasz klaster, dużo łatwiej jest próbować zrozumieć coś. To znacznie wygodniejsze, ponieważ wprowadzenie do wersji produkcyjnej, której nie sprawdziłeś – to droga donikąd. Czasami to działa, a czasami nie. Dlatego poleganie na sukcesie – to źle.

Maxim Kotyakov, starszy inżynier backendu w Avito: Dodam trochę o środowiskach testowych z serii problemów dużych firm. Mamy pełnoprawny klaster akceptacyjny ClickHouse, który jest dokładną kopią schematów danych i ustawień tego, co jest w produkcji. Ten klaster jest uruchomiony w dość zniszczonych kontenerach z minimalnymi zasobami. Zapisujemy tam pewien procent danych produkcyjnych, na szczęście mamy możliwość replikacji w Kafce. Wszystko jest synchronizowane i skalowane – zarówno pod względem mocy, jak i przepływu, teoretycznie powinno według metryk zachowywać się jak produkcja. Wszystko potencjalnie niebezpieczne jest najpierw uruchamiane na tym stanowisku i przez kilka dni osiąga gotowość. Ale oczywiście, to rozwiązanie jest drogie, ciężkie i wiąże się z niezerowymi kosztami wsparcia.

Alieksiej Miłowidow: Opowiem, jak wygląda środowisko testowe naszych przyjaciół z Yandex.Metrica. Jeden klaster miał ponad 600 serwerów, drugi 360, a jest jeszcze trzeci i kilka klastrów. Środowisko testowe dla jednego z nich – to po prostu dwa shard'y z dwoma replikami w każdym. Dlaczego dwa shardy? Aby nie był tylko jeden. I również, aby były repliki. Po prostu minimalna liczba, którą możemy sobie pozwolić.

To środowisko testowe pozwala sprawdzić, czy zapytania działają i czy nic poważnego się nie zepsuło. Jednak często problemy pojawiają się zupełnie innego charakteru, gdy wszystko działa, ale występują pewne drobne zmiany w obciążeniu.

Podam przykład. Postanowiliśmy zainstalować nową wersję ClickHouse. Została ona umieszczona w środowisku testowym, przeszły zautomatyzowane testy w samej Yandex.Metrice, które porównują dane w starej wersji i nowej, przepuszczając cały proces. I oczywiście, zielone testy naszego CI. W przeciwnym razie nawet nie zaproponowalibyśmy tej wersji.

Wszystko jest w porządku. Zaczynamy wdrażać do produkcji. Otrzymuję wiadomość, że obciążenie na wykresach wzrosło kilka razy. Cofamy wersję. Patrzę na wykres i widzę: obciążenie rzeczywiście wzrosło kilka razy w czasie wdrożenia, a potem zmniejszyło się, gdy wersja została wycofana. Później zaczęliśmy cofać wersję. I obciążenie dokładnie tak samo wzrosło i równie mocno spadło. Tak więc wnioskuję — obciążenie wzrosło w związku z wdrożeniem, nic dziwnego.

Dalej było trudno przekonać kolegów, aby jednak zainstalowali nową wersję. Mówię: „Wszytko w porządku, wdrażajcie. Trzymajcie kciuki, wszystko zadziała. Aktualnie obciążenie wzrosło na wykresach, ale wszystko jest w porządku. Trzymajcie się”. W każdym razie, tak zrobiliśmy, i już — wersja została wdrożona na produkcję. Ale przy prawie każdym wdrożeniu pojawiają się podobne problemy.

Zabijanie zapytań powinno działać, ale nie działa. Dlaczego?

Przyszedł do mnie użytkownik, jakiś analityk, i stworzył pewne zapytanie, które zablokowało mój klaster ClickHouse. Jakąś węzeł lub cały klaster — w zależności od tego, do której repliki lub shardu zapytanie trafiło. Widzę, że wszystkie zasoby CPU na tym serwerze są w użyciu, wszystko czerwone. Jednocześnie sam ClickHouse odpowiada na zapytania. Piszę: „Pokaż mi proszę listę procesów, jakie zapytanie spowodowało to szaleństwo”.

Znalazłem to zapytanie i piszę mu kill. I widzę, że nic się nie dzieje. Mój serwer w użyciu, ClickHouse dalej wydaje mi jakieś polecenia, pokazuje, że serwer żyje, i wszystko jest w porządku. Ale mam degradację we wszystkich zapytaniach użytkowników, zaczyna się degradacja w zapisie do ClickHouse, a moje kill query nie działa. Dlaczego? Myślałem, że kill query powinno zabić zapytania, a to się nie wydarza.

Teraz będzie dość dziwna odpowiedź. Otóż kill query nie zabija zapytań.

Kill query ustawia małą flagę o nazwie „chcę, aby to zapytanie zostało zabite”. A samo zapytanie przy przetwarzaniu każdego bloku sprawdza tę flagę. Jeśli jest ustawiona, zapytanie przestaje działać. Okazuje się, że nikt nie zabija zapytania, ono samo powinno to wszystko sprawdzić i zatrzymać się. I to powinno działać we wszystkich przypadkach, gdy zapytanie znajduje się w stanie przetwarzania bloków danych. Obsłuży następny blok danych, sprawdzi flagę i zatrzyma się.

To nie działa w przypadkach, gdy zapytanie jest zablokowane w jakiejś operacji. Prawdopodobnie nie jest to twój przypadek, ponieważ, jak mówisz, wykorzystuje on mnóstwo zasobów serwera. Może to nie działa w przypadku zewnętrznego sortowania oraz kilku innych szczegółów. Ale ogólnie tak być nie powinno, to jest błąd. A jedyne, co mogę doradzić, to zaktualizować ClickHouse.

Jak obliczyć czas odpowiedzi przy obciążeniu odczytu?

Jest tabela, w której są przechowywane agregaty według item — różne liczniki. Liczba wierszy to około sto milionów. Czy można liczyć na przewidywalny czas odpowiedzi, jeśli wprowadzimy 1K RPS dla 1K itemów?

Sądząc po kontekście, chodzi o obciążenie odczytu, ponieważ problemów podczas zapisu nie ma — można wstawiać tysiące, setki tysięcy, a czasami nawet kilka milionów wierszy.

Zapytania odczytujące mogą być bardzo różne. W select 1 ClickHouse może wykonywać około dziesiątek tysięcy zapytań na sekundę, dlatego nawet zapytania według jednego klucza będą wymagały pewnych zasobów. A takie zapytania punktowe będą trudniejsze niż w jakichkolwiek bazach danych key-value, ponieważ każde odczytanie wymaga przeczytania bloku danych według indeksu. Indeks u nas adresuje nie każdy rekord, a każdy zakres. Oznacza to, że trzeba będzie przeczytać cały zakres — to 8192 wierszy domyślnie. I trzeba będzie rozpakować skompresowany blok danych z 64 Kb do 1 Mb. Zazwyczaj takie zapytania punktowe zajmują od kilku milisekund. Ale to najprostsza opcja.

Spróbujmy zrobić prostą arytmetykę. Jeśli pomnożymy kilka milisekund przez tysiąc, otrzymamy kilka sekund. Jakby nie można było utrzymać tysiąca zapytań na sekundę, ale tak naprawdę można, ponieważ mamy kilka rdzeni procesora. Tak więc, zasadniczo, ClickHouse czasami może wytrzymać 1000 RPS, ale przy krótkich zapytaniach, właśnie punktowych.

Jeśli trzeba skalować klaster ClickHouse pod względem liczby prostych zapytań, to polecam najprostsze — zwiększyć liczbę replik i wysyłać zapytania do losowej repliki. Jeśli jedna replika teoretycznie obsługuje pięćset zapytań na sekundę, co jest całkowicie realne, to trzy repliki będą obsługiwały półtorej tysiąca.

Czasami, oczywiście, można skonfigurować ClickHouse do maksymalnej liczby punktowych odczytów. Co jest do tego potrzebne? Po pierwsze, należy zmniejszyć granularność indeksu. Przy tym nie należy jej zmniejszać do jedności, ale z założeniem, że liczba rekordów w indeksie wyniesie kilka milionów lub dziesiątków milionów na serwerze. Jeśli w tabeli znajduje się sto milionów wierszy, można ustawić granularność na 64.

Można zmniejszyć rozmiar skompresowanego bloku. Do tego są ustawienia min compress block size, max compress block size. Można je zmniejszyć, przeładować dane, a wtedy zapytania punktowe będą szybsze. Jednak ClickHouse nie jest bazą danych typu key-value. Duża liczba małych zapytań to antywzorzec obciążenia.

Kirill Shvakov: Podam radę na wypadek, jeśli tam są zwykłe liczniki. To dość standardowa sytuacja, gdy ClickHouse przechowuje jakiś licznik. Mam użytkownika, jest z takiego kraju, plus jakieś trzecie pole, i trzeba coś inkrementalnie zwiększać. Bierzesz MySQL, robisz unikalny klucz - w MySQL to klucz duplikujący, a w PostgreSQL to konflikt - i dodajesz z plusem. To będzie działać znacznie lepiej.

Kiedy masz niewiele danych, nie ma sensu szczególnie używać ClickHouse. Są zwykłe bazy danych, które dobrze sobie z tym radzą.

Co można dostroić w ClickHouse, aby więcej danych znajdowało się w pamięci podręcznej?

Wyobraźmy sobie sytuację - na serwerach jest 256 GB RAM, w codziennej rutynie ClickHouse zajmuje około 60-80 GB, w szczycie - do 130. Co można włączyć i dostroić, aby więcej danych znajdowało się w pamięci podręcznej, a tym samym zmniejszyła się liczba odwołań do dysku?

Zasypiający bufor strony systemu operacyjnego zazwyczaj dobrze radzi sobie z tym zadaniem. Jeśli otwierasz po prostu top, patrzysz tam na cached lub free - również jest tam napisane, ile jest zakodowane - można zauważyć, że cała wolna pamięć jest wykorzystana pod cache. I te dane przy odczycie będą odczytywane nie z dysku, ale z pamięci operacyjnej. Przy tym mogę powiedzieć, że cache jest wykorzystywane efektywnie, ponieważ przechowywane są właśnie skompresowane dane.

Niemniej jednak, jeśli chcesz jeszcze bardziej przyspieszyć niektóre proste zapytania, istnieje możliwość włączenia wewnętrznego cache w danych rozpakowanych w ClickHouse. Nazywa się to uncompressed cache. W pliku konfiguracyjnym config.xml ustawiasz uncompressed cache size na wartość, która Ci odpowiada — radzę nie więcej niż połowę wolnej pamięci RAM, ponieważ reszta pójdzie na page cache.

Ponadto istnieją dwa ustawienia na poziomie zapytania. Pierwsze ustawienie — use uncompressed cache — włącza jego użycie. Zaleca się, aby było włączone dla wszystkich zapytań, poza ciężkimi, które mogą odczytać wszystkie dane i ten cache wyczyścić. Drugie ustawienie to coś w rodzaju maksymalnej liczby wierszy do wykorzystania w cache. Automatycznie ogranicza duże zapytania, aby były pominięte w cache.

Jak można skonfigurować storage_configuration do przechowywania w pamięci operacyjnej?

W nowej dokumentacji ClickHouse znalazłem sekcję związaną z data storage. W opisie jest przykład z szybkimi SSD.

Ciekawe, jak można skonfigurować to samo z volume hot memory. I jeszcze jedno pytanie. Jak działa select w takiej organizacji danych, czy będzie odczytywał cały zestaw czy tylko ten, który znajduje się na dysku, i czy te dane są kompresowane w pamięci? Jak działa sekcja prewhere w takiej organizacji danych?

To ustawienie ma wpływ na przechowywanie fragmentów danych, a ich format się nie zmienia.
Zobaczmy to bliżej.

Można skonfigurować przechowywanie danych w pamięci operacyjnej. Wszystko, co konfiguruje się dla dysku — to jego ścieżka. Tworzysz podsystem tmpfs, który jest zamontowany pod jakąś ścieżką w systemie plików. Wskazujesz tę ścieżkę jako ścieżkę do przechowywania danych dla samego gorącego podsystemu, gdzie zaczynają trafiać i zapisywać się fragmenty danych, wszystko działa dobrze.

Ale nie polecam tego robić ze względu na niską niezawodność, chociaż jeśli masz minimum trzy repliki w różnych centrach danych, to można. W razie czego dane będą odzyskane. Załóżmy, że serwer nagle wyłączył się i włączył ponownie. Podsystem zamontował się ponownie, ale tam jest pustka. Serwer ClickHouse przy starcie widzi, że te fragmenty są nieobecne, chociaż zgodnie z metadanymi ZooKeeper powinny być. Sprawdza, na których replikach są dostępne, prosi o nie i pobiera. W ten sposób dane będą odzyskane.

W tym sensie przechowywanie danych w pamięci operacyjnej zasadniczo nie różni się od przechowywania ich na dysku, ponieważ podczas zapisu danych na dysk również najpierw trafiają one do cache strony i fizycznie są zapisywane z opóźnieniem. Zależy to od sposobu montowania systemu plików. Ale dla pewności powiem, że ClickHouse nie wykonuje fsync podczas wstawiania.

Dane w pamięci operacyjnej są przechowywane w dokładnie tym samym formacie, co na dysku. Zapytanie select dokładnie w ten sposób wybiera fragmenty, które trzeba czytać, w fragmentach wybiera potrzebne zakresy danych i je odczytuje. A prewhere działa absolutnie tak samo, niezależnie od tego, czy dane były w pamięci operacyjnej, czy na dysku.

Do jakiej liczby unikalnych wartości Low Cardinality jest efektywny?

Low Cardinality jest sprytnie zaprojektowany. Tworzy słowniki danych, ale są one lokalne. Po pierwsze, są to słowniki specyficzne dla każdego fragmentu, po drugie, nawet w obrębie jednego fragmentu mogą być różne dla każdego zakresu. Gdy liczba unikalnych wartości osiąga próg — moim zdaniem, milion — słownik po prostu jest odkładany, a tworzony jest nowy.

Odpowiedź jest następująca: dla każdego lokalnego zakresu — powiedzmy, dla każdego dnia — gdzieś do miliona unikalnych wartości Low Cardinality jest efektywny. Po tym występuje po prostu fallback, w którym używane są różne słowniki, a nie jeden. Będzie działać mniej więcej tak, jak zwykła kolumna typu string, może być nieco mniej efektywnie, ale nie spowoduje to poważnej degradacji wydajności.

Jakie są najlepsze praktyki dotyczące pełnotekstowego wyszukiwania w tabeli z pięcioma miliardami wierszy?

Istnieją różne opcje odpowiedzi. Pierwsza — powiedzieć, że ClickHouse to nie jest system do pełnotekstowego wyszukiwania. Do tego są specjalne systemy na przykład, Elasticsearch i Sphinx. Niemniej jednak, coraz częściej spotykam ludzi, którzy mówią, że przechodzą z Elasticsearch na ClickHouse.

Dlaczego tak się dzieje? Wyjaśniają to tym, że Elasticsearch przestaje radzić sobie z obciążeniem przy niektórych wolumenach danych, zaczynając od kwestii budowy indeksów. Indeksy stają się zbyt rozbudowane, a jeśli po prostu przeniesiemy dane do ClickHouse, okaże się, że są one przechowywane znacznie bardziej efektywnie pod względem objętości. Przy tym zapytania wyszukiwania często nie były takie, że trzeba znaleźć w całej objętości danych jakąś frazę z uwzględnieniem morfologii, a zupełnie inne. Na przykład, znaleźć w ciągu ostatnich kilku godzin w logach według jakiejś podsekwencji bajtów.

W tym przypadku w ClickHouse tworzysz indeks, w którym pierwszym polem będzie data z czasem. Największe odcięcie danych będzie miało miejsce właśnie w zakresie dat. W wybranym zakresie dat zazwyczaj można przeprowadzić pełnotekstowe wyszukiwanie, nawet metodą brute force za pomocą like. Operator like w ClickHouse to najbardziej efektywny operator like, jaki możesz znaleźć. Jeśli znajdziesz lepszy, daj mi znać.

Ale mimo to like to pełne skanowanie. A pełne skanowanie może być wolne nie tylko pod względem CPU, ale także dysku. Jeśli nagle masz jeden terabajt danych dziennie i chcesz znaleźć jakieś słowo, będziesz musiał przeskanować terabajt. A na pewno będzie on na zwykłych dyskach twardych, co w efekcie spowoduje, że nie wejdziesz na ten serwer przez SSH.

W tym przypadku mogę zaproponować jeszcze jeden mały trik. Jest to coś eksperymentalnego - może zadziała, a może nie. W ClickHouse istnieją pełnotekstowe indeksy w postaci trójgramowych filtrów Bloom. Nasi koledzy z firmy Arenadata już przetestowali te indeksy i często działają one zgodnie z przeznaczeniem.

Aby je prawidłowo wykorzystać, należy dobrze zrozumieć, jak dokładnie działają: czym jest trójgramowy filtr Bloom i jak dobrać jego rozmiar. Mogę powiedzieć, że pomogą w zapytaniach dotyczących rzadkich fraz, podciągów, które rzadko występują w danych. W takim przypadku indeksy wybiorą podzakresy i zostanie odczytanych mniej danych.

Niedawno w ClickHouse pojawiły się jeszcze bardziej zaawansowane funkcje dla pełnotekstowego wyszukiwania. Po pierwsze, wyszukiwanie wielu podciągów w jednym przebiegu, w tym opcje z uwzględnieniem wielkości liter, bez uwzględnienia, z obsługą UTF-8 lub tylko dla ASCII. Wybierz najbardziej efektywny, który jest Ci potrzebny.

Pojawiło się również wyszukiwanie kilku wyrażeń regularnych w jednym przebiegu. Nie musisz pisać X like jeden podciąg or X like drugi podciąg. Po prostu piszesz od razu i wszystko jest wykonywane maksymalnie efektywnie.

Trzecie - teraz jest dostępne zbliżone wyszukiwanie wyrażeń regularnych i zbliżone wyszukiwanie podciągów. Jeśli ktoś napisał słowo z literówką, będzie ono wyszukiwane według maksymalnego dopasowania.

Jak najlepiej zorganizować dostęp do ClickHouse dla dużej liczby użytkowników?

Opowiedz, jak najlepiej zorganizować dostęp dla dużej liczby użytkowników i analityków. Jak utworzyć kolejkę, priorytetyzować zapytania maksymalnych zapytań równoległych i jakich narzędzi użyć?

Jeśli klaster jest dość duży, dobrym rozwiązaniem będzie uruchomienie dwóch dodatkowych serwerów, które będą punktem wejścia dla analityków. Oznacza to, że nie należy wpuszczać analityków na konkretne shard'y klastra, a po prostu stworzyć dwa puste serwery, bez danych, i na nich już skonfigurować prawa dostępu. Przy tym, ustawienia użytkowników przy rozproszonych zapytaniach przekazywane są na zdalne serwery. Oznacza to, że konfigurujesz wszystko na tych dwóch serwerach, a ustawienia mają wpływ na cały klaster.

Te serwery są zasadniczo puste, ale ilość pamięci RAM na nich jest bardzo ważna dla wykonywania zapytań. Dysk również może być używany do danych tymczasowych, jeśli włączona jest zewnętrzna agregacja lub sortowanie.

Ważne jest, aby przyjrzeć się ustawieniom związanym ze wszystkimi możliwymi limitami. Jeśli teraz wejdę na klaster "Yandex.Metrica" jako analityk i zadam zapytanie select count from hits, od razu dostanę wyjątek, że nie mogę wykonać zapytania. Maksymalna liczba wierszy, które mogę skanować, to sto miliardów, a na klastrze jest ich pięćdziesiąt trylionów w jednej tabeli. To pierwsze ograniczenie.

Załóżmy, że usunę ograniczenie dotyczące liczby wierszy i ponownie wykonam zapytanie. Wtedy zobaczę następny wyjątek - ustawienie force index by date. Nie mogę wykonać zapytania, jeśli nie określę zakresu dat. Nie należy liczyć na to, że analitycy będą określać go ręcznie. Typowy przypadek - zapisany zakres dat where event date between tydzień. A potem wystarczy źle umieścić nawias, i zamiast and pojawiło się or - or URL match. Jeśli nie ma ograniczeń, zacznie skanować kolumnę URL i straci ogromne ilości zasobów.

Ponadto w ClickHouse są dwa ustawienia priorytetów. Niestety, są one bardzo prymitywne. Jedno nazywa się po prostu priority. Jeśli priority ≠ 0 i są wykonywane zapytania o jakimś priorytecie, ale przy tym wykonywane jest zapytanie o priorytecie, które ma wartość mniejszą, co oznacza wyższy priorytet, to zapytanie o wyższym priorytecie, co oznacza niższy priorytet, po prostu zostaje wstrzymane i w ogóle nie będzie działać w tym czasie.

To bardzo szorstkie ustawienie i nie nadaje się do przypadków, gdy klaster ma stałe obciążenie. Ale jeśli masz krótkie, impulsowe zapytania, które są ważne, a w zasadzie klaster jest bezczynny, takie ustawienie będzie odpowiednie.

Następne ustawienie priorytetów nazywa się priorytet wątku OS. Po prostu ustawia dla wszystkich wątków realizacji zapytania wartość nice dla planisty Linux. Działa z tym trzeba przyznać, tak sobie, ale mimo to działa. Jeśli ustawisz najmniejszą wartość nice - jest ona największa co do wielkości, a więc oznacza najniższy priorytet - a dla zapytań o wysokim priorytecie ustawisz -19, to CPU będzie konsumować niskopriorytetowe zapytania około cztery razy mniej niż zapytania o wysokim priorytecie.

Jeszcze trzeba ustawić maksymalny czas wykonania zapytania - powiedzmy pięć minut. Minimalna prędkość wykonania zapytania - to jest najważniejsze. To ustawienie istnieje od dłuższego czasu i jest wymagane, aby nie tylko twierdzić, że ClickHouse nie zwalnia, ale aby to wymusić.

Wyobraź sobie, że ustalasz: jeśli jakieś zapytanie przetwarza mniej niż milion wierszy na sekundę - tak nie można. To hańbi nasze dobre imię, naszą dobrą bazę danych. Po prostu zakazujemy tego. W rzeczywistości są dwa ustawienia. Jedno nazywa się min execution speed — wiersze na sekundę, a drugie nazywa się timeout before checking min execution speed — domyślnie piętnaście sekund. To znaczy piętnaście sekund można, a potem, jeśli wolno, to po prostu zgłosić wyjątek - przerwać zapytanie.

Jeszcze trzeba ustawić kwoty. W ClickHouse jest wbudowana możliwość kwotowania, która liczy zużycie zasobów. Ale niestety nie zasobów fizycznych typu CPU, dysków, a logicznych - liczbę przetworzonych zapytań, wierszy i przeczytanych bajtów. I można ustawić na przykład maksymalnie sto zapytań w ciągu pięciu minut i tysiąc zapytań na godzinę.

Dlaczego to jest ważne? Ponieważ część zapytań analitycznych będzie wykonywana ręcznie bezpośrednio z klienta ClickHouse. I wszystko będzie dobrze. Ale jeśli w twojej firmie pracują zaawansowani analitycy, napiszą skrypt, a w skrypcie może być błąd. Ten błąd spowoduje, że zapytanie będzie wykonywane w nieskończonej pętli. To jest to, czego należy się bronić.

Czy można przekazać wyniki jednego zapytania dziesięciu klientom?

Mamy kilku użytkowników, którzy lubią przychodzić z bardzo dużymi zapytaniami w tym samym momencie. Zapytanie jest duże, zasadniczo wykonywane szybko, ale z powodu dużej liczby równoczesnych zapytań staje się to bardzo bolesne. Czy można wykonać to samo zapytanie, które przychodzi dziesięć razy z rzędu, tylko raz, a wynik przekazać dziesięciu klientom?

Problem polega na tym, że nie mamy wyników z pamięci podręcznej ani pamięci podręcznej danych pośrednich. Jest pamięć podręczna strony w systemie operacyjnym, która pozwoli uniknąć wielokrotnego odczytu danych z dysku, ale, niestety, dane i tak będą musiały być dekompresowane, deserializowane i przetwarzane ponownie.

Chciałbym w jakiś sposób tego uniknąć, albo cachując dane pośrednie, albo porządkując podobne zapytania w jakąś kolejkę i dodając pamięć podręczną wyników. Obecnie rozwijamy jeden pull request, który dodaje pamięć podręczną zapytań, ale tylko dla podzapytań w sekcji in i join — więc rozwiązanie jest niepełne.

Niemniej jednak, my również mamy taką sytuację. Szczególnie kanoniczny przykład to zapytania ze stronicowaniem. Jest raport, ma kilka stron, a zapytanie brzmi limit 10. Potem to samo, ale limit 10,10. Następnie jeszcze następna strona. I pojawia się pytanie, po co za każdym razem to wszystko obliczamy? Ale obecnie nie ma rozwiązania i nie można tego uniknąć.

Istnieje alternatywne rozwiązanie, które jest ustawiane w trybie sidecar obok ClickHouse — ClickHouse Proxy.

Kirill Shvakov: W ClickHouse Proxy znajduje się wbudowany limiter przepustowości i wbudowana pamięć podręczna wyników. Wiele ustawień zostało zrobionych, ponieważ rozwiązano podobny problem. Proxy pozwala na limitowanie zapytań, organizując je w kolejce, i ustalanie, jak długo żyje pamięć podręczna zapytań. Jeśli zapytania były naprawdę identyczne, Proxy zwróci je wiele razy, a do ClickHouse uda się tylko raz.

W Nginx również jest pamięć podręczna w wersji darmowej, i to także będzie działać. Nginx ma nawet ustawienia, które powodują, że jeśli żądania przychodzą jednocześnie, to spowalnia inne, dopóki jedno nie zostanie zrealizowane. Ale w ClickHouse Proxy konfiguracja jest znacznie lepsza. Została ona stworzona specjalnie dla ClickHouse, pod te konkretne zapytania, dlatego bardziej odpowiada. I jest prosta do zainstalowania.

Jak postępować z operacjami asynchronicznymi i materializowanymi widokami?

Jest taki problem, że operacje z silnikiem replikacji są asynchroniczne – najpierw zapisywane są dane, potem następuje ich scalenie. Jeśli pod tabelą znajduje się materializowana tabela z jakimiś agregatami, to duplikaty zostaną do niej zapisane. I jeśli nie ma jakiejś skomplikowanej logiki, to dane będą zduplikowane. Co można z tym zrobić?

Jest oczywiste rozwiązanie – zrealizować wyzwalacz dla określonej klasy materializowanych widoków przy asynchronicznej operacji scalania. Czy są jakieś „srebrne kule”, plany na wdrożenie podobnych funkcjonalności?

Warto zrozumieć, jak działa deduplikacja. To, o czym teraz opowiem, nie odnosi się do pytania, ale na wszelki wypadek warto o tym przypomnieć.

Podczas wstawiania do replikowanej tabeli dochodzi do deduplikacji całkowicie wstawionych bloków. Jeśli ponownie wstawisz ten sam blok, zawierający taką samą liczbę tych samych wierszy w tej samej kolejności, to dane zostaną zduplikowane. Otrzymasz "Ok" w odpowiedzi na insert, ale faktycznie zostanie zapisana jedna paczka danych i nie będzie ona zduplikowana.

To potrzebne dla pewności. Jeśli podczas wstawiania otrzymałeś "Ok", oznacza to, że twoje dane zostały wstawione. Jeśli otrzymałeś błąd od ClickHouse, oznacza to, że nie zostały wstawione i trzeba powtórzyć wstawienie. Ale jeśli podczas wstawiania połączenie zostało zerwane, to nie wiesz, czy dane zostały wstawione, czy nie. Jedyną opcją jest powtórzenie wstawienia. Jeśli dane faktycznie zostały wstawione i wstawisz je ponownie, mamy deduplikację bloków. Jest ona potrzebna w celu uniknięcia duplikatów.

I ważne jest jeszcze, jak to działa dla materializowanych widoków. Jeśli dane zostały deduplikowane podczas wstawiania do głównej tabeli, to do materializowanego widoku również się nie dostaną.

Teraz, jeśli chodzi o problem. Macie trochę bardziej skomplikowaną sytuację, ponieważ rejestrujecie duplikaty poszczególnych wierszy. To znaczy, że nie cała paczka jest duplikowana, a konkretnie poszczególne wiersze, które w tle się znikają. Rzeczywiście, dane będą zniknąć w głównych tabelach, natomiast do materiałowego przedstawienia wejdą niezniknięte, i podczas scalania nic się z materiałowymi przedstawieniami nie wydarzy. Ponieważ materiałowe przedstawienie to nic innego jak wyzwalacz na insert. Przy innych operacjach nic dodatkowego z nim się nie dzieje.

I tu nie mogę Was pocieszyć. Trzeba tylko szukać konkretnego rozwiązania dla tego przypadku. Na przykład, czy można w materiałowym przedstawieniu również zrobić jego zastąpienie, a sposób deduplikacji może również działać. Ale niestety, nie zawsze. Jeśli jest to agregujące, to się nie uda.

Kirill Shvakov: U nas też w swoim czasie budowano różne patenty. Był problem, że są pokazy reklamy, i są pewne dane, które możemy pokazywać w czasie rzeczywistym – to są po prostu pokazy. Rzadko się dublują, ale jeśli tak się dzieje, potem i tak je znikniemy. I były rzeczy, które nie mogą być dublowane – kliknięcia i cała ta historia. Ale chciało się je pokazać praktycznie od razu.

Jak powstały materiałowe przedstawienia? Były przedstawienia, do których zapisuje się bezpośrednio – zapis do surowych danych, i zapisywane są w widokach. Tam w pewnym momencie dane nie są zbyt poprawne, dublują się i tak dalej. I jest druga część tabeli, gdzie wyglądają absolutnie tak samo, jak materiałowe przedstawienia, to znaczy pod względem struktury są całkowicie identyczne. Co pewien czas przeliczamy dane, uzupełniamy dane bez duplikatów, zapisujemy w te tabele.

Korzystaliśmy z API — w ClickHouse to nie zadziała ręcznie. I API sprawdza: kiedy mam datę ostatniego dodania do tabeli, gdzie gwarantowane są już poprawne dane, obliczone, i wykonuje zapytanie do jednej tabeli i do drugiej tabeli. Z jednej tabeli pobiera do określonego czasu, a z drugiej uzupełnia to, co jeszcze nie zostało obliczone. I to działa, ale nie środkami jednego ClickHouse.

Jeśli masz jakieś API – dla analityków, dla użytkowników – to w zasadzie jest to opcja. Zawsze dokonujesz obliczeń, zawsze przeliczasz. Możesz to robić raz dziennie lub w innym czasie. Sam wybierasz zakres, który nie jest potrzebny i nie jest krytyczny.

ClickHouse ma wiele logów. Jak mogę zobaczyć wszystko, co się dzieje z serwerem w danym momencie?

W ClickHouse jest bardzo dużo różnych logów, a ich liczba rośnie. W nowych wersjach niektóre z nich są włączane domyślnie, a w starych wersjach trzeba je włączyć podczas aktualizacji. Niemniej jednak, jest ich coraz więcej. Chciałbym widzieć na końcu, co teraz dzieje się na moim serwerze, może na jakimś zbiorczym pulpicie.

Czy w Twoim zespole ClickHouse, lub w zespołach Twoich znajomych, są osoby, które wspierają jakiś funkcjonalny, gotowy pulpit, który wyświetlałby te logi w formie już gotowego produktu? W końcu, oglądanie logów w ClickHouse jest świetne. Ale byłoby super, gdyby to już było przygotowane w formie pulpitu. To by mnie ucieszyło.

Pulpity istnieją, chociaż nie są zstandaryzowane. W naszej firmie około 60 zespołów używa ClickHouse, a co dziwne, wiele z nich ma pulpity, które same sobie zrobiły i są nieco inne. Niektóre zespoły korzystają z wewnętrznej instalacji „Yandex.Cloud”. Tam są dostępne niektóre gotowe raporty, chociaż nie wszystkie potrzebne. Inni mają swoje.

Moi koledzy z „Metryki” mają swój pulpit w Grafanie, a ja mam swój na ich klastrze. Obserwuję tam takie rzeczy jak hit cache dla danych z cache'a. A nawet jeszcze trudniejsze jest to, że używamy różnych narzędzi. Mój pulpit stworzyłem na bardzo starym narzędziu, które nazywa się Graphite-web. Jest całkowicie brzydkie. I do dziś się nim posługuję, chociaż Grafana byłaby pewnie wygodniejsza i ładniejsza.

Podstawową rzeczą w pulpitach nawigacyjnych są te same metryki systemowe dotyczące klastra: CPU, pamięć, dysk, sieć. Inne to: liczba jednoczesnych zapytań, liczba jednoczesnych scalen, liczba zapytań na sekundę, maksymalna liczba fragmentów dla partycji tabel MergeTree, opóźnienie replikacji, rozmiar kolejki replikacji, liczba wstawianych wierszy na sekundę, liczba wstawianych bloków na sekundę. To wszystko, co można uzyskać nie z logów, a z metryk.

Władimir Kołobaew: Aleksey, chciałbym nieco to skorygować. Jest Grafana. Grafana ma datasource, którym jest ClickHouse. To znaczy, że mogę z Grafany zadać zapytania bezpośrednio do ClickHouse. W ClickHouse jest tabela z logami, która jest taka sama dla wszystkich. Chcę w rezultacie w Grafanie odwoływać się do tej tabeli logów i widzieć te zapytania, które generuje mój serwer. Byłoby świetnie mieć taki pulpit nawigacyjny.

Samo to wymyśliłem. Ale mam pytanie – jeśli wszystko jest ustandaryzowane, a Grafana jest używana przez wszystkich, dlaczego w „Yandexie” nie ma takiego oficjalnego pulpitu nawigacyjnego?

Kirill Shvakov: W rzeczywistości datasource, który łączy się z ClickHouse, jest obecnie wspierany przez Altinity. Chcę tylko wskazać kierunek, gdzie szukać i kogo popychać. Można ich zapytać, ponieważ „Yandex” w końcu tworzy ClickHouse, a nie historię wokół niego. Altinity to główna firma, która obecnie promuje ClickHouse. Nie porzucą go, a będą go wspierać. Bo zasadniczo, aby załadować pulpit nawigacyjny na stronę Grafany, wystarczy się zarejestrować i go przesłać – nie ma z tym większych problemów.

Alieksiej Miłowidow: W ciągu ostatniego roku w ClickHouse dodano wiele możliwości profilowania zapytań. Istnieją metryki dla każdego zapytania dotyczące wykorzystania zasobów. A całkiem niedawno dodano jeszcze bardziej niskopoziomowy profiler zapytań, aby zobaczyć, gdzie zapytanie spędza każdą milisekundę. Ale aby móc skorzystać z tej funkcjonalności, muszę otworzyć klienta konsolowego i wpisać zapytanie, które ciągle zapominam. Gdzieś je zapisałem i ciągle zapominam, gdzie dokładnie.

Chciałbym mieć narzędzie, które po prostu pokazuje - oto wasze trudne zapytania, pogrupowane według klas zapytań. Klikam na jakieś, a tam informują mnie, że jest trudne z tego powodu. Obecnie nie ma takiego rozwiązania. To rzeczywiście dość dziwne, że gdy ludzie pytają mnie: „Powiedzcie, czy są jakieś gotowe dashboardy dla Grafana?”, odpowiadam: „Wejdźcie na stronę Grafana, tam jest społeczność „Dashboardy”, i tam jest dashboard od Dima, jest dashboard od Kostyana. Co to jest, nie wiem, sam nie korzystałem.”

Jak wpłynąć na merge, aby serwer nie padł z powodu OOM?

Mam tabelę, w tabeli jest tylko jedna partycja, jest to ReplacingMergeTree. Wpisuję w nią dane przez cztery lata. Musiałem w niej wykonać alter i usunąć pewne dane.

Zrobiłem to, a podczas przetwarzania tego zapytania cała pamięć na wszystkich serwerach klastra została wykorzystana i wszystkie serwery klastra padły jednocześnie w OOM. Potem wszystkie razem się podniosły, zaczęły wykonywać merge tej samej operacji, tego bloku danych i znowu padły w OOM. Potem znowu się podniosły i znowu padły. I to nie miało końca.

Potem okazało się, że to był w rzeczywistości błąd, który chłopaki naprawili. To świetnie, dziękuję bardzo. Ale resztka jednak pozostała. I teraz, gdy myślę o tym, by wykonać jakiś merge w tabeli, pojawia się pytanie - dlaczego nie mogę jakoś wpłynąć na te merges? Na przykład, ograniczyć ich pod względem wymaganej pamięci operacyjnej, albo w ogóle według ich ilości, która będzie przetwarzać tę konkretną tabelę.

Mam tabelę, która nazywa się „Metryki”, przetwarzaj ją proszę w dwa strumienie. Nie trzeba tworzyć dziesięciu czy pięciu merge'ów równocześnie, zrób w dwa. Myślę, że w dwa wystarczy mi pamięci, a przetworzenie dziesięciu może okazać się niewystarczające. Dlaczego pozostaje strach? Ponieważ tabela rośnie, i kiedyś zderzę się z sytuacją, w której nie z powodu błędu, a z powodu tego, że dane będą się zmieniać w tak dużej ilości, że po prostu zabraknie pamięci na serwerze. I wtedy serwer zacznie padać w OOM podczas merge. Co więcej, mutację mogę cofnąć, ale merge'ów już nie.

Wiesz, podczas scalania serwer nie padnie z powodu OOM, ponieważ podczas scalania używa się pamięci operacyjnej tylko na jeden mały zakres danych. Tak więc wszystko będzie dobrze niezależnie od objętości danych.

Władimir Kołobaew: Dobrze. Tutaj jest taki moment, że po tym, jak zrobiliśmy poprawkę błędu, pobrałem nową wersję i na innej, mniejszej tabeli, gdzie jest dużo partycji, wykonałem podobną operację. W trakcie scalania na serwerze zużyto około 100 GB pamięci operacyjnej. Miałem zajęte 150 GB, 100 GB zjadło, więc pozostało mi okno na 50 GB, dlatego nie wpadłem w OOM.

Co obecnie chroni mnie przed wpadnięciem w OOM, jeśli on naprawdę zużywa 100 GB pamięci operacyjnej? Co zrobić w sytuacji, gdy nagle pamięć operacyjna podczas scalania się skończy?

Alieksiej Miłowidow: Jest taki problem, że zużycie pamięci operacyjnej podczas scalania nie jest ograniczone. A drugi problem polega na tym, że jeśli jakiekolwiek scalanie zostało zaplanowane, to musi być wykonane, ponieważ jest zapisane w logu replikacji. Log replikacji to te działania, które są potrzebne, aby doprowadzić replikę do spójnego stanu. Jeśli nie przeprowadzi się ręcznych operacji, które cofną ten log replikacji, scalanie będzie musiało zostać wykonane w ten czy inny sposób.

Oczywiście, byłoby dobrze mieć ograniczenie pamięci operacyjnej, które 'na wszelki wypadek' chroniłoby przed OOM. Nie pomoże to w wykonaniu scalania, będzie ono zaczynało się od nowa, dochodziło do jakiegoś progu, rzucało wyjątek, a potem znowu się zaczynało – nic dobrego z tego nie wyniknie. Ale w zasadzie wprowadzenie tego ograniczenia byłoby przydatne.

Jak będzie przebiegać rozwój sterownika Golang dla ClickHouse?

Sterownik Golang, który napisał Kirill Shvakov, teraz oficjalnie wydaje się być wspierany przez zespół ClickHouse. On jest w repozytorium ClickHouse, teraz jest duży i prawdziwy.

Mała uwaga. Jest wspaniałe i przez wszystkich uwielbiane repozytorium normatywnych form nieskończonego porządku – to Vertica. Mają również swój oficjalny sterownik Python, który jest wspierany przez programistów Vertica. I wielokrotnie zdarzało się, że wersje repozytorium i wersje sterownika znacznie się rozjeżdżały, a sterownik w pewnym momencie przestawał działać. I drugi punkt. Wsparcie dla tego oficjalnego sterownika, wydaje mi się, jest prowadzone w systemie „nipple” – piszesz im zgłoszenie, a ono wisi wiecznie.

Mam dwa pytania. Aktualnie sterownik Golang Kirilla to niemal domyślny sposób komunikacji z ClickHouse z Golang. Chyba że ktoś wciąż komunikuje poprzez interfejs http, bo tak mu pasuje. Jak będzie przebiegał rozwój tego sterownika? Czy będzie zsynchronizowany z jakimiś breaking changes w samym repozytorium? I jak wygląda proces rozpatrywania zgłoszeń?

Kirill Shvakov: Pierwsze - jak to wszystko wygląda biurokratycznie. Ten moment nie był omawiany, więc nie mam na to odpowiedzi.

Aby odpowiedzieć na pytanie dotyczące zgłoszeń, potrzebna jest mała historia sterownika. Pracowałem w firmie, w której było dużo danych. Był to reklamowy serwis z ogromną ilością zdarzeń, które trzeba było gdzieś przechowywać. I w pewnym momencie pojawił się ClickHouse. Zaserwowaliśmy tam dane i przez jakiś czas wszystko było dobrze, a potem ClickHouse padł. Wówczas zdecydowaliśmy, że nie jest nam potrzebny.

Rok później wróciliśmy do pomysłu użycia ClickHouse i musieliśmy jakoś pisać tam dane. Warunki były takie - sprzęt bardzo słaby, mało zasobów. Ale zawsze tak pracowaliśmy, więc spojrzeliśmy w stronę protokołu natywnego.

Ponieważ pracowaliśmy na Go, było jasne, że potrzebny jest sterownik na Go. Robiłem go prawie na pełen etat – to było moje zadanie robocze. Do pewnego momentu doprowadziliśmy go do końca i w zasadzie nikt nie spodziewał się, że kto inny go wykorzysta. Potem przyszedł CloudFlare z dokładnie tym samym problemem i przez jakiś czas pracowaliśmy z nimi na równi, ponieważ mieli te same zadania. I robiliśmy to zarówno w ClickHouse, jak i w sterowniku.

W pewnym momencie po prostu przestałem się tym zajmować, ponieważ moja aktywność w kontekście ClickHouse i pracy trochę się zmieniła. Dlatego problemy nie są zamykane. Okazjonalnie do repozytorium wysyłają zmiany ludzie, którzy sami czegoś potrzebują. Wtedy przeglądam pull request i czasami nawet coś sam poprawiam, ale zdarza się to rzadko.

Chciałbym wrócić do sterownika. Kilka lat temu, gdy to wszystko się zaczynało, ClickHouse był inny i miał inne możliwości. Teraz rozumiemy, jak przebudować sterownik, aby był lepszy. Jeśli to się wydarzy, wersja 2 będzie na pewno niekompatybilna z powodu nagromadzonych „kuleczek”.

Nie wiem, jak to zorganizować. Sam mam niewiele czasu. Jeśli jakaś grupa ludzi zajmie się poprawkami w sterowniku, mogę im pomóc i wyjaśnić, co robić. Ale aktywne uczestnictwo „Yandexu” w rozwoju projektu nie było jeszcze omawiane.

Alieksiej Miłowidow: Na razie nie ma żadnej biurokracji dotyczącej tych sterowników. Jedyne czego się doczekaliśmy, to że zostały one przeniesione do oficjalnej organizacji, więc ten sterownik uznawany jest za oficjalne rozwiązanie domyślne dla Go. Istnieją inne sterowniki, ale działają osobno.

W naszej organizacji nie ma pracy nad tymi sterownikami. Pytanie brzmi, czy uda nam się zatrudnić kogoś do pracy nad wszystkimi sterownikami społecznościowymi, czy znajdziemy kogoś na zewnątrz.

Zewnętrzny słownik nie podnosi się po restartowaniu przy włączonej opcji lazy_load. Co zrobić?

Mamy włączoną opcję lazy_load i po ponownym uruchomieniu serwera słownik sam się nie ładuje. Ładuje się dopiero po tym, jak użytkownik zwróci się do tego słownika. A przy pierwszym odwołaniu zwraca błąd. Czy można jakoś automatycznie za pomocą ClickHouse ładować słowniki, czy zawsze musimy kontrolować ich gotowość, aby użytkownicy nie dostawali błędów?

Może mamy starszą wersję ClickHouse, przez co słownik nie ładował się automatycznie. Czy to możliwe?

Po pierwsze, słowniki można wymusić do załadowania za pomocą zapytania system reload dictionaries. Po drugie, co do błędu — jeśli słownik już został załadowany, zapytania będą działać na tych danych, które zostały załadowane. Jeśli słownik jeszcze nie był załadowany, to będzie ładowany bezpośrednio w trakcie zapytania.

Dla ciężkich słowników to nie jest zbyt wygodne. Na przykład, jeśli trzeba wydobyć milion wierszy z MySQL. Ktoś może wykonać proste zapytanie select, ale to zapytanie będzie czekać na te milion wierszy. Istnieją dwa rozwiązania. Pierwsze - wyłączyć lazy_load. Drugie - gdy serwer się uruchamia, przed obciążeniem go, wykonać system reload dictionary lub po prostu wykonać zapytanie, które korzysta ze słownika. Wtedy słownik zostanie załadowany. Należy samodzielnie kontrolować dostępność słowników przy włączonej opcji lazy_load, ponieważ ClickHouse automatycznie ich nie pobiera.

Na ostatnie pytanie odpowiedź brzmi - albo wersja jest stara, albo trzeba debugować.

Co zrobić w sytuacji, gdy system ładowania słowników nie wczytuje żadnego z licznych słowników, gdy chociaż jeden z nich zwraca błąd?

Jest jeszcze pytanie dotyczące system reload dictionaries. Mamy dwa słowniki - jeden się nie ładuje, drugi się ładuje. W takim przypadku system reload dictionaries nie załadowuje żadnego słownika i trzeba ładować konkretnego po nazwie za pomocą system reload dictionary. Czy to również jest związane z wersją ClickHouse?

Chcę was pocieszyć. To zachowanie się zmieniało. Oznacza to, że jeśli zaktualizujesz ClickHouse, to również się to zmieni. Jeśli nie odpowiada ci obecne zachowanie system reload dictionaries, zaktualizuj się i miejmy nadzieję, że zmieni się na lepsze.

Czy istnieje sposób na konfigurowanie danych uwierzytelniających w konfiguracji ClickHouse, ale bez ujawniania ich w przypadku błędów?

Następne pytanie dotyczy błędów związanych ze słownikiem, a mianowicie danych połączenia. Zdefiniowaliśmy dane połączenia w konfiguracji ClickHouse dla słownika i w przypadku błędu te dane i hasło otrzymujemy w odpowiedzi.

Rozwiązaliśmy ten błąd przenosząc dane połączenia do konfiguracji sterownika ODBC. Czy istnieje jakiś sposób, aby skonfigurować te dane w konfiguracji ClickHouse, ale nie ujawniać ich w przypadku błędów?

Tutaj rzeczywistym rozwiązaniem jest wskazanie tych credentials w odbc.ini, a w samym ClickHouse wskazanie tylko ODBC Data Source Name. Dla pozostałych źródeł słowników tak nie będzie - ani dla słownika z MySQL, ani dla pozostałych nie powinieneś widzieć hasła w wiadomości o błędzie. Również sprawdzę ODBC — jeśli coś takiego istnieje, po prostu trzeba to usunąć.

Bonus: tła do Zooma z spotkań.

Klikając na obrazek, dla najbardziej wytrwałych czytelników otworzą się bonusowe tła z posiedzeń. Gasić pożar razem z maskotkami technologii Avito, naradzać się z kolegami z pokoju administratora systemu lub starego klubu komputerowego i prowadzić daily pod mostem na tle graffiti.

ClickHouse dla zaawansowanych użytkowników w pytaniach i odpowiedziach

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster