ClickHouse для продвинутых пользователей в вопросах и ответах

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

По мотивам встречи мы собрали статью с ответами экспертов на наши и зрительские вопросы про бэкапы, решардинг данных, внешние словари, Golang-драйвер и обновление версий ClickHouse. Она может быть полезна разработчикам, которые уже активно работают с СУБД «Яндекса» и интересуются её настоящим и будущим. По умолчанию ответы Алексея Миловидова, если не написано иное.

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

uvixouffnzvqs2ff5pen32ojsc8.png


Содержание


  • ClickHouse постоянно обновляется, а наши данные — нет. Что с этим делать?
  • Какие лучшие практики есть на данный момент по резервному копированию данных из ClickHouse?
  • Можно ли будет организовать контролируемое отставание реплик в валах?
  • Как быть, если структура таблицы поменялась?
  • Какие сейчас лучшие практики в решардинге данных?
  • В ClickHouse есть утилита clickhouse-copier. Можете про неё рассказать?
  • У вас была пилотная штука, которая называлась решардинг. Что с ней?
  • Можно ли сливать все части данных воедино перед перемещением на медленные диски?
  • Как переезжать на новые версии ClickHouse, если нет возможности заранее проверить совместимость?
  • Kill query должен убивать запросы, но он этого не делает. Почему?
  • Как рассчитать время ответа при читающей нагрузке?
  • Что подтюнить в ClickHouse, чтобы больше данных было в кэше?
  • Как можно настроить storage_configuration для хранения в оперативке?
  • До какого количества уникальных значений эффективен Low Cardinality?
  • Какие лучшие практики по полнотекстовому поиску по таблице с пятью миллиардами строк?
  • Как лучше организовать доступ в ClickHouse для большого количества пользователей?
  • Можно ли отдать результаты одного запроса десяти клиентам?
  • Как быть с асинхронными операциями и материализованными представлениями?
  • В ClickHouse много логов. Как я могу видеть все, что происходит с сервером в моменте?
  • Как воздействовать на мерджи, чтобы сервер не падал в OOM?
  • Как будет происходить разработка Golang-драйвера для ClickHouse?
  • Внешний словарь не поднимается после перезагрузки с включенной настройкой lazy_load. Что делать?
  • Как быть с тем, что system reload dictionaries не подгружает ни один из множества словарей, если хотя бы один из них падает с ошибкой?
  • Есть ли способ конфигурировать реквизиты в конфиге ClickHouse, но не светить их при ошибках?
  • Бонус: фоны для Зума с посиделок


Если не хочется читать текст, можно посмотреть запись посиделок на нашем ютуб-канале. Таймкоды — в первом комментарии под видео.


ClickHouse постоянно обновляется, а наши данные — нет. Что с этим делать?


ClickHouse постоянно обновляется, а наши данные, которые были optimize final обработаны, не обновляются и лежат в резервной копии.

Предположим, у нас случилась какая-нибудь проблема, и данные были утеряны. Мы решили восстановиться, и оказалось, что старые партиции, которые лежат на сохранении в серверах бэкапов, очень сильно расходятся с используемой на данный момент версией ClickHouse. Что делать в такой ситуации, и возможна ли она?

Ситуация, при которой вы восстановили из бэкапа данные в старом формате, а на новой версии они не подключаются, невозможна. Мы следим за тем, чтобы формат данных в ClickHouse всегда оставался обратно совместимым. Это гораздо важнее, чем обратная совместимость по функциональности, если изменилось поведение какой-то редко используемой функции. Данные, которые хранятся на диске, новая версия ClickHouse всегда должен уметь читать. Это закон.


Какие лучшие практики есть на данный момент по резервному копированию данных из ClickHouse?


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

Мы можем накостылять собственное решение и на баше написать: собирай так-то и так-то эти резервные копии. Может быть, костылять ничего не надо, и велосипед давно изобретён?

Для начала по поводу лучших практик. Мои коллеги всегда советуют в ответ на вопросы про бэкапы напоминать про сервис «Яндекс.Облако», где эта задача уже решена. Так что пользуйтесь им, если есть такая возможность.

Полного решения, на сто процентов встроенного в ClickHouse, для бэкапов нет. Есть некоторые заготовки, которые можно использовать. Чтобы получить полное решение, придётся либо немножко вручную повозиться, либо сделать обёртки в виде скриптов.

Начну с самых простых решений и закончу самыми навороченными в зависимости от объёма данных и размера кластера. Чем больше кластер — тем сложнее становится решение.

Если таблица с данными занимает всего несколько гигабайт, бэкап можно сделать так:


  1. Сохранить определение таблиц, то есть метаданные — show create table.
  2. Сделать дамп с помощью ClickHouse клиента — select * from table в файл. По умолчанию вы получите файл в формате tags separated. Если хочется более эффективно — можно в формате native.

