ClickHouse 100% нагрузки на процессор улетает, уничтожая virtual server.

Сегодня при написании своего пет проекта я столкнулся с тем что ClickHouse по непонятной причине начинает деградировать понемногу по RAM, а потом уходит в 100% потребления процессора хотя у меня загрузка смешная: 1 инсерт в 15 секунд в датасет из 1 мегабайта таблицы MergeTree.

Оказалось что проблема в архитектуре ClickHouse, она не позволяет адекватно инсертить больше чем 1 раз в примерно 15 минут. Это попросту перегружает одноядерный сервер. Суть в том что в прошлом проекте у нас была более серьёзная нагрузка: при 3 инсертах в секунду у нас полностью деградировала VPS машина, уходя за примерно за неделю в тротлинг даже при 32 GB RAM, и 8 ядрах.

Эта проблема на самом деле называется Write Amplification, о котором почему-то мало где пишут в маркетинговых соевых постах восхваляющих ClickHouse:

"Users should avoid creating too many small inserts and too many small initial parts, respectively. As this creates (1) overhead on the creation of files, (2) increasing write amplification (leading to higher CPU and I/O usage), and (3) overhead on ClickHouse Keeper requests. These leads to degradation of ingestion performance in case of frequent small inserts due to high CPU and I/O usage overhead. Leaving fewer resources available for other operations like queries"

Источник: https://clickhouse.com/blog/common-getting-started-issues-with-clickhouse#many-small-inserts

Умники часто в issues отвечают что якобы попросту это решается увеличением мощности сервера, но на самом деле корень проблеме в логарифмическом росте сложности вычисления MergeTree помноженном на сложность при синхронных инсертах. Каждый инсерт тригерит полное перевычисление индекса, что создаёт гиганскую нагрузку на сервер. Что в итоге при казалось бы смешных 3 инсертах в секунду вызывает огромные проблемы у OLAP движка ClickHouse.

Решения лишь 1 - батчинг. А где батчить уже есть 3 варианта:

  1. На стороне клиента (храните гдето в очереди rabbitmq например, а потом пачкой пишите по крону)
  2. На стороне ClickHouse через async_insert
  3. На стороне ClickHouse через BufferEngine
Но важно отметить что ДАННЫЕ ПОКА НАХОДЯТСЯ В БУФФЕРЕ НЕ ИСПОЛЬЗУЮТСЯ ДЛЯ РЕСПОНСОВ. ОНИ ПРОСТО ВИСЯТ. То есть по факту вы можете буфферизировать хоть где, вы попросту через батчинг увеличиваете задержку между записью данных и получением свежих.

Конечно для многих задач достаточно и такого батчинга и толерантность к задержкам подобная может быть адекватной, но я окончательно убедился что OLAP это очень специфичная вещь и лучше сидеть в OLTP тк они решают 99% кейсов.


Комментарии

Популярные сообщения из этого блога

DOS атака при помощи Python

Как компилировать встроенные приложения gnome

TypeError: __init__() got an unexpected keyword argument 'decode'