ClickHouse за напреднали потребители в въпроси и отговори

През април инженьорите на Авито заседаваха на онлайн-срещи с главния разработчик на ClickHouse Алексей Миловидов и Кирил Шваков, разработчик на Golang от компания Integros. Обсъдиха как използваме системата за управление на бази данни и какви трудности срещаме.

В резултат на срещата събрахме статия с отговори на експертите на нашите и зрителски въпроси за бекъпи, решардиране на данни, външни речници, Golang-драйвер и обновяване на версиите на ClickHouse. Тя може да бъде полезна за разработчици, които вече активно работят с СУБД на Яндекс и се интересуват от нейното настояще и бъдеще. По подразбиране отговорите са на Алексей Миловидов, освен ако не е написано друго.

Внимание, под кат има много текст. Надяваме се, че съдържанието с въпросите ще ви помогне да се ориентирате.

ClickHouse за напреднали потребители в въпроси и отговори

Съдържание

Ако не искате да четете текста, можете да гледате записа от сбирките на нашия YouTube канал. Тайм кодовете са в първия коментар под видеото.

ClickHouse постоянно се обновява, а нашите данни не. Какво да правим по този въпрос?

ClickHouse постоянно се обновява, а нашите данни, които бяха оптимизирани, не се обновяват и остават в резервно копие.

Да предположим, че сме имали някакъв проблем и данните са били загубени. Решихме да се възстановим и се оказа, че старите партиции, които са на съхранение в бекъп сървърите, значително се различават от версията на ClickHouse, която в момента използваме. Какво да правим в такъв случай и възможно ли е това?

Ситуацията, при която сте възстановили от бекъп данните в стар формат, а новата версия не ги разпознава, не е възможна. Ние следим, за да гарантираме, че форматът на данните в ClickHouse винаги остава обратно съвместим. Това е много по-важно от обратно съвместимостта на функционалността, ако поведението на някоя рядко използвана функция е променено. Данните, които се съхраняват на диска, новата версия на ClickHouse винаги трябва да може да чете. Това е закон.

Какви са най-добрите практики в момента за резервно копиране на данни от ClickHouse?

Как да правим резервни копия, като вземем предвид, че имаме операции optimize final, огромна база данни на терабайти и данни, които се обновяват, да предположим, през последните три дни, и след това с тях не се извършват никакви процедури?

Можем да разработим собствено решение и да напишем на баша: събирай тези резервни копия. Може би, не е нужно да измисляме колелото отново и то вече е изобретено?

Първо относно най-добрите практики. Мои колеги винаги съветват в отговор на въпроси относно бекъпите да напомнят за услугата „Яндекс.Облако“, където този проблем вече е решен. Така че я използвайте, ако имате такава възможност.

Няма пълно решение, на сто процента интегрирано в ClickHouse, за бекъпи. Има някои шаблони, които могат да се използват. За да получите пълно решение, ще трябва или да поработите малко ръчно, или да направите обвивки под формата на скриптове.

Ще започна с най-простите решения и ще завърша с най-сложните в зависимост от обема на данните и размера на клъстера. Колкото по-голям е клъстерът – толкова по-сложно става решението.

Ако таблицата с данни заема само няколко гигабайта, бекъпът може да се направи така:

  1. Запазете определението на таблиците, тоест метаданните – show create table.
  2. Направете дамп с помощта на клиента на ClickHouse – select * от таблицата в файл. По подразбиране ще получите файл в формат TabSeparated. Ако искате по-ефективно – може да е в формат Native.

Ако обемът на данните е по-голям, тогава бекъпът ще отнеме повече време и много място. Това се нарича логически бекъп, той не е свързан с формата на данните в ClickHouse. Ако такъв съществува, в краен случай можете да вземете бекъп и да го заредите в MySQL за възстановяване.

За по-напреднали случаи в ClickHouse е вградена възможността да се създаде снапшот на партиции в локалната файлова система. Тази възможност е налична под формата на заявка alter table freeze partition. Или просто alter table freeze — това е снапшот на цялата таблица.

Снапшотът ще бъде създаден консистентен за една таблица на един шард, т.е. създаването на консистентен снапшот на целия клъстер по този начин е невъзможно. Но за повечето задачи такава необходимост няма, и е достатъчно на всеки шард да изпълните заявката и да получите консистентен снапшот. Той се създава под формата на хардлинкове и затова не заема допълнително място. След това копирате този снапшот на бекъп-сървър или в хранилище, което използвате за бекъпи.

Възстановяването на такъв бекъп е достатъчно лесно. Първо – създавате таблиците по наличните определения. След това копирате запазените снапшоти на партициите в Directory-Detached за данните от таблиците и изпълнявате заявка attach partition. Такова решение е напълно подходящо за най-сериозните обеми данни.

Понякога е нужно нещо още по-впечатляващо – в случаите, когато имате десетки или дори стотици терабайти на всеки сървър и стотици сървъри. Има решение, което разгледах при колегите от «Яндекс.Метрики». Не бих го препоръчал на всеки – прочетете и сами преценете, дали е подходящо за вас или не.

Първо трябва да създадете няколко сървъра с големи дискови полки. След това да инсталирате няколко ClickHouse сървъра на тези сървъри и да ги настроите да работят като още една реплика за същите шардове. А след това да използвате файловата система на тези сървъри или някакъв инструмент, който позволява създаване на снимки. Има два варианта. Първият вариант е LVM снимки, вторият вариант е ZFS на Linux.

След това всеки ден трябва да създавате снимка, която ще заема известно място. Естествено, ако данните се променят, с времето обемът ще се увеличава. Тази снимка може да бъде възстановена по всяко време, такова странно решение. Освен това, трябва да ограничите тези реплики в конфигурацията, за да не се опитват да станат лидери.

Може ли да се организира контролирано забавяне на репликите в валовете?

Тази година планирате да правите валове в ClickHouse. Ще бъде ли възможно в тях да организирате контролирано забавяне на репликите? Искаме да се защитим от негативни сценарии с алтери и други промени.

Възможно ли е да се направят някакви възстановявания за алтерите? Например, в съществуващ вал да кажем, че до този момент прилагайте изменения, а от този момент нататък да не прилагате изменения?

Ако в нашия кластер дойде команда и го повреди, имаме условна реплика с едночасово забавяне, където можем да решим, че именно нея ще използваме в момента, но последните десет минути изменения в нея да не ги прилагаме?

Първо, за контролираното забавяне на репликите. Имаше запитване от потребителите и създадохме задача в GitHub с молба: „Ако на някого това му е необходимо, дайте лайк, дайте сърце“. Никой не постави, и задачата беше затворена. Все пак, вече е възможно да се получи такава възможност, настройвайки ClickHouse. Вярно, само от версия 20.3.

ClickHouse постоянно в фоновом режиме выполняет слияние данных — мердж. Когда мердж завершен, определенный набор фрагментов данных заменяется на более крупный фрагмент. При этом старые фрагменты данных остаются на диске в течение определенного времени.

Во-первых, они продолжают храниться до тех пор, пока существуют запросы select, которые их используют, чтобы обеспечить неблокирующую работу. Запросы select могут спокойно читать старые фрагменты.

Во-вторых, есть также временной порог — старые фрагменты данных хранятся на диске восемь минут. Этот период можно настроить и увеличить до одного дня. Это займет место на диске: в зависимости от потока данных может получится так, что за последний день данные не удвоятся, их количество может увеличиться в пять раз. Но при серьезной проблеме вы сможете остановить сервер ClickHouse и разобраться с ситуацией.

Теперь возникает вопрос, как это защищает от альтеров. Здесь стоит посмотреть глубже, потому что в старых версиях ClickHouse альтер работал так, что просто непосредственно менял фрагменты. Существовал фрагмент данных с некоторыми файлами, и мы делали, например, alter drop column. Тогда этот столбец физически удалялся из всех фрагментов.

Но начиная с версии 20.3, механизм альтеров был полностью изменен, и теперь фрагменты данных всегда иммутабельные. Они не изменяются вообще — альтеры теперь работают примерно так же, как мерджи. Вместо того, чтобы менять фрагмент на месте, мы создаем новый. В новом фрагменте файлы, которые не изменились, становятся хардлинками, и если мы удаляем какой-то столбец, он просто не будет присутствовать в новом фрагменте. Старый фрагмент будет удален по умолчанию через восемь минут, и здесь можно настроить параметры, о которых упоминается выше.

