---
title: "Четыре типа метрик: Counter, Gauge, Histogram, Summary"
description: "Типы метрик Prometheus: Counter, Gauge, Histogram и Summary. Разбираем, чем счётчик отличается от датчика, как читать бакеты и когда histogram лучше summary."
course: "Мониторинг Go с Prometheus: метрики, Grafana, алерты"
url: "https://golangmaster.ru/courses/prometheus/lessons/02-tipa-metrik/"
published: "2026-09-19"
updated: "2026-09-24"
minutes: 18
---

# Четыре типа метрик: Counter, Gauge, Histogram, Summary

*Курс «Мониторинг Go с Prometheus: метрики, Grafana, алерты», урок 2 из 25. ~18 минут. Обновлено 24.09.2026. Источник: https://golangmaster.ru/courses/prometheus/lessons/02-tipa-metrik/*

Типы метрик Prometheus — первое решение, которое принимается до строчки кода: Counter, Gauge, Histogram и Summary нельзя поменять местами задним числом, а неверный выбор рисует ложные графики. Разберём, за что отвечает каждый тип и как выбирать без ошибок.

Владелец магазина хочет знать две вещи: сколько всего заказов создано и сколько прямо сейчас висит в очереди на обработку. Числа похожи, но живут по разным законам: первое только растёт, второе ходит вверх и вниз. Если мерить оба одной метрикой, одна из двух историй будет врать. В Prometheus за эти два закона отвечают разные типы, и всего их четыре: Counter, Gauge, Histogram и Summary. Тип выбирается один раз: он вшивается в формат экспозиции — строку TYPE и суффиксы имён, — поэтому «сменить тип» на живой метрике нельзя; по факту вы заведёте новую метрику, а старые дашборды и алерты замолчат. Поэтому этот урок — про выбор, а код с типами Counter и Gauge пойдёт следом: в следующих двух уроках каждый из них получит свой разбор со всеми методами и ловушками.

### Типы метрик Prometheus: карта из четырёх сущностей

Counter — счётчик, который может только расти и сбрасывается в ноль при рестарте процесса: запросы, ошибки, обработанные байты. Gauge — датчик текущего значения, который двигается в обе стороны: длина очереди, занятая память, активные сессии. Histogram — распределение: каждое измерение падает в заранее заданные бакеты, из которых уже на стороне Prometheus считаются доли и перцентили — про латентность и размеры. Summary — второй способ считать квантили, но на стороне клиента: сервис сам агрегирует наблюдения и отдаёт готовые квантильные значения. Первые два типа — про «сколько всего» и «сколько сейчас», третий и четвёртый — про «как распределено». Типичный сервис на Go большую часть времени живёт на Counter и Histogram: рост и латентность — главные сигналы здоровья; Gauge добавляется под очереди и пулы, Summary — точечно. Дальше по карте — два самых ходовых типа в деталях, а гистограммы с summary получат собственные уроки после темы лейблов.

### Counter и Gauge: счётчик против датчика

Разницу удобно держать в голове через пару «пробег автомобиля» и «спидометр». Counter — пробег: число с запуска, убывать не может физически, даже когда события закончились, значение просто стоит на месте. Gauge — спидометр: сейчас сто двадцать, через минуту ноль, и оба показания честные. Отсюда рабочая проверка при выборе типа: спросите себя, что означает ноль. Для счётчика ошибок ноль — «с запуска ошибок не было», нормально. Для числа активных пользователей ноль — «прямо сейчас никто не онлайн», тоже нормально, но смысл другой: это состояние, а не накопление. Самая живая ловушка — рестарт: счётчик обнуляется, датчик начинает с того, что вы в него записали. Prometheus знает про поведение счётчика и в запросах умеет склеивать сбросы; датчику склейка не нужна — у него нет истории, есть момент. Итого: растущее — Counter, текущее состояние — Gauge, и никогда наоборот.

### Типичная ошибка: сырой счётчик на графике

Ошибка интерпретации, на которой я ловлю почти каждого новичка. Счётчик запросов рисуют сырым значением: линия ползёт вверх, после деплоя падает в ноль и снова растёт. Человек, привыкший к датчикам, читает это как «трафик упал до нуля и восстановился» — и начинается поиск аварии, которой не было. На деле провал в ноль — рестарт процесса, а скорость по такой линии на глаз не оценить: рост с тысячи до двух тысяч за сутки и за год выглядит одинаково круто. Правильная картинка — прирост: в PromQL это [rate](/courses/prometheus/lessons/12-promql-basics/), который сглаживает и сбросы, и рваный ритм событий. Пока PromQL не изучен, держите простое правило: сырое значение счётчика годится для лога, для графика — только скорость. Тот же принцип встретите у гистограмм: сырые бакеты там тоже никто не рисует, рисуют доли и квантили.

