СводкаГлавные показатели канала за выбранный период. Изменение — к такому же отрезку перед периодом, если за него есть статистика. Наведите на диаграмму плитки, чтобы увидеть число в каждой точке периода.
Главные числа
ПодписчикиСколько подписчиков у канала сейчас. Волна — число подписчиков в каждой точке периода. Изменение — к началу периода.2 173▲ 0,4 %+8 за период
ПросмотрыСколько сейчас просмотров у постов, вышедших за период. Это не просмотры за день: сколько посмотрели вчера, MAX не сообщает.213▼ 51,9 %было 472
РеакцииСколько реакций у постов, вышедших за период.5▲ 77,7 %было 3
УпоминанияСколько раз канал упомянули другие каналы: ссылки и репосты, без рекламных постов. Чем крупнее круг, тем больше упоминаний в этой точке периода.58▼ 18,3 %было 72по подписке
РепостыСколько раз другие каналы сделали репост постов этого канала (без рекламных постов). Репосты входят и в число упоминаний.26▼ 2,3 %было 27после входа
Средний охват постаСколько просмотров в среднем набирает один пост. Считаем по постам старше двух суток: у свежих просмотры ещё растут. Точки, где есть свежие посты, — пунктиром и полыми кружками: охват всех постов на сейчас, он ещё вырастет.213▼ 54,9 %было 472
ERRКакая доля подписчиков видит средний пост: средний охват ÷ подписчики × 100 %. Линия — ERR в каждой точке периода, пунктир — ERR прошлого такого же периода. Точки с постами моложе двух суток — полые кружки на пунктирном конце линии.9,8 %▼ 12,0 п. п.пунктир — было 21,8 %
Вовлечённость ERКак часто читатели реагируют на посты: реакции ÷ просмотры × 100 %. Засечка на полосе — прошлый период.2,35 %▲ 1,7 п. п.
было 0,64 %
Постов в деньСколько публикаций в среднем выходит за день. Клетка — точка периода: чем темнее, тем больше постов в день.0,1▲ 6,6 %было 0,1
Доля рекламыКакая доля публикаций за период похожа на рекламу: маркировка erid, рекламные ссылки и другие признаки. Шкала — рекламная нагрузка по порогам индекса качества: до 10 % — низкая, до 25 % — умеренная, до 50 % — высокая, дальше — очень высокая. Рост доли отмечается красным.2,5 %▼ 0,9 п. п.
ДинамикаСверху — число подписчиков на конец каждой точки периода, снизу — прирост за точку: зелёный — подписчиков стало больше, красный — меньше. Над графиком прироста — самый большой прирост и самая большая убыль. Сколько подписалось и отписалось по отдельности, MAX не сообщает.
Рост аудитории
+8подписчиков за период
+3 самый большой прирост · 23 окт 2026−1 самая большая убыль · 21 окт 2026
Оценка каналаОценка канала от 0 до 100 из пяти частей: аудитория, честность роста, рекламная нагрузка, доверие и достоверность расчёта. Полоса — сколько баллов часть набрала из своего максимума. Индекс пересчитывается каждую ночь; каналы сравниваются с похожими — той же категории и размера.
IT и программирование, 1–5 тыс. подписчиков · каналов в группе: 40
ОхватыСколько сейчас просмотров у постов, вышедших в каждой точке периода (а не просмотры за день). Подписан рекорд; точка с сегодняшним днём бледнее — день ещё идёт. Средний охват поста — по постам старше двух суток.
Просмотры и охват
213просмотров за период▼ 51,9 %
Средний охват поста — 213 просмотров (посты старше двух суток).
ВовлечённостьER — реакции, делённые на просмотры, в процентах — у постов каждой точки периода. Пунктир — ER за весь период. Изменение — в процентных пунктах к прошлому такому же периоду.
Вовлечённость подписчиков
2,35 %ER = реакции ÷ просмотры▲ 1,7 п. п.
ER каналав среднем за период
ЦитируемостьИндекс цитируемости (ИЦ) — насколько часто и какими каналами упоминают этот канал за последние 30 дней, без рекламных постов. Уровень — место среди похожих каналов. Линия — ИЦ в каждой точке периода (в неделе и месяце — средний за её дни).
РитмСколько постов в среднем выходит в каждый час каждого дня недели, время московское: чем темнее клетка, тем больше публикаций. «Лучшее время» — часы, в которые у постов старше двух суток самый высокий средний охват.
Когда и сколько публикует
ПнВтСрЧтПтСбВс
036912151821
Лучшее время:09:0018:00часы, в которые у постов самый высокий средний охват
ФорматыИз чего состоит лента. У каждого поста один формат — по старшинству: репост, видео, фото, ссылка, текст. Полоса и проценты — доля постов формата; справа — средний охват одного поста формата (по постам старше двух суток), полоска — сравнение с самым просматриваемым форматом.
ПубликацииКаждая точка — пост за период: по горизонтали — дата выхода, по вертикали — просмотры, размер точки — реакции, цвет — формат. Так видно хиты, провалы и то, как меняется охват. У крупных каналов показаны 100 самых просматриваемых постов и равномерная выборка остальных — не больше 1 500 точек.
Каждый пост — точка
Выше — больше просмотров, крупнее — больше реакций. Нажмите на точку, чтобы открыть пост.
ВидеоФотоДругоеразмер — реакцииПриближение — кнопками «+» и «−», щипком или Ctrl + колесо мыши; приближенный график сдвигается перетаскиванием
СводкаИтоги выбранного периода: сколько вышло публикаций, сколько у них сейчас просмотров и реакций и средний охват поста. Просмотры — текущие у постов, вышедших в эти дни, а не просмотры за день. Изменение — к такому же отрезку перед периодом, если за него есть статистика.
Итоги периода
Нажмите на показатель — ниже он появится по точкам периода
Просмотрысегодня — день ещё идётТочки с постами моложе двух суток — бледные с пунктиром: их просмотры ещё растут.
РекламаКакая доля публикаций за период похожа на рекламу: маркировка erid, рекламные ссылки и другие признаки. Детектор осторожный, поэтому настоящая доля обычно выше. Шкала — рекламная нагрузка по порогам индекса качества. Ниже — средний охват рекламного и обычного поста и кого рекламирует канал (сайты, на которые ведут ссылки из рекламы).
Что работаетПосты периода с наибольшим числом просмотров. Полоса — просмотры относительно первого места. Превью — картинка поста, у поста без картинки — аватар канала. Просмотры — сколько у поста сейчас.
РитмСколько постов вышло в каждый день периода (бледные столбики) и среднее за 7 дней (линия): видно, разгоняется канал или затихает. Сегодняшний день ещё идёт, поэтому среднее для него считается по вчерашний день.
Публикации по дням
Бледные столбики — дни, линия — среднее за 7 дней: видно, разгоняется канал или затихает
Публикации за деньСреднее за 7 дней
Данные обновлены в 13:35 по Москве. Просмотры — текущие у постов, вышедших в эти дни; средний охват — по постам старше двух суток.
Как считается индекс качества
🧠 Go Memory Model: Почему ваша горутина слепая (и что такое Happens-Before)
Напишем простейший код. Одна горутина меняет флаг, другая ждет этого изменения:
var done bool var msg string
func setup() { msg = "hello, world" done = true }
func main() { go setup()
// Ждем, пока setup() закончит работу for !done { }
fmt.Println(msg) }
Джун посмотрит на этот код и скажет: "Ну, он выведет hello, world". Сеньор посмотрит на этот код и скажет: "Этот код может уйти в бесконечный цикл, может вывести пустую строку, а может работать нормально. Это лотерея".
Добро пожаловать в жестокий мир Go Memory Model.
Иллюзия мгновенной памяти
Мы привыкли думать, что память - это единый монолит. Записал переменную - она тут же стала доступна всем. Но в реальности код выполняется на современных многоядерных процессорах. У каждого ядра есть свой сверхбыстрый локальный кэш (L1/L2).
Когда горутина setup пишет done = true, процессор может положить это значение в свой локальный кэш и не сбрасывать его в общую оперативную память (RAM) еще миллисекунды. А горутина main, работающая на другом ядре, будет бесконечно читать старое значение done == false из своего собственного кэша.
Но и это не всё! Компилятор Go невероятно умен. Он смотрит на цикл for !done {} и думает: "Внутри этого цикла переменная done не меняется. Зачем мне читать её из памяти на каждой итерации? Прочитаю один раз, сохраню в регистр процессора и буду проверять его". Итог - вечный цикл (Infinite Loop).
Святой Грааль: Happens-Before (Происходит-До)
Чтобы навести порядок в этом хаосе, создатели Go написали формальный документ - Модель Памяти (Memory Model). В её основе лежит концепция Happens-Before.
Если событие A происходит до события B, то Модель Памяти гарантирует, что горутина, выполняющая B, абсолютно точно увидит изменения, сделанные в A.
Если между действиями нет связи Happens-Before, компилятор и процессор имеют право переупорядочивать инструкции как им вздумается, а кэши могут не синхронизироваться.
Как создать связь Happens-Before?
Вам нужны примитивы синхронизации. Они работают как жесткие барьеры памяти (Memory Barriers), заставляя процессоры сбросить кэши, а компилятор - прекратить умничать с перестановкой строк кода.
✅ 1. Каналы (Channels) Отправка данных в канал происходит до завершения чтения из этого канала в другой горутине.
c := make(chan struct{}) go func() { msg = "hello" c <- struct{}{} // Happens-Before }() <-c // Ждем fmt.Println(msg) // 100% увидит "hello"
✅ 2. Мьютексы (Mutexes) Снятие блокировки mu.Unlock() происходит до успешного захвата mu.Lock() другой горутиной.
✅ 3. Атомики (sync/atomic) Начиная с Go 1.19, в Модель Памяти официально добавили пакет atomic. Атомарные операции теперь гарантированно создают связь Happens-Before.
✅ 4. Жизненный цикл горутины Создание горутины (go func()) происходит до начала выполнения её кода. А вот завершение горутины не имеет гарантий! (Именно поэтому нам нужен sync.WaitGroup, чтобы дождаться её финала).
🔥 Senior Tip: Не пытайтесь обмануть систему
Существует соблазн написать код, который работает "без блокировок", опираясь на задержки: time.Sleep(time.Millisecond). Это называется data race (состояние гонки). Даже если на вашей машине с процессором Intel код работает идеально, завтра его скомпилируют под ARM-архитектуру (Apple Silicon или AWS Graviton), у которой гораздо более слабая модель памяти процессора, и ваш код рассыплется в пыль.
Всегда используйте флаг -race во время локальной разработки и CI: go test -race ./.... Он ловит отсутствие связей Happens-Before с хирургической точностью.
🛑 Graceful Shutdown: Хватит обрывать запросы при деплое
Знакомая ситуация: вы катите новую версию микросервиса в Kubernetes, и в этот момент графики в Grafana на пару секунд краснеют от 502/503 ошибок. А потом всё снова хорошо.
Что произошло? Оркестратор убил старый под, а ваш Go-сервис моментально схлопнулся, оборвав на полуслове десятки текущих HTTP-запросов, сломав пару транзакций к базе и бросив недокачанные файлы.
Как это работает в здоровом проде? Когда Kubernetes хочет обновить под, он не стреляет ему в голову сразу. Он посылает вежливый сигнал SIGTERM и дает время (обычно 30 секунд), чтобы собрать вещи. Мы должны перехватить этот сигнал и сказать нашему HTTP-серверу: "Новые запросы не принимай, а те, что уже в работе - спокойно доделывай".
Как это написать: Забудьте про ручное создание make(chan os.Signal). Используйте signal.NotifyContext.
func main() { // 1. Создаем контекст, который отменится при SIGINT (Ctrl+C) или SIGTERM (Docker/K8s) ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop()
srv := &http.Server{Addr: ":8080", Handler: mux}
// 2. Запускаем сервер в отдельной горутине! go func() { // http.ErrServerClosed возвращается при успешном Shutdown, это не ошибка if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("Критическая ошибка сервера: %v", err) } }()
// 3. Блокируемся и ждем сигнала от ОС <-ctx.Done() log.Println("Получен сигнал завершения. Тушим свет...")
// 4. Создаем контекст с таймаутом для Shutdown shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel()
// 5. Плавно останавливаем сервер (ждет завершения текущих хендлеров) if err := srv.Shutdown(shutdownCtx); err != nil { log.Printf("Сервер не смог остановиться плавно: %v", err) }
// 6. Здесь закрываем коннекты к БД, RabbitMQ, сбрасываем кэши в Redis // db.Close()
log.Println("Сервер успешно завершил работу.") }
🔥 Нюансы для Senior-ов: • Обязательно ставьте таймаут на Shutdown(). Если клиент с медленным интернетом качает от вас гигабайтный файл, srv.Shutdown будет ждать его вечно. В итоге K8s устанет ждать свои 30 секунд и жестко убьет под через SIGKILL (kill -9). Контролируйте таймаут сами (Шаг 4).
• Порядок важен. Сначала останавливаем HTTP-сервер (чтобы перестали прилетать новые задачи), и только потом закрываем пул соединений с БД. Если сделать наоборот, текущие HTTP-запросы упадут с ошибкой sql: database is closed.
🐳 Идеальный Dockerfile для Go. Худеем с 800 МБ до 10 МБ
Знакомая картина: джун приносит микросервис, который делает пару запросов к БД, а Docker-образ весит под гигабайт. Почему? Потому что в FROM гордо красуется golang:latest.
Вместе с вашим кодом в продакшен уезжает весь тулчейн компилятора, операционная система, куча утилит (шелл, curl) и, как бонус, пачка потенциальных уязвимостей.
Прелесть Go в том, что он компилирует всё в один независимый бинарный файл. Нам не нужен Go в рантайме! Наш путь - Multi-stage builds (Многоэтапная сборка).
Вот "золотой стандарт" Dockerfile, который работает в 99% случаев:
# === Этап 1: Сборка (Builder) === FROM golang:1.22-alpine AS builder
WORKDIR /app
# Шаг 1: Кэшируем зависимости # Этот слой пересоберется ТОЛЬКО если изменились go.mod или go.sum COPY go.mod go.sum ./ RUN go mod download
# Шаг 2: Копируем код COPY . .
# Шаг 3: Собираем бинарник # CGO_ENABLED=0 - критически важно для статической линковки # -ldflags="-w -s" - вырезаем отладочную информацию RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /app/bin/service ./cmd/server/main.go
# === Этап 2: Финальный образ (Runner) === # Используем distroless вместо alpine или scratch FROM gcr.io/distroless/static-debian12:nonroot
WORKDIR /app
# Забираем только готовый бинарник из первого этапа COPY --from=builder /app/bin/service .
# Контейнер будет работать от непривилегированного пользователя USER nonroot:nonroot
EXPOSE 8080 ENTRYPOINT ["/app/service"]
Разбираем нюансы под капотом (Senior Edition):
• Зачем нужен CGO_ENABLED=0? По умолчанию Go может динамически линковаться с системными C-библиотеками (например, libc). Если вы соберете такой бинарник и положите в пустой образ, он упадет при старте. Отключая CGO, мы принудительно делаем статическую линковку - всё необходимое запекается прямо внутрь файла.
• Флаги -ldflags="-w -s": Они вырезают DWARF-таблицы и символы отладки. Это бесплатно срезает ~20-30% веса бинарника. Не переживайте, трейсы паник (stack traces) всё ещё будут показывать номера строк, так что для прода это безопасно.
• Почему distroless/static, а не scratch или alpine? * В scratch (абсолютно пустом образе) нет корневых сертификатов (ca-certificates). Как только ваш сервис попытается сделать внешний HTTPS-запрос, он упадет. Там также нет таймзон (tzdata). - В alpine есть sh (шелл) и пакетный менеджер apk - это векторы атаки для хакеров, если они найдут RCE в вашем коде. - Google Distroless содержит только сертификаты, таймзоны и юзера nonroot. Идеальный баланс микроскопического размера (~2 МБ) и безопасности.
У кого образы до сих пор весят больше 50 МБ - срочно переписывать!
🧠 Go Memory Model: Почему ваша горутина слепая (и что такое Happens-Before)
Напишем простейший код. Одна горутина меняет флаг, другая ждет этого изменения: var done bool var msg string
func setup() { msg = "hello, world" done = true }
func main() { go setup()
// Ждем, пока setup() закончит работу for !done { }
fmt.Println(msg) }
Джун посмотрит на этот код и скажет: "Ну, он выведет `hello, world`". Сеньор посмотрит на этот код и скажет: "Этот код может уйти в бесконечный цикл, может вывести пустую строку, а может работать нормально. Это лотерея".
Добро пожаловать в жестокий мир Go Memory Model.
Иллюзия мгновенной памяти
Мы привыкли думать, что память - это единый монолит. Записал переменную — она тут же стала доступна всем. Но в реальности код выполняется на современных многоядерных процессорах. У каждого ядра есть свой сверхбыстрый локальный кэш (L1/L2).
Когда горутина setup пишет done = true, процессор может положить это значение в свой локальный кэш и не сбрасывать его в общую оперативную память (RAM) еще миллисекунды. А горутина main, работающая на другом ядре, будет бесконечно читать старое значение done == false из своего собственного кэша.
Но и это не всё! Компилятор Go невероятно умен. Он смотрит на цикл for !done {} и думает: "Внутри этого цикла переменная done не меняется. Зачем мне читать её из памяти на каждой итерации? Прочитаю один раз, сохраню в регистр процессора и буду проверять его". Итог - вечный цикл (Infinite Loop).
Святой Грааль: Happens-Before (Происходит-До)
Чтобы навести порядок в этом хаосе, создатели Go написали формальный документ - Модель Памяти (Memory Model). В её основе лежит концепция Happens-Before.
> Если событие A происходит до события B, то Модель Памяти гарантирует, что горутина, выполняющая B, абсолютно точно увидит изменения, сделанные в A.
Если между действиями нет связи Happens-Before, компилятор и процессор имеют право переупорядочивать инструкции как им вздумается, а кэши могут не синхронизироваться.
Как создать связь Happens-Before?
Вам нужны примитивы синхронизации. Они работают как жесткие барьеры памяти (Memory Barriers), заставляя процессоры сбросить кэши, а компилятор - прекратить умничать с перестановкой строк кода.
✅ 1. Каналы (Channels) Отправка данных в канал происходит до завершения чтения из этого канала в другой горутине.
c := make(chan struct{}) go func() { msg = "hello" c <- struct{}{} // Happens-Before }() <-c // Ждем fmt.Println(msg) // 100% увидит "hello"
✅ 2. Мьютексы (Mutexes) Снятие блокировки mu.Unlock() происходит до успешного захвата mu.Lock() другой горутиной.
✅ 3. Атомики (sync/atomic) Начиная с Go 1.19, в Модель Памяти официально добавили пакет atomic. Атомарные операции теперь гарантированно создают связь Happens-Before.
✅ 4. Жизненный цикл горутины Создание горутины (go func()) происходит до начала выполнения её кода. А вот завершение горутины не имеет гарантий! (Именно поэтому нам нужен sync.WaitGroup, чтобы дождаться её финала).
🔥 Senior Tip: Не пытайтесь обмануть систему
Существует соблазн написать код, который работает "без блокировок", опираясь на задержки: time.Sleep(time.Millisecond). Это называется data race (состояние гонки). Даже если на вашей машине с процессором Intel код работает идеально, завтра его скомпилируют под ARM-архитектуру (Apple Silicon или AWS Graviton), у которой гораздо более слабая модель памяти процессора, и ваш код рассыплется в пыль.
Всегда используйте флаг -race во время локальной разработки и CI: go test -race ./.... Он ловит отсутствие связей Happens-Before с хирургической точностью.