То же самое касается альтеров типа мутаций. Когда вы делаете alter delete или alter update, он не изменяет фрагмент, а создает новый. А затем удаляет старый.

Какво да правим, ако структурата на таблицата се е променила?

Как восстановить бэкап, который был сделан со старой схемой? И второй вопрос о кейсе со снапшотами и средствами файловой системы. Подойдет ли здесь Btrfs вместо ZFS на Linux LVM?

Если вы делаете attach partition Ако имате партиции с друга структура, ClickHouse ще ви каже, че не може да стане. Решението е следното. Първото - създайте времена таблица от тип MergeTree със старата структура, прикачете данните с помощта на attach, направете запитване alter. След това можете или да копирате, или да прехвърлите тези данни и да направите attach отново, или да използвате запитване alter table move partition.

Сега вторият въпрос - може ли да се използва Btrfs. Първо, ако имате LVM, достатъчни са LVM снимки, а файловата система може да бъде и ext4, не е от значение. С Btrfs всичко зависи от вашия опит с него. Това е зряла файловата система, но все пак има определени съмнения относно това как всичко ще работи на практика в конкретен сценарий. Не бих препоръчал да го използвате, ако нямате Btrfs в продукция.

Какви са най-добрите практики в решардирането на данни в момента?

Въпросът за пре-шардването е сложен и многогранен. Може да отговорим веднага с няколко варианта. Можете да подойдете от едната страна и да кажете така - в ClickHouse няма вградена възможност за пре-шардване. Но се страхувам, че този отговор няма да удовлетвори никого. Затова можем да подходим от другата страна и да кажем, че в ClickHouse има много начини за пре-шардване на данни.

Ако свършва мястото в клъстера или той не се справя с натоварването, добавяте нови сървъри. Но тези сървъри по подразбиране са празни, нямат данни, няма натоварване. Трябва да прехвърлите данни, за да станат равномерно разпределени по новия, увеличен размер клъстер.

Първият начин, по който може да стане, е да копирате част от партициите на новите сървъри с помощта на запитване alter table fetch partition. Например, ако имате партиции по месеци, взимате първия месец на 2017 година и го копирате на нов сървър, след това - третия месец копирате на друг нов сървър. И така правите, докато не стане по-равномерно.

Прехвърлянето може да се извърши само за тези парции, които не се променят при запис. За свежите парции записът трябва да бъде изключен, защото прехвърлянето им не е атомарно. В противен случай ще получите дубликати или пропуски в данните. Въпреки това, този метод е практичен и работи доста ефективно. По мрежата се предават вече готови компресирани парции, а данните не се компресират и не се прекодират.

Този метод има един недостатък, който зависи от схемата на шардове, дали сте заложили на тази схема и какъв ключ на шардове имате. В примера ви за случая с метрики, ключът на шардове е хеш от пътя. Когато правите select в Distributed таблица, той отива веднага на всички шардове на кластера и взима данни оттам.

Това означава, че всъщност за вас не е важно какви данни са на кой шард. Важното е, че данните по един и същ път са на един шард, а на кой точно, не е от значение. В този случай, преносът на готови партиции е отлично решение, защото при select запитванията също — както преди преразпределянето, така и след него, схемата на данните няма да играе съществена роля — ще получавате пълни данни.

Има обаче и по-сложни случаи. Ако на ниво логика на приложението залагате на специална схема на шардове, при която този клиент е разположен на определен шард и запитването може да бъде изпратено директно там, а не в Distributed таблица. Или използвате сравнително нова версия на ClickHouse и сте включили настройката optimize skip unused shards. В този случай, по време на select запитването, изразът в секцията where ще бъде анализиран и ще бъде изчислено на кои шардове е нужно да отидете според схемата на шардове. Това работи при условие, че данните са разположени именно според тази схема на шардове. Ако сте ги пренаредили ръчно, съответствието може да се промени.

Така че, това е първият метод. Очаквам вашия отговор, дали методът е подходящ или продължаваме напред.

Владимир Колобаев, главен системен администратор в Авито: Алексей, методът, който споменахте, не е много подходящ, когато е необходимо да се разпредели натоварването, включително и при четене. Можем да вземем партиция, която е месечна, и можем да преместим предшестващия месец на друга нода, но когато пристигне запитването за тези данни, ще натоварим само нея. А искаме да натоварим целия клъстер, защото в противен случай за известно време цялото натоварване на четене ще се обработва от два шарда.

Алексей Миловидов: Отговорът тук е странен — да, зле е, но може и да сработи. Ще обясня как точно. Трябва да се разгледа сценарият на натоварването, който следва вашите данни. Ако става въпрос за данни от мониторинг, то почти със сигурност може да се каже, че огромното мнозинство от заявките са за свежи данни.

Вие сте инсталирали нови сървъри, пренесли сте стари партиции, но също сте променили начина, по който се записват свежите данни. Свежите данни ще бъдат разпръснати по целия кластер. Така, след само пет минути, заявките за последните пет минути ще натоварят равномерно кластера, след ден заявките за едно денонощие ще натоварят равномерно кластера. За съжаление, заявките за предходния месец ще отидат само на част от сървърите на кластера.

Но често няма да имате заявки именно за февруари 2019 година. По-скоро, ако има заявки за 2019 година, те ще са за цялата 2019 година — за голям времеви интервал, а не за някакъв малък диапазон. И такива заявки също ще могат да натоварят кластера равномерно. Но като цяло вашето наблюдение е напълно вярно, че това е ad hoc решение, което не разпръсква данните напълно равномерно.

Имам още няколко точки за отговор на въпроса. Една от тях е как първоначално да се направи схема на шардинг така, че от преработването на шардовете да има по-малко болка. Това не винаги е възможно.

Например, имате данни от мониторинг. Данните от мониторинга нарастват по три причини. Първата е натрупването на исторически данни. Втората е растежът на трафика. Третата е увеличаването на броя на нещата, които попадат под мониторинг. Появяват се нови микросервиси и метрики, които трябва да се запазят.

Възможно е, че най-голямото нарастване е свързано именно с третата причина — увеличеното използване на мониторинга. В този случай трябва да се разгледа характерът на натоварването, какви са основните заявки за select. Основните заявки за select вероятно ще идват от някакво подмножество метрики.

Например, използването на CPU на някои сървъри от определени услуги. Става така, че има известно подмножество ключове, по които извличате тези данни. И самият запит за тези данни вероятно е доста прост и се изпълнява за десетки милисекунди. Използва се за мониторингови услуги и табла с данни. Надявам се, че разбирам правилно.

Владимир Колобаев: Става въпрос, че много често се позоваваме на исторически данни, тъй като в реално време сравняваме текущото положение с историческото. За нас е важно да имаме бърз достъп до голям обем данни, а ClickHouse се справя отлично с това.

Напълно сте прави, повечето заявки за четене получаваме за последния ден, както и всяка мониторингова система. Въпреки това, натоварването по историческите данни също е значително. То идва основно от системата за алертиране, която на всеки тридесет секунди пита ClickHouse: „Дай ми данните за последните шест седмици. А сега да ми построиш някаква скользяща средна и да сравним текущата стойност с историческата“.

Искам да кажа, че за такива много свежи запитвания имаме още една малка таблица, в която съ храним данни само за два дни, а основните заявки отиват там. В голямата шардизирана таблица изпращаме само големи исторически запитвания.

Алексей Миловидов: За съжаление, за вашия сценарий отидава неприложимо, но ще ви разкажа за две лоши и сложни схеми на шардизиране, които не трябва да използвате, но които се използват в услугата на моите приятели.

Има основен клъстер с събития от „Яндекс.Метрика“. Събитията включват прегледи на страници, кликове и преходи. Повечето запитвания са насочени към конкретен уебсайт. Вие отваряте услугата „Яндекс.Метрика“, имате сайт — avito.ru, влизате в отчета и става запитване по вашия сайт.

Но има и други запитвания — аналитични и глобални, които правят вътрешните анализатори. За всеки случай ще отбележа, че вътрешните анализатори правят запитвания само по услугите на „Яндекс“. Но въпреки това, дори услугите на „Яндекс“ заемат значителна част от всички данни. Това са запитвания не по конкретни счетоводители, а по по-широка филтрация.