> **Проверка типа одним вопросом.** Когда тип спорит сам с собой, помогает вопрос к единице измерения: что будет, если сервис оставить в покое на час? Счётчик останется на месте — события кончились, накопление замерло. Датчик вернётся к естественному уровню: очередь разберут, сессии истекут, память отдаст сборщик мусора. Если значение само приходит в норму без вашего кода — это gauge; если оно навсегда хранит след прошлых событий — counter.

### Два типа рядом: как это выглядит в Go

```go
package main

import (
        "github.com/prometheus/client_golang/prometheus"
)

var (
        orders = prometheus.NewCounter(prometheus.CounterOpts{
                Name: "shop_orders_total",
                Help: "Всего созданных заказов.",
        })
        queue = prometheus.NewGauge(prometheus.GaugeOpts{
                Name: "shop_queue_size",
                Help: "Текущая длина очереди заказов.",
        })
)

func main() {
        prometheus.MustRegister(orders, queue)

        orders.Inc()   // +1 заказ
        queue.Set(17)  // в очереди сейчас 17
        queue.Dec()    // один заказ обработан
}
```

Counter создаётся через prometheus.NewCounter с CounterOpts, Gauge — через NewGauge с GaugeOpts; у обоих обязательны Name и Help. Методы разные по духу: у счётчика только Inc и Add с неотрицательным аргументом, у датчика — Set, Inc, Dec и Add с любым знаком. MustRegister регистрирует обе метрики в реестре по умолчанию. Полный разбор каждого типа — в двух следующих уроках.

### Четыре типа глазами формата экспозиции

```go
# HELP shop_orders_total Всего созданных заказов.
# TYPE shop_orders_total counter
shop_orders_total 812

# TYPE shop_queue_size gauge
shop_queue_size 17

# TYPE shop_request_duration_seconds histogram
shop_request_duration_seconds_bucket{le="0.1"} 240
shop_request_duration_seconds_bucket{le="0.5"} 380
shop_request_duration_seconds_bucket{le="+Inf"} 400
shop_request_duration_seconds_sum 92.1
shop_request_duration_seconds_count 400
```

Тип вшит в экспозицию: у counter суффикс _total, у gauge одна строка значения, у histogram — семейство _bucket с меткой le плюс _sum и _count. Строка TYPE объявляет тип до строк значений. Как устроены бакеты и метка le — разбор в седьмом уроке про гистограммы; summary вместо бакетов покажет строки вида quantile.

### Четыре типа метрик: сравнение по конструкции

| Тип | Закон изменения | Что мерить | Ключевые методы в Go |
| --- | --- | --- | --- |
| Counter | только вверх, сброс при рестарте | запросы, ошибки, байты | Inc, Add с неотрицательным |
| Gauge | вверх и вниз | очередь, память, сессии | Set, Inc, Dec, Add |
| Histogram | наблюдения в бакеты | латентность, размер ответа | Observe |
| Summary | квантили на клиенте | перцентили одного процесса | Observe |

### Histogram: латентность по бакетам

Гистограмма не хранит каждое измерение — это разорвало бы кардинальность. Вместо этого вы заранее задаёте бакеты, пороги времени: сто миллисекунд, двести, пятьсот, секунда, две, пять. Каждое наблюдение увеличивает счётчики бакетов, чей порог превышен: ответ за триста миллисекунд добавит единицу в бакеты пятьсот, секунду, две и пять. Плюс копятся сумма и число наблюдений. Красота схемы в том, что клиентская часть дёшево стоит, а математика происходит в Prometheus: из накопленных бакетов считается, какая доля запросов быстрее порога, и оцениваются перцентили — медиана и девяносто девятый. Цена — приближённость: значение p99 вычисляется по границам бакетов, и при плохом выборе порогов оценка плывёт. Зато гистограммы агрегируются между инстансами: суммировать бакеты двадцати подов — нормальная операция. Это делает histogram выбором по умолчанию для латентности HTTP — в седьмом уроке соберём её руками и подберём бакеты.

### Summary: квантили на стороне клиента