Если объём данных больше, то бэкап займёт больше времени и много места. Это называется логический бэкап, он не привязан к формату данных ClickHouse. Если он есть, то в крайнем случае вы сможете взять бэкап и загрузить в MySQL для восстановления.

Для более продвинутых случаев в ClickHouse встроена возможность создать снапшот партиций в локальной файловой системе. Эта возможность доступна в виде запроса alter table freeze partition. Или просто alter table freeze — это снапшот всей таблицы.

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

Восстановить такой бэкап достаточно легко. Первое — создаёте таблицы по имеющимся определениям таблиц. Далее копируете сохраненные снапшоты партиций в Directory-Detached для данных таблиц и выполняете запрос attach partition. Такое решение вполне подходит для самых серьёзных объемов данных.

Иногда требуется что-то ещё круче — в тех случаях, когда у вас десятки или даже сотни терабайт на каждом сервере и сотни серверов. Тут есть решение, которое я подсмотрел у коллег из «Яндекс.Метрики». Я бы не рекомендовал его каждому — прочитайте и сами решите, подходит оно или нет.

Сначала нужно создать несколько серверов с большими дисковыми полками. Далее на этих серверах поднять несколько ClickHouse серверов и настроить их так, чтобы они работали как ещё одна реплика для тех же шардов. И дальше использовать на этих серверах файловую систему или некий инструмент, который позволяет создавать снапшоты. Тут есть два варианта. Первый вариант — это LVM снапшоты, второй вариант — ZFS на Linux.

После этого каждый день нужно создавать снапшот, он будет лежать и занимать какое-то место. Естественно, если данные меняются, то со временем объём места будет увеличиваться. Этот снапшот можно достать в любой момент и восстановить данные, вот такое странное решение. Плюс ещё надо ограничить эти реплики в конфиге, чтобы они не пытались становиться лидерами.


Можно ли будет организовать контролируемое отставание реплик в валах?


В этом году вы планируете делать валы в ClickHouse. Можно ли будет в них организовать контролируемое отставание реплик? Мы хотели бы с его помощью обезопасить себя от негативных сценариев с альтерами и прочими изменениями.

Можно ли сделать какие-то roll back для альтеров? Например, в существующем вале взять и сказать, что до этого момента применяй изменения, а с этого момента изменения перестань применять?

Если в наш кластер пришла команда и поломала его, то у нас есть условная реплика с отставанием в час, где мы можем сказать, что давайте будем именно её использовать на данный момент, но последние десять минут изменений в ней применять не будем?

Для начала про контролируемое отставание реплик. Такой запрос от пользователей был, и мы создали issue на Гитхабе с просьбой: «Если кому-то это надо, ставьте лайк, ставьте сердечко». Никто не поставил, и issue закрыли. Тем не менее, уже сейчас можно получить такую возможность, настроив 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, это не имеет значения. С Btrts всё зависит от вашего опыта её эксплуатации. Это зрелая файловая система, но всё равно возникают некоторые подозрения по поводу того, как всё отработает на практике в конкретном сценарии. Я бы не советовал это использовать, если у вас нет Btrfs в продакшне.


Какие сейчас лучшие практики в решардинге данных?

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

Если заканчивается место на кластере или он не справляется с нагрузкой, вы добавляете новые серверы. Но эти серверы по умолчанию пустые, данных на них нет, нагрузки никакой не идёт. Вам нужно переложить данные, чтобы они стали равномерно размазаны по новому, увеличенному в размерах, кластеру.

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

Перенос можно осуществлять только для тех партиций, которые не меняются при записи. Для свежих партиций запись придётся отключить, потому что их перенос не атомарный. Иначе вы получите дубликаты или пропуски в данных. Тем не менее, этот способ практичный и работает достаточно эффективно. По сети передаются уже готовые сжатые партиции, то есть данные не пережимаются и не перекодируются.

У этого способа есть один недостаток, и он зависит от схемы шардирования, закладывались ли вы на эту схему шардирования, какой у вас был ключ шардирования. В вашем примере для случая с метриками ключ шардирования — это хеш от пути. Когда у вас идёт select в Distributed таблицу, он идёт сразу на все шарды кластера и забирает оттуда данные.

Это значит, что фактически для вас не имеет значения, какие данные на каком шарде оказались. Главное то, что данные по одному пути оказываются на одном шарде, а вот каком именно, не принципиально. В этом случае перенос готовых партиций прекрасно подходит, потому что при запросах select вы тоже — что до перешардирования, что после, схема значения особо не имеет — будете получать полные данные.

Но бывают случаи и более сложные. Если на уровне логики приложения вы закладываетесь на специальную схему шардирования, что этот клиент расположен на таком-то шарде, и запрос можно отправить сразу туда, а не в Distributed таблицу. Или вы используете достаточно свежую версию ClickHouse и включили настройку optimize skip unused shards. В этом случае во время запроса select выражение в секции where будет проанализировано, и будет вычислено, на какие шарды необходимо пойти согласно схеме шардирования. Это работает при условии, что данные разложены именно в соответствии с этой схемой шардирования. Если вы их переложили вручную, соответствие может поменяться.