Как да организираме данните така, че да работят ефективно както за един счетчик, така и за глобални заявки? Сложността произлиза и от факта, че броят на заявките в ClickHouse на кластера "Метрики" е няколко хиляди в секунда. При това не тривиални заявки, например, един сървър ClickHouse не може да понесе няколко хиляди в секунда.

Размерът на кластера е около шестстотин сървъра. Ако просто наложим Distributed таблица над този кластер и изпращаме няколко хиляди заявки, ситуацията ще стане още по-лоша, отколкото да ги изпращаме на един сървър. От друга страна, опцията, при която данните са равномерно разпределени и ние правим заявки от всички сървъри, веднага отпада.

Има диаметрално противоположна опция. Представете си, че ще шардим данните по сайтове, и заявката за един сайт ще отиде на един шард. Сега кластерът спокойно ще може да понесе десет хиляди заявки в секунда, но на един шард някоя единствена заявка ще работи твърде бавно. Не ще може да се мащабира по пропускна способност. Особено ако това е сайтът avito.ru. Няма да ви разкрия тайна, ако кажа, че Авито е един от най-посещаваните сайтове в рунета. И обработването му на един шард би било безумие.

Затова схемата на шардите е устроена по по-умен начин. Целият кластер е разделен на определен брой кластерчета, които наричаме слоеве. Вътре в всяко кластерче има от десет до няколко десетки шарда. И общо такива кластерчета има тридесет и девет.

Как всичко това се мащабира? Броят на кластерчетата не се променя - както беше преди няколко години тридесет и девет, така и е останало. Но вътре в тях постепенно увеличаваме броя на шардовете с натрупването на данни. И схемата на шардите като цяло е такава - разпределението на тези кластерчета става по уебсайтове, и за да разберем кой сайт е на кой кластер, се използва изцяло отделна метабаза в MySQL. Един сайт - на едно кластерче. А вътре в него шардовете са принципно по идентификационни номера на посетителите.

При записване ги разделяме по остатъка от деление на идентификатора на посетителя. Но при добавяне на нов шард схемата на шардовете се променя, продължаваме да разделяме, но по остатъка от делението на друго число. Това означава, че един посетител вече е разположен на няколко сървъра и не можем да разчитаме на това. Това е направено изключително за по-добро компресиране на данните. А при заявки отиваме в Distributed таблицата, която гледа на кластера и се обръща към десетки сървъри. Тази глупава схема.

Но разказът ми ще бъде непълен, ако не кажа, че се отказахме от тази схема. В новата схема всичко променихме и всички данни копирахме с помощта на clickhouse-copier.

В новата схема всички сайтове се делят на две категории - големи и малки. Не знам как е избран прагът, но в резултат се оказа, че големите сайтове се записват на един кластер, където има 120 шарда с по три реплики във всеки - тоест 360 сървъра. И схемата на шардовете е такава, че всяка заявка отива веднага на всички шардове. Ако сега в "Яндекс.Метрике" отворите която и да е страница от отчета за avito.ru, заявката ще отиде на 120 сървъра. Големите сайтове в рунета са малко. И заявките не са хиляда в секунда, а дори по-малко от сто. Всичко това спокойно се обработва от Distributed таблицата, която всеки от тях обработва с 120 сървъра.

А вторият кластер е за малките сайтове. Тук схемата на шардовете е по идентификатора на сайта, и всяка заявка отива точно на един шард.

В ClickHouse има утилита clickhouse-copier. Можете ли да разкажете за нея?

Веднага ще кажа, че това решение е по-обемно и малко по-малко продуктивно. Предимството е, че напълно разпределя данните съгласно схемата, която посочите. Но недостатъкът на утилитата е, че тя изобщо не прави перешардиране. Тя копира данните от една схема на клъстера в друга схема на клъстера.

Това означава, че за нейната работа трябва да имате два клъстера. Те могат да се намират на еднакви сървъри, но въпреки това данните няма да се преместят инкрементално, а ще бъдат копирани.

Например, имаше четири сървъра, стана осем. Създавате нова разпределена таблица на всички сървъри, нови локални таблици и стартирате clickhouse-copier, указвайки в него схемата на работа, че той трябва да чете оттам, да приеме новата схема на шардирование и да прехвърли данните там. И на старите сървъри ще ви е нужно пространство с половин повече от това, което имате в момента, тъй като старите данни трябва да останат там, а освен това ще получат половина от същите стари данни. Ако предварително сте помислили за това, че данните трябва да бъдат пререплатени и има място, то такъв метод ще е подходящ.

Как е организиран clickhouse-copier вътре? Той разделя цялата работа на набор от задачи за обработка на една партиция на една таблица на един шард. Всички тези задачи могат да се изпълняват паралелно и clickhouse-copier може да бъде стартиран на различни машини в няколко инстанции, но това, което той прави за една партиция, е не нищо друго освен insert select. Данните се четат, разопаковат, преразпределят, след това отново се опаковат, записват на някъде, пренареждат. Това е по-тежко решение.

Имахте пилотен проект, който се наричаше решардинг. Какво стана с него?

Имахте още през 2017 година пилотен проект, наречен решардинг. Има дори опция в ClickHouse. Разбирам, че това не се получи. Можете ли да разкажете защо така се е случило? Изглеждаше много актуално.

Цялата проблема е, че при необходимостта от пререплатиране на данните на място е нужна доста сложна синхронизация, за да се направи това атомарно. Когато започнахме да изследваме как е организирана тази синхронизация, стана ясно, че има основни проблеми. И тези основни проблеми не са само теоретични, а веднага започват да се проявяват и на практика, което може да се обясни много просто – нищо не работи.

Може ли да се слеят всички части на данните преди преместването им на бавни дискове?

Въпрос относно TTL с опцията move to slow disk в контекста на мердж искам да знам. Има ли начин, извън cron, да се съединят всички части в една преди преминаването на бавните дискове?

Отговор на въпроса, дали е възможно автоматично да се съединят всички парчета в едно преди тяхното преместване – не. Мисля, че в това няма необходимост. Може и да не се съединяват всички части в една, а просто да се разчита на това, че те автоматично ще бъдат пренесени на бавните дискове.

Имаме два критерия за прехвърляне. Първият е по мярка за запълване. Ако на текущото ниво на хранилището има по-малко от определен процент свободно пространство, избираме една част и я прехвърляме на по-бавно хранилище. По-точно, не по-бавно, а следващото — както сте настроили.

Вторият критерий е по размер. Той касае прехвърлянето на големи парчета. Можете да настроите прага за свободно място на бързия диск, и данните ще се прехвърлят автоматично.

Как да преминем към нови версии на ClickHouse, ако нямаме възможност предварително да проверим съвместимостта?

Тази тема редовно се обсъжда в телеграм чата ClickHouse с оглед на различни версии, и все пак. Насколько е безопасно да се обновите от версия 19.11 на 19.16 и, например, от 19.16 на 20.3. Как най-добре да преминете на нови версии, без да имате възможност за предварителна проверка на съвместимостта в пясъчната кутия?

Има няколко „златни“ правила. Първото е да четете changelog. Той е обширен, но там има отделни точки за обратно несъвместими промени. Не трябва да се отнасяте към тези точки като към червен флаг. Обикновено това са дребни несъвместимости, свързани с определена гранична функционалност, която вероятно не използвате.

Второ — ако нямате възможност да проверите съвместимостта в пясъчната кутия, и искате да обновите веднага в продукция, препоръката е следната — не го правете. Първо, създайте пясъчна кутия и проверете. Ако няма тестова среда, вероятно компанията ви не е много голяма, следователно можете да копирате част от данните на лаптопа си и на него да се уверите, че всичко работи коректно. Можете дори да стартирате няколко реплики локално на собствената си машина. Или можете да пуснете нова версия някъде наблизо и да вложите част от данните там — тоест да направите импровизирана тестова среда.

Още едно правило е — да не се обновявате в рамките на седмица след пускането на версията поради открития проблеми в продукцията и последващите бързи корекции. Нека разгледаме номерацията на версиите на ClickHouse, за да не се объркаме.