Summary решает ту же задачу, что гистограмма, но с другой стороны: сервис сам держит скользящее окно наблюдений и отдаёт готовые квантили — скажем, медиану и девяносто девятый перцентиль — просто числами. Плюс честный: значение квантиля точнее, чем оценка по бакетам, и пороги угадывать не надо. Минус один и жирный: квантили нельзя агрегировать. Медиана двух подов — не сумма медиан, и Prometheus не может собрать p99 по кластеру из summary двадцати инстансов; каждая метрика замыкается на своём процессе. Плюс окно квантилей зашито в конфигурацию клиента и не меняется на лету. Поэтому в типичном Go-сервисе summary занимает нишу точечных метрик одного процесса — скажем, латентность внутреннего вызова конкретного инстанса, — а для HTTP-латентности и всего, что надо смотреть по кластеру, выбирают histogram. Сравнение с кодом и выводами — в восьмом уроке, где оба типа лягут рядом.

### Спорное мнение: summary почти всегда лишний

Спорное мнение, к которому я пришёл после пары лет с квантилями: в прикладном Go-сервисе summary почти не нужен. Его честные аргументы — точный квантиль и отсутствие подбора сетки — звучат весомо, пока сервис один. Но практически каждый сервис, доживший до успеха, обрастает вторым инстансом: горизонтальное масштабирование, выкатка в два региона, canary-релиз. С этого момента клиентские квантили замыкаются в себе, рядом всё равно появляется [гистограмма](/courses/prometheus/lessons/07-histogram/), и два типа для одной величины содержать дороже, чем один. Граница, при которой я меняю мнение: фоновый процесс без горизонтального масштабирования и с тяжёлым, плохо предсказуемым хвостом — там summary с одной целью и окном MaxAge действительно проще, чем угадывать бакеты. Встроенный go_gc_duration_seconds к спору не относится: его писали не мы, и убрать его из реестра никто не просил.

> **Смена типа метрики — это новая метрика.** Тип вшивается в экспозицию: у счётчика строка TYPE counter и суффикс _total, у гистограммы — набор _bucket, _sum и _count. Поменять тип на живой метрике нельзя: старое имя перестанет существовать, графики лягут, алерты замолчат тихо, без ошибок. Я видел команду, которая за один вечер «переименовала» counter в gauge и неделю не замечала, что алерт по скорости запросов не срабатывает: условие смотрело на имя, которого больше не было. Если тип выбран неверно — заводите новую метрику и гасите старую по плану.

### Проверка: выбор типа

**Вопрос:** Нужно мерить число задач, которые прямо сейчас ждут обработки в очереди. Какой тип выбираете?

- Counter
- ✅ Gauge
- Histogram
- Summary

Очередь — текущее состояние: растёт и убывает, ноль означает «пусто». Это Gauge с методами Set, Inc и Dec. Счётчик не умеет убывать, а гистограмма отвечает на вопрос о распределении, а не о текущем размере.

### Проверка: закон Counter

**Вопрос:** Что произойдёт со значением Counter после перезапуска процесса?

- Продолжится с прежнего значения — клиент хранит счётчики на диске
- ✅ Обнулится, и Prometheus склеит сброс при расчёте rate()
- Счётчик исчезнет из экспозиции до первого Inc
- Метрика перейдёт в состояние down

Значение живёт в памяти процесса, рестарт сбрасывает его в ноль. Prometheus рассчитывает на это: запросы вроде rate умеют учитывать сбросы, и скорость считается корректно. Хранить счётчики на диске не нужно и не принято.

### Что покажет датчик после трёх операций

```go
queue.Set(42)
queue.Inc()
queue.Inc()
queue.Dec()
```

**Что выведет программа?**

- 44
- ✅ 43
- 42
- 45

Set задаёт абсолютное значение сорок два, дальше Inc прибавляет единицу дважды, Dec отнимает одну: сорок два плюс два минус один — сорок три. Датчик живёт последним значением, а история для Prometheus начинается с момента скрейпа.

### Законный и незаконный Add

```go
orders.Add(0.5)  // законно?
queue.Add(-3)    // законно?
```

**Что выведет программа?**

- ✅ Оба выполнятся: счётчик вырастет на половину, датчик уменьшится на три
- Первый упадёт: счётчик принимает только целые
- Второй упадёт: датчик не умеет убывать
- Оба упадут: метрики меняются только на единицу

Под капотом обе метрики — float64. Counter.Add принимает неотрицательные дроби: ползаказа — допустимая, хоть и странная, бухгалтерия; отрицательный аргумент у счётчика — паника, о ней подробно в уроке про Counter. Gauge.Add принимает любой знак — убывание его законный основной сценарий.