Итак, это способ номер один. И я жду вашего ответа, подходит способ, или идём дальше.

Владимир Колобаев, lead system administrator в Авито: Алексей, тот способ, который вы упомянули не очень хорошо ложится, когда надо размазать нагрузку в том числе и на чтение. Мы можем взять партицию, которая месячная и можем предыдущий месяц унести на другую ноду, но когда придёт запрос за этими данными, мы будем нагружать только её. А хотелось бы нагружать весь кластер, потому что, в противном случае, у нас какое-то время вся нагрузка на чтение будет обрабатываться двумя шардами.

Алексей Миловидов: Ответ тут странный — да, плохо, но может и прокатить. Объясню, как именно. Стоит посмотреть на сценарий нагрузки, который идёт за вашими данными. Если это данные мониторинга, то почти наверняка можно сказать, что подавляющее большинство запросов идёт за свежими данными.

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

Но зачастую у вас не будет запросов именно за февраль 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. Можете про неё рассказать?

Сразу скажу, что это решение более громоздкое и несколько менее производительное. Преимущество в том, что оно размазывает данные полностью согласно той схеме, которую вы укажете. Но недостаток утилиты в том, что она вовсе не делает перешардирование. Она копирует данные из одной схемы кластера в другую схему кластера.

Это значит, что для её работы у вас должно быть два кластера. Они могут быть расположены на одинаковых серверах, но, тем не менее, данные не будут перемещаться инкрементально, а будут скопированы.

Например, было четыре сервера, стало восемь. Вы создаёте на всех серверах новую Distributed таблицу, новые локальные таблицы и запускаете 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, потому что у разных людей разные деплои. Это многое упростит. Когда ты берёшь и за пять минут разворачиваешь кластер, гораздо проще пытаться в чём-то разобраться. Так гораздо удобнее, потому что катить в прод версию, которую ты не проверил — это путь в никуда. Иногда это работает, а иногда нет. И поэтому надеяться на успех — плохо.

Максим Котяков, senior backend engineer Авито: Немного дополню о тестовых средах из серии проблем больших компаний. У нас есть полноценный приёмочный кластер ClickHouse, по схемам данных и настройкам точная копия того, что есть в продакшне. Этот кластер развёрнут в достаточно жухлых контейнерах с минимумом ресурсов. Мы пишем туда некоторый процент от продакшн-данных, благо есть возможность отреплицировать в Кафке поток. Там всё синхронизировано и отскейлено — и по мощностям, и по потоку, и, в теории, при прочих равных должно по метрикам вести себя как продакшн. Всё потенциально взрывоопасное сперва катится на этот стенд и несколько дней там настаивается до готовности. Но естественно, это решение дорогое, тяжелое и с ненулевыми затратами на поддержку.

Алексей Миловидов: Расскажу, что представляет собой тестовая среда наших друзей из «Яндекс.Метрики». Один кластер был на 600 с чем-то серверов, другой на 360, и есть ещё третий и несколько кластеров. Тестовая среда для одного из них — это просто два шарда с двумя репликами в каждом. Почему два шарда? Чтобы был не один. И реплики тоже чтобы были. Просто некоторое минимальное количество, которое можно себе позволить.

Эта тестовая среда позволяет проверить работоспособность запросов и не сломалось ли что-то по-крупному. Но часто проблемы возникают совершенно другого характера, когда всё работает, но есть некоторые небольшие изменения с нагрузкой.

Приведу пример. Решили установить новую версию ClickHouse. Она выложена на тестовую среду, пройдены автоматизированные тесты в самой «Яндекс.Метрике», которые сравнивают данные на старой версии и на новой, прогоняя весь конвейер. И естественно, зелёные тесты нашего CI. Иначе бы мы даже не предложили эту версию.

Всё прекрасно. Начинаем катить в продакшн. Мне приходит сообщение, что на графиках нагрузка выросла в несколько раз. Мы откатываем версию. Я смотрю на график и вижу: нагрузка действительно выросла в несколько раз во время выкатки, и обратно уменьшилась, когда выкатили. Потом мы стали откатывать версию. И нагрузка точно так же увеличилась и точно так же обратно упала. Так что вывод такой — нагрузка выросла в связи с выкладкой, ничего удивительного.

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


Kill query должен убивать запросы, но он этого не делает. Почему?


Ко мне пришёл пользователь, какой-то аналитик, и создал некий запрос, который положил мой кластер ClickHouse. Какую-то ноду или кластер целиком — в зависимости от того, в какую реплику или шард запрос попал. Я вижу, что все ресурсы по CPU на этом сервере в полку, всё красное. При&nb

© Habrahabr.ru