Има версия 20.3.4. Числото 20 обозначава годината на пускане — 2020. От гледна точка на съдържанието, това няма значение, така че да не му обръщаме внимание. Следващото е 20.3. Втората цифра — в този случай 3 — увеличаваме всеки път, когато издаваме версия с нова функционалност. Ако искаме да добавим някаква функция в ClickHouse, сме длъжни да увеличим това число. Тоест в версия 20.4 ClickHouse ще работи дори по-добре. Третата цифра — 20.3.4. Тук 4 е броят на пач релизите, в които не сме добавили нови възможности, но сме поправили някои бъгове. И 4 означава, че сме направили това четири пъти.

Не трябва да мислите, че това е нещо ужасно. Обикновено потребителят може да инсталира най-новата версия, и тя ще работи без никакви проблеми с ъптайм от година. Но представете си, че в някоя функция за обработка на битмапи, която е била добавена от нашите китайски колеги, сървърът пада при предаване на грешни аргументи. Ние сме длъжни да го поправим. Ще пуснем нова пач версия, и ClickHouse ще стане по-стабилен.

Ако ClickHouse работи във производствена среда и излиза нова версия ClickHouse с допълнителни функции — например 20.4.1 — в началото, не бързайте да я инсталирате в производството в първия ден. Каква е необходимостта от нея? Ако все още не използвате ClickHouse, можете да я инсталирате, и вероятно всичко ще бъде наред. Но ако ClickHouse вече работи стабилно, следете за пачовете и актуализациите — какви проблеми поправяме.

Кирил Шваков: Искам да добавя малко за тестовите среди. Всички много се страхуват от тестовите среди и по някаква причина смятат, че ако имате много голям клъстер ClickHouse, тестовата среда трябва да е не по-малка или поне десет пъти по-малка. Това не е вярно.

Мога да говоря от личен опит. Имам проект, и там има ClickHouse. Нашата тестова среда за него е малка виртуалка в Hetzner за двадесет евро, където всичко е разгръщено. За да го направим, имаме пълна автоматизация в Ansible, и затова няма никаква разлика къде развиваме — на физически сървъри или просто в виртуалки.

Какво може да се направи? Би било хубаво да се добави пример в документацията на ClickHouse как да се разположи малък кластер – в Docker, в LXC, може би да се създаде Ansible playbook, тъй като различните хора имат различни методи за разгръщане. Това би опростило много. Когато можеш за пет минути да разположиш кластер, много по-лесно е да се опитваш да разбереш нещо. По този начин е много по-удобно, защото разгръщането на версия в продукция, която не си проверил, е път към нищото. Понякога работи, понякога не. Затова е лошо да разчиташ на успех.

Максим Котяков, старши бекенд инженер в Авито: Нека добавя нещо за тестовите среди от серията проблеми на големите компании. Имаме напълно функциониращ приемен кластер ClickHouse, точна копия на данни и настройки на това, което имаме в продукцията. Този кластер е разположен в сравнително стари контейнери с минимум ресурси. Пишем там известен процент от продукционните данни, което е възможно благодарение на репликацията в Kafka. Там всичко е синхронизирано и мащабирано – както по мощност, така и по поток, и в теория, при равни условия, би трябвало да се държи като продукция по метрики. Всичко потенциално опасно пръв преминава през този стенд и преминава няколко дни, за да бъде готово. Но разбира се, това решение е скъпо, сложно и с не нулеви разходи за поддръжка.

Алексей Миловидов: Ще разкажа какво представлява тестовата среда на нашите приятели от «Яндекс.Метрика». Един кластер имаше над 600 сървъра, друг на 360, и има още трети и няколко клъстера. Тестовата среда за един от тях е просто два шарда с по две реплики във всеки. Защо два шарда? Защото не може да има само един. И репликите също трябва да са налични. Просто минимално количество, което можем да си позволим.

Тази тестова среда позволява да се провери работоспособността на запитванията и дали нещо не е счупено в голям мащаб. Но често проблемите възникват от съвсем различен характер, когато всичко работи, но има някои малки промени в натоварването.

Ще дам пример. Решихме да инсталираме нова версия на ClickHouse. Тя е разположена на тестовата среда, автоматизираните тестове в самата «Яндекс.Метрика» са преминали, които сравняват данните на старата версия с новата, стартирайки целия конвейер. И разбира се, зелените тестове на нашия CI. В противен случай не бихме предложили тази версия.

Всичко е чудесно. Започваме да излизаме на продукция. Получавам съобщение, че натоварването на графиците е нараснало няколко пъти. Връщаме версията. Поглеждам графика и виждам: наистина натоварването е нараснало няколко пъти по време на разгръщането и след това обратно намаля, когато версията беше разположена. След това започнахме да откатяваме версията. И натоварването увеличи точно толкова и също така отново падна. Така че изводът е такъв - натоварването се е увеличило във връзка с разгръщането, никаква изненада.

Следващото беше трудно да убедя колегите да инсталират новата версия. Казвам: „Всичко е наред, излагайте го. Дръжте палци, всичко ще работи. Сега натоварването на графиците е нараснало, но всичко е наред. Дръжте се“. В общи линии, направихме така и всичко - версията е разписана на продукцията. Но почти при всяко разгръщане възникват подобни проблеми.

Kill query трябва да убива заявките, но не го прави. Защо?

При мен дойде потребител, някакъв аналитик, и направи заявка, която постави моята ClickHouse клъстера. Някоя нода или целия клъстер - в зависимост от това, в коя реплика или шард заявката е попаднала. Виждам, че всички ресурси по CPU на този сървър са натоварени, всичко е червено. Въпреки това самият ClickHouse отговаря на заявките. И пиша: „Покажи ми, моля, списъка с процеси, коя заявка е породила това безумие“.

Намирам тази заявка и пиша kill. И виждам, че нищо не се случва. Моят сървър е натоварен, ClickHouse продължава да ми показва някакви команди, показва, че сървърът е жив и всичко е чудесно. Но имам деградация на всички потребителски заявки, започва деградация по записите в ClickHouse, и моя kill query не сработва. Защо? Мислех, че kill query трябва да убива заявките, но това не се случва.

Сега ще има доста странен отговор. Работата е там, че kill query не убива заявките.

Kill query поставя малък флаг с името „искам този запит да бъде убит“. А самата заявка при обработка на всеки блок поглежда този флаг. Ако той е зададен, заявката спира да работи. Получава се, че никой не убива заявката, тя сама трябва да провери всичко и да спре. И това трябва да работи във всички случаи, когато заявката е в състояние на обработка на данни блокове. Тя ще обработи следващия блок данни, ще провери флага и ще спре.

Това не работи в случаите, ако заявката е блокирана на някаква операция. Истината е, че вероятно това не е вашият случай, защото, според вашите думи, тя използва куп ресурси от сървъра. Възможно е това да не работи в случай на външна сортировка и още някои детайли. Но като цяло такова нещо не би трябвало да се случва, това е бъг. И единственото, което мога да съветвам, е да ъпдейтнете ClickHouse.

Как да изчислим времето за отговор при четяща натовареност?

Има таблица, в която се съхраняват агрегати по item — различни броячи. Броят на редовете е около сто милиона. Може ли да се разчита на предсказуемо време за отговор, ако налеем 1K RPS по 1K item-а?

Съдя по контекста, че става въпрос за четяща натовареност, тъй като при запис няма проблеми — може да се вмъкват дори хиляда, сто хиляди, а понякога и няколко милиона реда.

Четящите заявки могат да бъдат много разнообразни. В select 1 ClickHouse може да изпълнява около десетки хиляди заявки в секунда, така че дори заявки по един ключ вече ще изискват някои ресурси. И такива точкови заявки ще бъдат по-сложни, отколкото в някакви key-value бази данни, тъй като за всяко четене е необходимо да се прочете блок данни по индекса. Индексът адресира не всяка запис, а всеки диапазон. Тоест ще трябва да се прочете целият диапазон — това е 8192 реда по подразбиране. И ще трябва да се разпакова компресираният блок от 64 KB до 1 MB. Обикновено такива точкови заявки отнемат от няколко милисекунди. Но това е най-простият вариант.

Нека опитаме да направим проста аритметика. Ако умножим няколко милисекунди по хиляда, получаваме няколко секунди. Сякаш не можем да държим хиляда заявки в секунда, но всъщност можем, защото имаме няколко ядра на процесора. Така че принципно 1000 RPS ClickHouse понякога може да поддържа, но на кратки заявки, именно точкови.

