Files
clickstream-data-platform/infra/grafana/provisioning/dashboards/cluster.json
T
ddadmin 48bec014cf fix(monitoring): доводы приведены к замерам, пары нод больше не расходятся
- Зачем:
  - второй круг ревью нашёл, что текст спорит с собственной приёмкой: окно
    держалось доводом «слияния за минуту-две», а замер даёт двадцать секунд;
    довод панели ошибок опирался на отказ по памяти, которого ADR 0004 на этом
    стенде не обещает.
- Что:
  - «Части» сортируются по таблице: сортировка по числу частей разводила две
    ноды одной таблицы, как только между ними вставала чужая.
  - у «Слияний» столбик шириной в минуту, иначе редкие события выходили
    волосяной линией; из заголовка убран «слой» — фильтр отсекает журналы
    сервера, а не выбирает слои.
  - в cluster.md исправлены довод за окно, ложное «времени в system.parts нет»,
    счёт панелей без нод (их две, не одна) и разрешение, в котором снят замер
    процессора.
  - панель ошибок и её запись в ADR 0002 переписаны под проверенное: отказ на
    шарде воспроизведён принудительным пределом памяти.
  - из queries.md убран абзац про SELECT 1 — он объяснял пол удалённой панели.
- Проверка:
  - make config-test; make smoke 21/21; make check-clickhouse 10/10.
  - все десять панелей отвечают через /api/ds/query в окнах на полчаса, час и
    шесть часов; шаг столбика слияний проверен отдельным запросом.
2026-08-21 15:28:03 -04:00

319 lines
9.9 KiB
JSON