### Восстановите пару счётчик-датчик

Допишите типы в служебных строках экспозиции: у первой метрики счётчик, у второй — датчик.

```go
# HELP shop_orders_total Всего созданных заказов.
# TYPE shop_orders_total ___
shop_orders_total 812
# HELP shop_queue_size Текущая длина очереди.
# TYPE shop_queue_size ___
shop_queue_size 17
```

Подсказка: Растущая метрика объявляется counter, текущее состояние — gauge; обе строки TYPE пишутся строчными.

Правильные ответы в пропусках: `counter`, `gauge`

### Соберите экспозицию двух метрик

Расставьте строки экспозиции в правильном порядке: у каждой метрики сначала описание, потом тип, потом значение.

Правильный порядок строк:

1. `# HELP shop_queue_size Текущая длина очереди.`
2. `# TYPE shop_queue_size gauge`
3. `shop_queue_size 17`
4. `# HELP shop_orders_total Всего созданных заказов.`
5. `# TYPE shop_orders_total counter`
6. `shop_orders_total 812`

### Карточки: типы метрик

- **Counter** — Метрика только вверх: запросы, ошибки, байты. Методы Inc и Add с неотрицательным аргументом; при рестарте обнуляется, Prometheus склеивает сбросы в rate().
- **Gauge** — Датчик текущего значения: очередь, память, активные сессии. Set, Inc, Dec, Add с любым знаком; живёт последним записанным значением.
- **Histogram** — Распределение измерений по бакетам: Observe увеличивает пороги, Prometheus считает доли и перцентили. Агрегируется между инстансами.
- **Summary** — Квантили на стороне клиента: сервис сам отдаёт медиану и p99 числами. Точнее гистограммы, но квантили не агрегируются между инстансами.
- **Бакет** — Порог гистограммы: наблюдения копятся как счётчики «выше порога» с меткой le. От выбора бакетов зависит точность p99.
- **TYPE** — Строка формата экспозиции, объявляющая тип метрики: counter, gauge, histogram, summary. Смена типа — это заведение новой метрики.

Карта типов у вас в голове — время потрогать её руками. В следующем уроке ставим client_golang: go get, promhttp.Handler() и первая страница /metrics с бесплатными Go-метриками. Потом два урока-разбора: [счётчик](/courses/prometheus/lessons/04-counter/) со всеми методами и ловушками, включая обнуление при рестарте, и датчик с Set, Inc и Dec и правилом, почему растущее нельзя мерить gauge-ом. Гистограммы и summary получат свои уроки после лейблов. Примеры запускаются локальным Go: песочница не поднимает HTTP-сервер, поэтому держите под рукой терминал. Если ваш сервис уже живёт на фреймворке, всё то же самое работает и там — например, в [сервисе на gin](/courses/gin/) счётчики встают рядом с middleware без правок маршрутов; карта всех двадцати пяти тем — на [странице курса](/courses/prometheus/).

## Коротко: что запомнить

- Типов четыре: Counter растёт, Gauge живёт состоянием, Histogram копит бакеты, Summary считает квантили на клиенте.
- Тип вшивается в экспозицию и имена — смена типа равнозначна заведению новой метрики.
- Проверка выбора: ноль у счётчика — «не было с запуска», у датчика — «пусто сейчас».
- Histogram агрегируется между инстансами и оценивает p99 по бакетам; summary точнее, но не агрегируется.
- В Go: NewCounter и NewGauge с Name и Help, регистрация MustRegister, дальше Inc и Add против Set, Inc, Dec.
- Типичный сервис живёт на Counter и Histogram; Gauge — под очереди и пулы, Summary — точечно.

## Домашнее задание

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

## Вопросы и ответы по уроку

### Какой тип выбрать для времени ответа API?

Histogram по умолчанию: бакеты дёшевы на клиенте, а перцентили считаются на стороне Prometheus и агрегируются по кластеру. Summary имеет смысл для точечных метрик одного процесса, где агрегация не нужна.

### Можно ли измерять деньги счётчиком?

Да, Counter.Add принимает дроби: сумма выручки — классическая бизнес-метрика с суффиксом вроде _total. Важно лишь, чтобы значение не убывало: возвраты заводят отдельной метрикой, а не отрицательным Add.

### Что будет, если перепутать типы?

Графики либо бессмысленны, либо лгут: растущая величина в gauge не поддаётся анализу скорости, убывающая в counter паникует при попытке уменьшения. Тип меняется только заводом новой метрики.