Ако трябва да мащабирате кластера ClickHouse по количество обикновени заявки, тогава препоръчвам най-простото — да увеличите броя на репликите и да изпращате заявки на случайна реплика. Ако една реплика е в състояние да поддържа петстотин заявки в секунда, което е напълно реално, то три реплики ще могат да поддържат хиляда и петстотин.

Разбира се, понякога може да конфигурирате ClickHouse за максимален брой селективни четения. Какво е необходимо за това? Първо - да намалите грануларността на индекса. При това, тя не трябва да се намалява до единица, а на база изчисления, че броят на записите в индекса ще бъде няколко милиона или десетки милиони на сървъра. Ако в таблицата има сто милиона реда, грануларността може да бъде зададена на 64.

Може да намалите размера на компресирания блок. За това има настройки min compress block size, max compress block size. Те могат да бъдат намалени, данните да бъдат преназначени и тогава селективните запитвания ще бъдат по-бързи. Но все пак ClickHouse не е база данни key-value. Голям брой малки запитвания е антипатерн на натоварването.

Кирил Шваков: Ще дам съвет в случай, че там има обикновени екаунтери. Това е доста стандартна ситуация, когато в ClickHouse се съхранява определен брояч. Имам потребител, той е от определена страна, още едно трето поле и трябва да увеличавате нещо инкрементално. Вземате MySQL, правите уникален ключ - в MySQL той е duplicate key, а в PostgreSQL той е conflict - и добавяте с плюс. Това ще работи значително по-добре.

Когато имате малко данни, няма смисъл да използвате ClickHouse особено. Има обикновени бази данни и те се справят добре с това.

Какво да настроим в ClickHouse, за да има повече данни в кеша?

Да предположим, че на сървърите има 256 Гб RAM, в ежедневната рутина ClickHouse взима около 60—80 Гб, в пикови моменти - до 130. Какво можем да включим и настроим, за да има повече данни в кеша и, съответно, да има по-малко достъпи до диска?

Обикновено, page cache на операционната система се справя добре с тази задача. Ако просто отворите топ, погледнете там cached или free - там също е написано колко е кеширано - може да забележите, че всяка свободна памет е използвана за кеш. И тези данни при четене ще се четат не от диска, а от RAM. В същото време мога да кажа, че кешът се използва ефективно, защото се кешират именно компресираните данни.

Тем не по-малко, ако искате да ускорите някои прости запитвания още повече, има възможност да включите в ClickHouse кеш на разкомпресираните данни. Това се нарича uncompressed cache. В конфигурационния файл config.xml задавате uncompressed cache size на желаната от вас стойност – препоръчвам да не е повече от половината свободна RAM, защото остатъка отива под page cache.

Освен това, има две настройки на ниво заявка. Първата настройка – use uncompressed cache – активира неговото използване. Препоръчва се да бъде включена за всички заявки, освен за тежки, които могат да прочетат всичките данни и да изтрият този кеш. И втората настройка – това е нещо като максимален брой редове за използване на кеша. Тя автоматично ограничива големите заявки, за да преминават мимо кеша.

Как може да се настрои storage_configuration за съхранение в оперативната памет?

В новата документация на ClickHouse прочетох секция, свързана с data storage. В описанието има пример с бърз SSD.

Интересно е как може да се конфигурира същото с volume hot memory. И още един въпрос. Как работи select с такава организация на данните, ще чете ли целия набор или само този, който е на диска и компресират ли се тези данни в паметта? И как работи секцията prewhere при такава организация на данните?

Тази настройка влияе на съхранението на парчетата данни и техният формат не се променя.
Нека да разгледаме по-подробно.

Може да се конфигурира съхранение на данни в оперативната памет. Всичко, което се конфигурира за диска – това е неговия път. Създавате tmpfs дял, който е монтиран на някакъв път в файлова система. Указвате този път като път за съхранение на данни за най-горещия дял, където започват да постъпват и записват парчета данни, всичко е наред.

Но не препоръчвам така да стане, поради ниска надеждност, макар че, ако имате минимум три реплики в различни дата центрове, е допустимо. Ако нещо стане, данните ще бъдат възстановени. Представете си, че сървърът внезапно се изключва и след това се включва отново. Дялът се монтира отново, но там е пусто. Сървърът ClickHouse при стартиране вижда, че тези парчета отсъстват, въпреки че според метаданните в ZooKeeper, те трябва да са налични. Той проверява на кои реплики ги има, заявява ги и ги сваля. По този начин данните ще бъдат възстановени.

В това отношение съхранението на данни в оперативна памет принципно не се различава от съхранението им на диск, тъй като при запис на данни на диск те също първо преминават през page cache и физически се записват отложено. Това зависи от начина на монтиране на файловата система. Но все пак ще кажа, че ClickHouse не прави fsync при insert.

При това данните в оперативната памет се съхраняват в точно такъв същия формат, както на диска. Запитването select точно така избира парчета, които трябва да се четат, в парчета избира необходимите диапазони данни и ги чете. И prewhere работи напълно идентично, независимо от това дали данните са в оперативната памет или на диска.

До какво количество уникални стойности е ефективен Low Cardinality?

Low Cardinality е хитро устроен. Той изгражда локални речници на данни. Първо, речниците са собствени за всяко парче, второ, дори в рамките на едно парче те могат да бъдат различни за всеки диапазон. Когато броят на уникалните стойности достигне праговото количество — по мое мнение, един милион — речникът просто се отлага и се създава нов.

Отговорът в общи линии: за всеки локален диапазон — да кажем, за всеки ден — някъде до милион уникални стойности Low Cardinality е ефективен. След това ще има само fallback, при който ще се използват много различни речници, а не един. Ще работи по подобен начин като обикновена колона от тип string, може би малко по-малко ефективно, но съществена деградация на производителността няма да настъпи.

Какви са най-добрите практики за пълнотекстово търсене на таблица с пет милиарда реда?

Има различни варианти на отговор. Първият е да се каже, че ClickHouse не е система за пълнотекстово търсене. За това има специализирани системи, например, Elasticsearch и Sphinx. Въпреки това, все по-често срещам хора, които казват, че преминават от Elasticsearch на ClickHouse.

Защо се случва това? Те обясняват, че Elasticsearch спира да се справя с натоварването на определени обеми, започвайки от това, което се отнася до изграждането на индекси. Индексите стават твърде обемисти, и ако просто прехвърлиме данните в ClickHouse, ще се окаже, че те се съхраняват в пъти по-ефективно по обем. В същото време търсещите запитвания често не са такива, че трябва да се намери фраза с оглед на морфологията в целия обем данни, а съвсем различни. Например, да се намери за последните няколко часа в логовете по някаква подпоследователност от байтове.

В този случай в ClickHouse създавате индекс, при който първото поле е дата с време. Най-голямото отсичане на данни ще бъде именно по диапазона дати. В рамките на избрания диапазон дати обикновено е възможно да се извърши пълнотекстово търсене дори с брутфорс методи, използвайки like. Операторът like в ClickHouse е най-ефективният оператор, който можете да намерите. Ако намерите по-добър – уведомете ме.

Но все пак like е full scan. И full scan може да бъде бавен не само по CPU, но и по диск. Ако случайно имате един терабайт данни на ден и за ден търсите някаква дума, ще трябва да сканирате терабайта. А той вероятно е на обикновени твърди дискове и в крайна сметка те ще бъдат натоварени така, че да не можете да влезете на този сървър по SSH.

В този случай съм готов да предложа още един малък трик. Той е от категорията експериментални – може да сработи, а може и не. В ClickHouse има пълнотекстови индекси под формата на триграмни Блум-филтри. Нашите колеги от компанията Arenadata вече пробваха тези индекси, и често те работят точно така, както е предвидено.

За да ги използвате правилно, трябва добре да разберете как точно работят: какво представлява триграмният Блум-филтър и как да изберете неговия размер. Мога да кажа, че те ще помогнат за заявки по някакви редки фрази, подстрингове, които рядко се срещат в данните. В този случай индексите ще изберат поддиапазони и ще се прочете по-малко данни.

Наскоро в ClickHouse се появиха още по-напреднали функции за пълнотекстово търсене. Това, от една страна, е търсене на куп подстрингове с едно преминаване, включително варианти с чувствителност към регистър, без чувствителност, с поддръжка на UTF-8 или само за ASCII. Изберете най-ефективния, от който се нуждаете.