{
"uid": "cluster",
"title": "Кластер",
"timezone": "utc",
"schemaVersion": 42,
"refresh": "30s",
"time": {
"from": "now-30m",
"to": "now"
},
"panels": [
{
"type": "timeseries",
"title": "Процессор: сколько ядер занимает нода",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 0,
"y": 0
},
"options": {
"tooltip": {
"mode": "multi"
}
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"editorType": "sql",
"queryType": "timeseries",
"format": 0,
"rawSql": "SELECT\n $__timeInterval(event_time) AS t,\n hostName() AS node,\n -- Процессорное время самого сервера. Метрики с именами OS* сняты с машины\n -- целиком, и в них обе ноды показывали бы одно и то же число.\n sum(ProfileEvent_OSCPUVirtualTimeMicroseconds) / 1e6 / $__interval_s AS \"ядер\"\nFROM clusterAllReplicas('clickstream_cluster', system.metric_log)\nWHERE $__timeFilter(event_time)\nGROUP BY t, node\nORDER BY t, node"
}
],
"fieldConfig": {
"defaults": {
"displayName": "${__field.labels.node}",
"min": 0,
"decimals": 2
},
"overrides": []
}
},
{
"type": "timeseries",
"title": "Память: сколько нода занимает и сколько ей отведено",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 8,
"y": 0
},
"options": {
"tooltip": {
"mode": "multi"
}
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"editorType": "sql",
"queryType": "timeseries",
"format": 0,
"rawSql": "SELECT\n $__timeInterval(event_time) AS t,\n hostName() AS node,\n -- Занятое меряется резидентной памятью: именно её ядро сравнивает с\n -- пределом контейнера, когда решает, убить ли ноду.\n maxIf(value, metric = 'MemoryResident') AS \"занято\",\n maxIf(value, metric = 'CGroupMemoryTotal') AS \"отведено\"\nFROM clusterAllReplicas('clickstream_cluster', system.asynchronous_metric_log)\nWHERE $__timeFilter(event_time)\n AND metric IN ('MemoryResident', 'CGroupMemoryTotal')\nGROUP BY t, node\nORDER BY t, node"
}
],
"fieldConfig": {
"defaults": {
"displayName": "${__field.name} · ${__field.labels.node}",
"min": 0,
"unit": "bytes"
},
"overrides": [
{
"matcher": {
"id": "byRegexp",
"options": "отведено.*"
},
"properties": [
{
"id": "custom.lineStyle",
"value": {
"fill": "dash",
"dash": [
10,
10
]
}
},
{
"id": "custom.fillOpacity",
"value": 0
}
]
}
]
}
},
{
"type": "timeseries",
"title": "Диски: сколько нода читает и пишет",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 0
},
"options": {
"tooltip": {
"mode": "multi"
}
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"editorType": "sql",
"queryType": "timeseries",
"format": 0,
"rawSql": "SELECT\n $__timeInterval(event_time) AS t,\n hostName() AS node,\n -- Байты, прошедшие через обращения к файлам: чтение из страничного кэша\n -- тоже видно. Счётчики блочного устройства на вставке молчат.\n sum(ProfileEvent_OSReadChars) / $__interval_s AS \"чтение\",\n sum(ProfileEvent_OSWriteChars) / $__interval_s AS \"запись\"\nFROM clusterAllReplicas('clickstream_cluster', system.metric_log)\nWHERE $__timeFilter(event_time)\nGROUP BY t, node\nORDER BY t, node"
}
],
"fieldConfig": {
"defaults": {
"displayName": "${__field.name} · ${__field.labels.node}",
"min": 0,
"unit": "Bps"
},
"overrides": []
}
},
{
"type": "table",
"title": "Части: сколько их у таблицы и по сколько строк в каждой",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 8
},
"options": {},
"targets": [
{
"refId": "A",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"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 \"Таблица\", \"Нода\"\n"
}
],
"fieldConfig": {
"defaults": {},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "На диске"
},
"properties": [
{
"id": "unit",
"value": "bytes"
}
]
}
]
}
},
{
"type": "timeseries",
"title": "Слияния: сколько частей они съедают",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 8
},
"options": {
"tooltip": {
"mode": "multi"
}
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"editorType": "sql",
"queryType": "timeseries",
"format": 0,
"rawSql": "SELECT\n $__timeInterval(event_time) AS t,\n database AS db,\n sum(length(merged_from)) AS \"частей съедено\"\nFROM clusterAllReplicas('clickstream_cluster', system.part_log)\nWHERE $__timeFilter(event_time)\n AND event_type = 'MergeParts'\n AND database != 'system'\nGROUP BY t, db\nORDER BY t, db"
}
],
"fieldConfig": {
"defaults": {
"displayName": "${__field.labels.db}",
"min": 0,
"custom": {
"drawStyle": "bars",
"fillOpacity": 60,
"stacking": {
"mode": "normal"
}
}
},
"overrides": []
},
"interval": "1m"
},
{
"type": "timeseries",
"title": "Keeper: сколько узлов в дереве",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 7,
"w": 8,
"x": 0,
"y": 16
},
"options": {
"tooltip": {
"mode": "multi"
}
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"editorMode": "code",
"expr": "ClickHouseAsyncMetrics_KeeperZnodeCount",
"legendFormat": "узлов в дереве",
"range": true
}
],
"fieldConfig": {
"defaults": {
"min": 0
},
"overrides": []
}
},
{
"type": "table",
"title": "Распределённый DDL: что прошло по кластеру и чем кончилось",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"gridPos": {
"h": 7,
"w": 16,
"x": 8,
"y": 16
},
"options": {},
"targets": [
{
"refId": "A",
"datasource": {
"type": "grafana-clickhouse-datasource",
"uid": "clickhouse"
},
"editorType": "sql",
"queryType": "table",
"format": 1,
"rawSql": "SELECT\n query_create_time AS \"Создан\",\n entry AS \"Запись\",\n host AS \"Нода\",\n status AS \"Состояние\",\n query_duration_ms AS \"Заняло, мс\",\n exception_text AS \"Ошибка\",\n query AS \"Запрос\"\nFROM system.distributed_ddl_queue\nORDER BY entry DESC, \"Нода\"\nLIMIT 20"
}
],
"fieldConfig": {
"defaults": {},
"overrides": []
}
}
]
}