diff --git a/docs/adr/0002-monitoring-scope.md b/docs/adr/0002-monitoring-scope.md index 5bf6767..5256ad3 100644 --- a/docs/adr/0002-monitoring-scope.md +++ b/docs/adr/0002-monitoring-scope.md @@ -133,8 +133,11 @@ keeper, и обе ноды читают её целиком — запрос в посетителям продиктован [ADR 0007](0007-clickhouse-access.md): своя учётка Grafana заведена там ровно затем, чтобы её запросы были отличимы от человеческих. -Отдельная панель ошибок понадобилась под здешний же сюжет про тяжёлый -`GROUP BY`: отказ по памяти случается на шарде, и текст ошибки — единственное -место, где написано, на каком. Устройство обоих дашбордов — +Отдельная панель ошибок понадобилась потому, что отказ достаётся шарду: в +замере с принудительным пределом памяти каждая нода записала свой, и строка +шарда видна только без фильтра по инициатору. Здешний сюжет про тяжёлый +`GROUP BY` при этом кончается не отказом, а сбросом на диск +([ADR 0004](0004-resource-limits.md)) — отказ на стенде приходится вызывать +настройкой. Устройство обоих дашбордов — [cluster.md](../architecture/monitoring/cluster.md) и [queries.md](../architecture/monitoring/queries.md). diff --git a/docs/architecture/monitoring/cluster.md b/docs/architecture/monitoring/cluster.md index 69a263e..5fe9547 100644 --- a/docs/architecture/monitoring/cluster.md +++ b/docs/architecture/monitoring/cluster.md @@ -17,14 +17,17 @@ | Keeper | встроенные метрики keeper через Prometheus | | Распределённый DDL | `system.distributed_ddl_queue` | -Окно у дашборда — полчаса, обновление — полминуты, и это выбрано под нагрузку. -Вставка на стенде занимает секунды, а слияния разбирают её следы за минуту-две; -в часовом окне и подъём, и оседание схлопнулись бы в один столбик. Урок здесь — -форма кривой, и окно подобрано так, чтобы форма была видна. +Окно у дашборда — полчаса, обновление — полминуты. Пачка из +`make generate-batch` проходит за двадцать секунд, и на получасовой оси это +узкий всплеск в пару столбиков. Шире окно не берут, чтобы всплеск не выродился +в точку; уже — чтобы не промахнуться мимо него, заглянув через минуту, и чтобы +рядом осталось спокойное время: подъём читается только над полом. Кто хочет +разглядеть форму вплотную, растягивает окно мышью по самому всплеску. -Две панели окна не знают, и обе по делу. «Части» показывают состояние сейчас: -`system.parts` — опись живых частей, времени в ней нет вовсе. Очередь DDL -показывает последние двадцать записей: в спокойные полчаса она пуста, а пустая +Панель частей окна не знает вовсе. `system.parts` — опись живых частей, и +вопрос к ней про сейчас: колонки со временем в ней есть, но ни одна не годится +в ось. Очередь DDL окна тоже не знает, но по другой причине: она показывает +последние двадцать записей, потому что в спокойные полчаса пуста, а пустая панель ничего бы не рассказала. ## Обе ноды на одной панели @@ -35,11 +38,15 @@ Поэтому запросы идут через `clusterAllReplicas`, а `hostName()` подписывает, чья это строка. -Исключение одно — очередь распределённых DDL. Она лежит не у ноды, а в keeper, -и обе ноды читают из него одну и ту же очередь целиком, вместе со строками про -соседа. Обёртка здесь не добавила бы правды, а удвоила бы каждую строку. -Правило поэтому звучит так: `clusterAllReplicas` нужен там, где у каждой ноды -своя правда. +Исключений два, и они разной природы. Очередь распределённых DDL лежит не у +ноды, а в keeper, и обе ноды читают из него одну и ту же очередь целиком, +вместе со строками про соседа. Обёртка здесь не добавила бы правды, а удвоила +бы каждую строку — это единственная панель дашборда без неё. Правило поэтому +звучит так: `clusterAllReplicas` нужен там, где у каждой ноды своя правда. + +Второе исключение мягче. Панель слияний читает обе ноды той же обёрткой, но +складывает их в один ряд: шарды сливают симметрично, и разделение удвоило бы +легенду ради двух одинаковых кривых. ## Пол на графиках — журналы самого сервера @@ -53,16 +60,22 @@ ClickHouse ведёт около десятка собственных журн двух панелях читается как подъём над полом, а не как число само по себе. У частей и слияний пол отделим: в `system.parts` и `system.part_log` у каждой -строки написано, какой таблице она принадлежит. Обе панели поэтому спрашивают -только про слои стенда. Довод в размере: за спокойные полчаса слияния съели +строки написано, какой таблице она принадлежит. Обе панели поэтому показывают +всё, кроме журналов сервера, — и у каждой на это своя причина. + +Столбик у слияний шириной в минуту, а не в шаг панели. Слияния — события +редкие: на своём шаге столбик выродился бы в волосяную линию, и четыре события +за полчаса пришлось бы искать глазами. + +Слияниям фильтр иначе не пережить по размеру: за спокойные полчаса они съели 6 492 части в системных журналах против 219 в `ods` и `stg` вместе. Оставь мы журналы в кадре, ряды слоёв прижались бы к нулю, и панель рассказывала бы про -уборку за сервером вместо ваших вставок. Сколько эта уборка стоит, видно этажом -выше, на процессоре и дисках. +уборку за сервером вместо приехавших данных. Сколько эта уборка стоит, видно +этажом выше, на процессоре и дисках. -Слияния показаны по слоям, а не по нодам и не по таблицам. Шарды сливают -симметрично, и второй ряд на слой удвоил бы легенду, ничего не добавив. Какая -именно таблица держит части, отвечает соседняя панель. +Частям фильтр нужен для другого: без него в таблице десятки строк, а значит +нужен предел — и предел рвёт пару нод пополам, оставляя таблицу с одной нодой в +кадре. С фильтром помещаются все, и предел не нужен. ## Что именно меряют процессор, память и диски @@ -109,23 +122,27 @@ Keeper — отдельный сервис, системных таблиц у - Дашборд поднимается из каталога сам, все семь панелей отвечают через `/api/ds/query` в окне на полчаса. Пустых нет. -- Обе ноды видны на всех панелях по системным таблицам, кроме одной. Без - `clusterAllReplicas` осталась очередь DDL, и обёртка ей действительно не - нужна: запрос с ней вернул 124 записи с `clickhouse-01` и те же 124 с - `clickhouse-02`. -- Под нагрузкой. `make generate-batch` (50 626 событий одной пачкой): процессор - поднялся с 0,04–0,18 ядра до 0,54 и 0,64, запись — с 400 КиБ/с до 2,1 и - 4,5 МиБ/с. Следующие десять секунд обе величины уже вернулись к прежним: на - таком объёме подъём и оседание укладываются в полминуты. -- Слияния под той же нагрузкой отозвались столбиком: два слияния в `stg`, +- Обе ноды видны на четырёх панелях из пяти, что читают системные таблицы нод. + Пятая — слияния, там ноды сложены намеренно. Без `clusterAllReplicas` + осталась только очередь DDL, и обёртка ей действительно не нужна: запрос с + ней вернул с `clickhouse-01` и с `clickhouse-02` одно и то же число записей — + на день замера 124 и 124. +- Под нагрузкой. `make generate-batch` (50 626 событий одной пачкой), замер в + десятисекундных вёдрах: процессор поднялся с 0,04–0,18 ядра до 0,54 на одной + ноде и 0,64 на другой, запись — с 400 КиБ/с до 2,1 и 4,5 МиБ/с. Ведро тут + часть ответа: в тридцатисекундном тот же прогон даёт 0,29 и 0,21 ядра. + Следующие десять секунд обе величины уже вернулись к прежним: на таком объёме + подъём и оседание укладываются в полминуты. +- Слияния под той же нагрузкой отозвались столбиком в ряду `stg` высотой в 15 съеденных частей. - Блочное чтение действительно молчит: за минуту вокруг вставки `OSReadBytes` был нулевым в десяти десятисекундных окнах из четырнадцати, а обращения к файлам шли непрерывно во всех. - Память: около 1 ГиБ занятого против 4 ГиБ отведённого на каждой ноде. - Панель частей показала `ods.order_rep` по 142 строки в части против 13 046 у - `ods.event_rep` — заказы приезжают дневным слепком, события потоком. Все - таблицы слоёв поместились целиком, каждая обеими нодами: восемь строк. + `ods.event_rep` — заказы приезжают дневным слепком, события потоком. Строк + вышло восемь: четыре таблицы, каждая обеими нодами. Таблиц ошибок среди них + нет, и это правда состояния — частей у них пока не появилось. - Очередь DDL показала `CREATE MATERIALIZED VIEW ... ON CLUSTER` в состоянии `Finished` и со временем по каждой ноде: `make generate-batch` поднимает `clickhouse-init`, и тот заново прогоняет DDL. diff --git a/docs/architecture/monitoring/queries.md b/docs/architecture/monitoring/queries.md index 3db86fe..cb84e52 100644 --- a/docs/architecture/monitoring/queries.md +++ b/docs/architecture/monitoring/queries.md @@ -27,10 +27,6 @@ Grafana ходит в ClickHouse обычным пользователем, и остальное. Спрячь мы свои запросы фильтром — цена ушла бы с глаз, а панель «Кто спрашивает» недосчиталась бы самого частого посетителя. -Там же, в «Кто спрашивает», стоит `default` с сотнями запросов и одной -прочитанной строкой на каждый: это `SELECT 1` от проверки состояния -контейнера, она ходит к каждой ноде раз в несколько секунд. - Различать посетителей дашборд умеет потому, что у Grafana своя учётка со своей ролью ([ADR 0007](../../adr/0007-clickhouse-access.md)). Ходи она под аналитиком, панель «Кто спрашивает» показывала бы одну строку на всех. @@ -46,9 +42,11 @@ Grafana ходит в ClickHouse обычным пользователем, и считают только запросы инициатора: иначе один запрос человека выглядел бы тремя, а прочитанные строки сложились бы дважды. -Панель ошибок, наоборот, куски шардов показывает. Отказ по памяти случается -там, где считали, — на шарде; инициатор в своей строке передаст только текст -ошибки, а нода, на которой всё случилось, останется неназванной. +Панель ошибок, наоборот, куски шардов показывает: отказ случается там, где +считали, и строка шарда — единственное место, где эта нода названа. В замере с +принудительным пределом памяти `clickhouse-01` записал свой отказ, а +`clickhouse-02` — свой, и вторая строка видна только без фильтра по +инициатору. ## Пустой пользователь @@ -69,6 +67,10 @@ Grafana ходит в ClickHouse обычным пользователем, и - Ошибки видны и различаются по природе: отказ по правам (`bi` без `SELECT` на `ods`) и ошибка в тексте запроса (несуществующая колонка) легли в панель разными строками, каждая с полным текстом. +- Строка шарда в панели ошибок настоящая. Принудительный предел памяти на + распределённом `GROUP BY` дал две записи: `clickhouse-01` с + `is_initial_query = 1` и `clickhouse-02` с нулём. Вторая пропала бы, стой на + панели тот же фильтр, что на соседних. - Панель «Кто спрашивает» разделила шесть учёток — `grafana`, `analyst`, `etl`, `dict`, `bi`, `default` — и фоновую работу сервера. Больше всех прочитала `grafana`: 11,5 млн строк за час, своими же панелями. diff --git a/infra/grafana/provisioning/dashboards/cluster.json b/infra/grafana/provisioning/dashboards/cluster.json index 3e2ada0..0593e7d 100644 --- a/infra/grafana/provisioning/dashboards/cluster.json +++ b/infra/grafana/provisioning/dashboards/cluster.json @@ -176,7 +176,7 @@ "editorType": "sql", "queryType": "table", "format": 1, - "rawSql": "SELECT\n concat(database, '.', table) AS \"Таблица\",\n hostName() AS \"Нода\",\n count() AS \"Частей\",\n sum(rows) AS \"Строк\",\n round(sum(rows) / count()) AS \"Строк в части\",\n sum(bytes_on_disk) AS \"На диске\"\nFROM clusterAllReplicas('clickstream_cluster', system.parts)\nWHERE active\n AND database != 'system'\nGROUP BY \"Таблица\", \"Нода\"\nORDER BY \"Частей\" DESC, \"Таблица\", \"Нода\"\n" + "rawSql": "SELECT\n concat(database, '.', table) AS \"Таблица\",\n hostName() AS \"Нода\",\n count() AS \"Частей\",\n sum(rows) AS \"Строк\",\n round(sum(rows) / count()) AS \"Строк в части\",\n sum(bytes_on_disk) AS \"На диске\"\nFROM clusterAllReplicas('clickstream_cluster', system.parts)\nWHERE active\n AND database != 'system'\nGROUP BY \"Таблица\", \"Нода\"\nORDER BY \"Таблица\", \"Нода\"\n" } ], "fieldConfig": { @@ -199,7 +199,7 @@ }, { "type": "timeseries", - "title": "Слияния: сколько частей они съедают в каждом слое", + "title": "Слияния: сколько частей они съедают", "datasource": { "type": "grafana-clickhouse-datasource", "uid": "clickhouse" @@ -241,7 +241,8 @@ } }, "overrides": [] - } + }, + "interval": "1m" }, { "type": "timeseries",