Също така се появи търсене на няколко регулярни израза с едно преминаване. Няма нужда да пишете X like един подстринг or X like друг подстринг. Просто пишете и всичко се извършва максимално ефективно.

Трето – сега има приближено търсене на регекс и приближено търсене на подстрингове. Ако някой е написал дума с печатна грешка, ще бъде потърсена по максимално съвпадение.

Как е най-добре да се организира достъпът до ClickHouse за голям брой потребители?

Разкажете как да организирате достъпа за голям брой потребители и анализатори. Как да формирате опашка, да приоритизирате запитванията max concurrent queries и с какви инструменти?

Ако клъстърът е достатъчно голям, то добро решение е да добавите още два сървъра, които да бъдат входна точка за анализаторите. Тоест, да не допускате анализаторите до конкретни шардове на клъстера, а просто да създадете два празни сървъра без данни и на тях да настроите правата за достъп. В същото време настройките на потребителите при разпределените запитвания се предават на отдалечените сървъри. Тоест, настройвате всичко на тези два сървъра и настройките оказват ефект върху целия клъстър.

В принципе, тези сървъри са без данни, но обемът на оперативната памет е съществен за изпълнението на запитванията. Дискът също може да се използва за времеви данни, ако е активирана външната агрегация или външната сортировка.

Важно е да се разгледат настройките, които са свързани с всички възможни лимити. Ако в момента вляза в клъстъра на "Яндекс.Метрика" като анализатор и задам заявка select count from hits, веднага ще получа изключение, че не мога да изпълня заявката. Максималният брой редове, които мога да сканирам, е сто милиарда, а общо в клъстъра има петдесет трилиона в една таблица. Това е първото ограничение.

Да предположим, че премахна ограничението за брой редове и изпълня запитването отново. Тогава ще видя следното изключение – активирана е настройката force index by date. Не мога да изпълня запитването, ако не съм посочил диапазон от дати. Не трябва да разчитате, че анализаторите ще го посочат ръчно. Типичен случай е, когато е написан диапазон от дати where event date between седмица. А после просто не къде трябва да е затворен скобата, и вместо and се получава or – or URL match. Ако няма ограничения, ще започне да сканира колоната URL и ще изразходва просто тон ресурси.

Освен това, в ClickHouse има две настройки за приоритети. За съжаление, те са много примитивни. Едната е просто приоритет. Ако приоритет ≠ 0, и се обработват заявки с някакъв приоритет, но при това се изпълнява заявка с приоритет, който има стойност под, което означава по-висок приоритет, то заявката със стойност приоритет по-голяма, което обозначава по-нисък приоритет, просто ще бъде временно спряна и няма да работи изобщо през това време.

Това е много груба настройка и тя не е подходяща за случаи, когато на кластера има постоянна натовареност. Но ако имате кратки, импулсивни важни заявки, а основно кластерът стои без работа, такава настройка ще бъде подходяща.

Следващата настройка на приоритетите се нарича приоритет на OS нишката. Тя просто задава за всички потоци за изпълнение на заявки величината nice за планиратора Linux. Работи не много добре, но все пак работи. Ако зададете най-ниската стойност на nice — тя е най-голямата по размер и означава най-нисък приоритет — а за заявките с висок приоритет зададете -19, то CPU ще приема нископриоритетни заявки приблизително четири пъти по-малко от вископриоритетните.

Трябва също така да настроите максималното време за изпълнение на заявката — да кажем, пет минути. Минималната скорост на изпълнение на заявката — това е най-важното. Тази настройка съществува отдавна и е необходима, за да не просто да твърдим, че ClickHouse не забавя, а за да го принудим.

Представете си, че настройвате: ако някоя заявка обработва под един милион реда в секунду — така не може. Това опетнява нашето добро име, нашата добра база данни. Нека просто да забраним това. Там всъщност има две настройки. Едната се нарича минимална скорост на изпълнение — в редове в секунду, а втората се нарича timeout преди проверка на минималната скорост на изпълнение — по подразбиране петнадесет секунди. Тоест петнадесет секунди е позволено, а след това, ако е бавно, просто да хвърлите изключение — да прекратите заявката.

Трябва също да настроите квоти. В ClickHouse има вградена възможност за квоти, която брои потреблението на ресурси. Но, за съжаление, не физически ресурси, като CPU, дискове, а логически — брой обработени заявки, реда и прочетени байтове. И можете да настроите, например, максимум сто заявки в течение на пет минути и хиляда заявки на час.

Защо е важно това? Защото част от аналитичните запитвания ще бъдат изпълнявани ръчно директно от клиента на ClickHouse. И всичко ще е наред. Но ако във вашата компания има напреднали анализатори, те ще напишат скрипт, а в скрипта може да има грешка. И тази грешка може да доведе до неограничен цикъл на изпълнение на запитването. Трябва да се защитим от това.

Може ли да се предадат резултатите от една заявка на десет клиента?

Имаме няколко потребители, които обичат да идват с много големи запитвания в един и същи момент. Запитването е голямо, изпълнява се бързо, но поради многото едновременни запитвания, ситуацията става много трудна. Може ли едно и също запитване, което идва десет пъти подред, да се изпълни веднъж и резултатът да бъде предоставен на десетте клиента?

Проблемът е, че нямаме резултати от кеша или кеш на междинните данни. Има кеш на страниците на операционната система, който ще позволи повторно да не се четат данни от диска, но, за жалост, данните пак ще се декомпресират, десериализират и обработват повторно.

Искаме да избегнем това, като кешираме междинни данни, или като изградини подобни запитвания в някаква опашка и добавим кеш на резултатите. В момента имаме в разработка един pull request, който добавя кеш на запитванията, но само за подзапитвания в секцията in и join — тоест, решението не е пълно.

Въпреки това, и при нас възниква такава ситуация. Особено каноничният пример е запитванията с пагинация. Има отчет, в него има няколко страници, и се изпълнява запитване с лимит 10. След това същото, но с лимит 10,10. След това идва следващата страница. И задаваме въпроса, защо всеки път смятаме всичко това? Но в момента решение няма и не можем да избегнем това.

Има алтернативно решение, което се поставя в сайдкар до ClickHouse — ClickHouse Proxy.

Кирил Шваков: В ClickHouse Proxy има вграден лимитатор на заявки и вграден кеш на резултатите. Там са направени много настройки, защото беше решавана сходна задача. Proxy позволява ограничаване на запитванията, подреждайки ги в опашка, и настройване колко време живее кешът на запитванията. Ако запитванията наистина са идентични, Proxy ще ги върне много пъти, а в ClickHouse ще отиде само веднъж.

В Nginx също има кеш в безплатната версия и това също ще работи. Nginx дори има настройки, които, ако заявките пристигнат едновременно, ще забавят другите, докато едната не бъде изпълнена. Но именно в ClickHouse Proxy настройката е направена много по-добре. Тя е проектирана конкретно за ClickHouse и за тези заявки, така че е по-подходяща. Освен това, инсталацията е много проста.

Как да се справим с асинхронните операции и материализираните представления?

Има такъв проблем, че операциите с реплейсинг мотора са асинхронни — първо се записват данните, после се извършва тяхното свиване. Ако под таблицата има материализирана таблица с определени агрегати, дубликатите ще се запишат в нея. И ако няма сложна логика, данните ще бъдат дублирани. Какво можем да направим по този въпрос?

Има очевидно решение — да се реализира тригер за определен клас матвьюх при асинхронна операция на свиване. Има ли някакви „сребърни куршуми“, планове за реализиране на подобни функционалности?

Струва си да се разбере как работи дедупликацията. Това, за което ще говоря сега, не се отнася до въпроса, но все пак е добре да се има предвид.

При вмъкване в реплицирана таблица има дедупликация на цялостно вмъкнатите блокове. Ако повторно вмъкнете един и същ блок, съдържащ същото количество от същите редове в същия ред, данните ще бъдат дедупликирани. Ще получите „Ok“ в отговор на insert, но всъщност ще бъде записан само един блок данни, който няма да бъде дублиран.

Това е необходимо за определеност. Ако по време на вмъкването сте получили „Ok“, значи вашите данни са вмъкнати. Ако получите грешка от ClickHouse, значи те не са вмъкнати и трябва да повторите вмъкването. Но ако по време на вмъкването връзката е прекъсната, няма да знаете дали данните са вмъкнати или не. Единственият вариант е да повторите вмъкването. Ако данните всъщност са били вмъкнати и вие ги вмъкнете повторно, има дедупликация на блоковете. Тя е необходима, за да се избегнат дубликати.

И е важно да се знае как работи тя за материализирани представления. Ако данните са били дедуплицирани при вмъкването в основната таблица, те също няма да влязат в материализираното представление.

Сега по отношение на въпроса. Вие имате по-сложна ситуация, защото записвате дубликати на отделни редове. Тоест, не пакетът е дублиран изцяло, а именно конкретни редове, и те се компресират на фона. Наистина, данните ще се компресират в основната таблица, а в материализираното представление ще отидат некондензираните, и при сливане нищо няма да се случи с материализираните представления. Защото материализираното представление е нещо като триггер на insert. При други операции нищо допълнително с него не се случва.

И тук не мога да ви зарадвам. Трябва само да търсите конкретно решение за този случай. Например, може ли в материализираното представление също да направите неговото заместване и начинът на дедупликация, може би, ще работи по същия начин. Но за съжаление, не винаги. Ако е агрегираща, няма да стане.

Кирил Шваков: При нас също имаше своето време на нещата. Имаше проблем, че има показвания на реклами и някои данни, които можем да показваме в реално време — това са просто показвания. Те рядко се дублират, но ако това се случи, ние пак ще ги компресираме по-късно. И имаше неща, които не могат да бъдат дублирани — кликове и цялата тази история. Но искахме да ги показваме почти веднага.

Как бяха направени материализираните представления? Имаше представления, в които се записва директно — записва се в суровите данни и се записва във view. Там в някакъв момент данните не са много точни, а те се дублират и така нататък. И има втора част от таблицата, където те изглеждат абсолютно същите, като материализираните представления, тоест по структура са абсолютно идентични. Всеки определен период преизчисляваме данните, допълваме данните без дубликати, записваме в тези таблици.

Ние работихме през API — в ClickHouse ръчно това няма да проработи. И API наблюдава: когато имам дата на последното добавяне в таблицата, където гарантирано вече има правилни данни, изчислени, и той прави запитване към една таблица и към друга таблица. От едната запрос избира до определено количество време, а от другата допълва това, което още не е изчислено. И това работи, но не със средствата на самия ClickHouse.

Ако имате API за анализатори или за потребителите, това е вариант. Вие винаги осчетоводявате, винаги преизчислявате. Можете да го правите веднъж на ден или в друго време. Вие сами избирате диапазона, който не ви е нужен и не е критичен.

В ClickHouse има много логове. Как мога да виждам всичко, което се случва със сървера в момента?

В ClickHouse има много различни логове и техният брой нараства. В новите версии някои от тях са включени по подразбиране, а в старите версии трябва да се активират при обновление. Независимо от това, те стават все повече. Искам да виждам какво се случва сега на моя сървър, може би на някаква обобщаваща табло.

Нямате ли в екипа си ClickHouse или в екипите на ваши приятели, които поддържат някакъв функционал на готови табла, които да показват тези логове в вид на готов продукт? В крайна сметка, просто да наблюдавате логовете в ClickHouse е страхотно. Но би било много удобно, ако това вече беше под формата на табло. Бих се радвал на това.

Има табла, но не са стандартизирани. При нас в компанията около 60 екипа използват ClickHouse, и най-странното е, че много от тях имат табла, които сами са си направили, и са малко различни. Някои екипи използват вътрешна инсталация на „Яндекс.Облака“. Там има някои готови отчети, макар и не всички необходими. Другите имат свои.

Моите колеги от „Метрики“ имат свое табло в Grafana, а аз имам свое по техния кластер. Там гледам неща като кэш хит за кэша на засечките. И е дори по-сложно, тъй като използваме различни инструменти. Моето табло съм създавал на много стар инструмент, който се нарича Graphite-web. То е съвсем грозно. И дотук ползвам него, въпреки че Grafana вероятно би била по-удобна и красива.

Основната информация в таблата за управление е еднаква. Това са системните метрики за кластера: CPU, памет, диск, мрежа. Другите метрики включват брой на едновременни заявки, брой на едновременни обединявания, брой на заявки в секунда, максимален брой парчета за партициите на таблиците MergeTree, забавяне на репликацията, размер на репликационната опашка, брой на вставени редове в секунда, брой на вставени блокове в секунда. Това са всичките метрики, които не произлизат от логовете, а от системните метрики.

Владимир Колобаев: Алексей, бих искал да направя малки корекции. Има Grafana. Grafana разполага с източник на данни, който е ClickHouse. Тоест мога да правя заявки от Grafana директно към ClickHouse. В ClickHouse има таблица с логове, която е еднаква за всички. Искам в Grafana да взаимодействам с тази таблица с логове и да виждам заявките, които моята система генерира. Би било чудесно да имам такава табличка.

Аз сам си я изградих. Но имам един въпрос - ако всичко е стандартизирано и Grafana се използва от много хора, защо в Яндекс няма такъв официален табло?

Кирил Шваков: Всъщност източникът на данни за ClickHouse в момента се поддържа от Altinity. И просто искам да дам насока къде да си търсите информация и на кого да се обърнете. Можете да попитате тях, защото Яндекс наистина разработва ClickHouse, а не историята около него. Altinity е основната компания, която в момента популяризира ClickHouse. Те няма да го оставят и ще продължат да го поддържат. Защото принципно, за да качите табло на сайта на Grafana, трябва само да се регистрирате и да го качите - няма особени проблеми.

Алексей Миловидов: През последната година в ClickHouse бяха добавени много нови функции за профилиране на заявки. Има метрики за всяка заявка относно използването на ресурси. А съвсем наскоро бе добавен дори по-нискостепенен профилатор на заявки, за да можем да видим къде всяка заявка прекарва милисекундите. Но за да да използвам тази функционалност, трябва да отворя конзолния клиент и да напиша заявка, която постоянно забравям. Запазил съм я някъде и постоянно забравям къде точно.

Бих искал инструмент, който просто да показва — ето вашите сложни заявки, групирани по класове. Кликвам на някоя и ми казват, че е сложна поради това. В момента такова решение няма. И наистина е странно, че, когато хората ме питат: „Кажете, има ли готови табла за Grafana?“, аз им казвам: „Отидете на сайта на Grafana, там е общността 'Табла', и там има табло от Димка, има табло от Костяна. Какво е това, не знам, сам не съм го ползвал“.

Как да влияя на мерджовете, за да не пада сървърът в OOM?

Имам таблица, в която има само една партиция, тя е ReplacingMergeTree. Пиша данни в нея в продължение на четири години. Трябваше да направя алтер и да изтрия някои данни.

Направих го и по време на обработката на тази заявка целият памет на всички сървъри в клъстера беше изразходвана и всички сървъри дружно отидоха в OOM. След това те всички заедно се наведоха, започнаха да изпълняват мерджа на същата операция, този блок данни, и отново паднаха в OOM. После отново станаха и отново паднаха. И това не спираше.

След това се оказа, че това наистина е бъг, който момчетата поправиха. Това е много хубаво, благодаря много. Но остатъкът остана. И сега, когато мисля да направя някакъв мердж в таблицата, ми хрумва въпросът — защо не мога да влияя на тези мерджове по някакъв начин? Например, да ги ограничавам по количество необходима оперативна памет или по принцип по тяхното количество, което ще обработва конкретно тази таблица.

Имам таблица, която се нарича 'Метрики', моля те, обработвай я в два потока. Не трябва да се създават десет или пет паралелни мерджа, направи я в два. Мисля, че в два ще ми стигне паметта, а за десет може да не стигне. Защо страхът остава? Защото таблицата расте и рано или късно ще се изправя пред ситуация, когато не само заради бъг, а поради факта, че данните ще се променят в толкова голямо количество, че просто няма да ми стигне паметта на сървъра. И тогава сървърът ще падне в OOM при мерджа. Мога да отменя мутацията, но мерджовете не могат.

Знаете ли вие, че при сливане сървърът няма да падне поради OOM, тъй като за сливане се използва количество оперативна памет само на един малък диапазон от данни. Така че всичко ще бъде наред, независимо от обема на данните.

Владимир Колобаев: Добре. Тук има такъв момент, че след като направихме корекция на грешки, изтеглих нова версия и на друга таблица, по-малка, kъдето имаше много партиции, направих подобна операция. И по време на сливането на сървъра изразходвах около 100 Гб оперативна памет. Имах 150 заето, 100 изчезнаха и остана прозорец от 50 Гб, така че не изпаднах в OOM.

Какво ме защитава в момента от това да не изпадна в OOM, ако той наистина изразходва по 100 Гб оперативна памет? Как да постъпя в ситуация, ако изведнъж оперативната памет на сливанията свърши?

Алексей Миловидов: Съществува такъв проблем, че разходът на оперативна памет именно при сливания не е ограничен. И вторият проблем е, че ако някое сливане е било назначено, то трябва да бъде изпълнено, защото е записано в логовете на репликацията. Логът на репликацията е тези действия, които са необходими, за да доведат репликата до последователно състояние. Ако не се направят ръчни манипулации, които да върнат този лог на репликацията, сливането трябва да бъде изпълнено, по всякакъв начин.

Разбира се, не би било лошо да има ограничение на оперативната памет, което "за всеки случай" защитава именно от OOM. То няма да помогне на сливането да се извърши, то ще започне отново, ще стигне до някакъв праг, ще хвърли изключение, а след това отново ще започне - от това нищо добро няма да излезе. Но в принципе, въвеждането на това ограничение би било полезно.

Как ще се разработва Golang драйверът за ClickHouse?

Golang драйверът, написан от Кирил Шваков, сега изглежда, че официално се поддържа от екипа на ClickHouse. Той в репозиторията на ClickHouse, сега е голям и истински.

Небольшо коментирање. Има одличен и широко обожаван хранилище нормални форми на бесконечен ред — тоа е Vertica. Тие исто така имаат свој официјален Python драйвер, кој го поддржуваат развивачите на Vertica. Неколку пати се случило верзиите на хранилиштето и верзиите на драйверот да значително да се разликуваат и драйверот одеднаш да престане да функционира. И уште една работа. Поддршката на овој официјален драйвер, се чини, се управува од системот „нипел“ — пишуваш им за проблем и тој останува отворен засекогаш.

Имам два прашања. Сега Golang драйверот на Кирил е речиси стандардниот начин за комуникација од Golang со ClickHouse. Освен ако некој сè уште комуницира преку http интерфејс, затоа што му е удобно. Како ќе се одвива развојот на овој драйвер? Дали ќе биде синхронизирано со некои breaking changes во самото хранилиште? И каков е редоследот на разгледување на проблемите?

Кирил Шваков: Првото — како е сè организирано бирократски. Овој момент не беше дискутиран, па немам што да одговорам.

За да одговорам на прашањето за проблемот, потребна е кратка историја на драйверот. Работев во компанија со многу податоци. Тоа беше рекламна платформа со огромен број на настани што требаше да се чуваат некаде. И во некој момент се појави ClickHouse. Ние ставивме податоци таму и првиот период сè беше во ред, а потоа ClickHouse се сруши. Во тој момент одлучивме дека не ни е потребен.

По година дена се вративме на идејата за користење на ClickHouse и ни беше потребно како да внесеме податоци таму. Воведната ситуација беше таква — хардверот беше многу слаб, ресурсите беа ограничени. Но секогаш работевме така, па погледнавме кон нативниот протокол.

Бидејќи работевме на Go, беше јасно дека ни треба драйвер на Go. Јас го развив речиси цело работно време — тоа беше мојата работна задача. До некоја точка го завршивме и генерално никој не очекуваше дека освен нас некој друг ќе го користи. Потоа дојде CloudFlare со иста проблематика и некое време работевме со нив многу сплотено, бидејќи имаа истите задачи. И тоа го правевме во ClickHouse самиот, и во драйверот.

В определен момент просто спрях да се занимавам с това, защото активността ми по отношение на ClickHouse и работата ми се промени. Поради това, въпросите не се закриват. Периодично в репозитория комитват хора, на които нещо им трябва. Тогава преглеждам pull request и понякога дори коригирам нещо сам, но това става рядко.

Искам да се върна към драйвера. Няколко години назад, когато всичко това започваше, ClickHouse също беше различен и с други възможности. Сега обаче имам представа как да преосмислим драйвера, така че да е по-добре. Ако това стане, версия 2 определено ще бъде несъвместима поради натрупаните проблеми.

Не знам как да организирам всичко това. Нямам много време сам. Ако има хора, които ще доразвиват драйвера, мога да им помагам и да обяснявам какво да правят. Но активното участие на ‘Яндекс’ в развитието на проекта все още не е обсъждано.

Алексей Миловидов: Наистина в момента няма никаква бюрокрация относно тези драйвери. Единственото е, че те са изнесени в официална организация, тоест този драйвер е признат за официално решение по подразбиране за Go. Има някакви други драйвери, но те са отделни.

Вътре при нас няма никаква разработка за тези драйвери. Въпросът е – можем ли да наемем отделен човек, не конкретно за този драйвер, а за развитието на всички комюнити-драйвери, или можем ли да намерим някого отвън.

Външната речник не се зарежда след рестартиране с включена настройка lazy_load. Какво да правим?

Имаме включена настройка lazy_load, и след рестартиране на сървъра речникът сам не се зарежда. Той се зарежда само след като потребителят се обърне към този речник. И при първото обращение дава грешка. Има ли начин автоматично чрез ClickHouse да се зареждат речниците, или винаги трябва ние да контролираме готовността им, за да не получават потребителите грешки?

Може би имаме стара версия на ClickHouse, поради което речникът автоматично не се е зареждал. Може ли да е така?

Първо, речниците могат да бъдат насилствено заредени с помощта на запитване system reload dictionaries. Второ, относно грешката – ако речникът вече е зареден, запитванията ще работят с данните, които са били заредени. Ако речникът все още не е бил зареден, то той ще се зарежда точно по време на запитването.

За тежки речници това не е много удобно. Например, трябва да извлечете милион реда от MySQL. Някой прави прост селект, но този селект ще чака именно милиона реда. Има два решения. Първото е да изключите lazy_load. Второто е, когато сървърът се стартира, преди да го натоварите, да направите system reload dictionary или просто да изпълните заявка, която използва речника. Тогава речникът ще бъде зареден. Трябва сами да контролирате достъпността на речниците с включена настройка lazy_load, защото ClickHouse автоматично не ги зарежда.

На последния въпрос отговорът е, че или версията е стара, или трябва да отлаждате.

Какво да правя с факта, че system reload dictionaries не зарежда нито един от многото лексикони, ако поне един от тях се провали с грешка?

Има и друг въпрос относно system reload dictionaries. Имаме два речника – един не се зарежда, вторият се зарежда. В такъв случай system reload dictionaries не зарежда нито един речник и трябва да заредите конкретен по името му с помощта на system reload dictionary. Свързано ли е това и с версията на ClickHouse?

Искам да ви зарадвам. Това поведение се е променило. Следователно, ако обновите ClickHouse, то също ще се промени. Ако текущото поведение не ви удовлетворява system reload dictionaries, обновете, и да се надяваме, че ще се промени към по-добро.

Има ли начин да конфигурираме данните в конфигурацията на ClickHouse, без да ги разкрием при грешки?

Следващият въпрос е за грешките, свързани с речника, а именно реквизитите. Ние сме посочили реквизитите за свързване в конфигурацията на ClickHouse за речника и при грешка получаваме тези реквизити и паролата в отговор.

Решихме този проблем, като изнесохме реквизитите в конфигурацията на ODBC драйвера. Има ли начин да конфигурирате реквизитите в конфигурацията на ClickHouse, но без да разкривате тези реквизити при грешки?

Тук решението е наистина да посочите тези credentials в odbc.ini, а в самия ClickHouse да посочите само Името на ODBC Източник на Данни. За останалите източници на речници това няма да се случи – нито за речника с MySQL, нито за другите не трябва да виждате паролата при съобщение за грешка. И за ODBC ще погледна – ако такова съществува, просто трябва да се премахне.

Бонус: фонове за Zoom от сбирките

При кликване на картинката за най-упоритите читатели ще се отворят бонус фонове от посиделките. Гасим пожара заедно с маскотите на технологиите на Авито, съветваме се с колеги от стаята на системния администратор или олдскульния компютърен клуб и провеждаме дейли под моста на фона на графити.

ClickHouse за напреднали потребители в въпроси и отговори

Източник: habr.com

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster