Производительность
Окно батчинга: размер и время ожидания
Вы поднимаете linger.ms у Kafka-продюсера с 0 до 10 — и throughput взлетает в 10 раз ценой всего 10мс лишней латентности. Apache сделал тот же выбор за всех: в Kafka 4.0 (март 2025) дефолт linger.ms сменили с 0 на 5мс после многих лет на нуле. Аргумент команды был жёстким — погоня за немедленностью на стороне отправителя не даёт глобально низкую латентность. Крошечная искусственная задержка покупает эффективность батчинга, которая часто снижает сквозную латентность. Чтобы понять, почему задержка в 5мс делает систему быстрее, нужно разобрать двумерное окно под капотом.
Два триггера, а не одна ручка
У любой системы батчинга, которую вы будете тюнить, ровно два лимита: max-size (байты или число записей) и max-wait (таймер). Элементы копятся в буфере. Батч сбрасывается в тот миг, когда сработал любой из лимитов — буфер дорос до max-size или таймер дошёл до max-wait. Это OR, а не AND. В Kafka это batch.size и linger.ms; в Redis-пайплайнинге — буфер клиента и то, сколько вы даёте ему наполняться; в bulk-insert БД — строк на запрос и интервал сброса. Везде одна и та же форма.
Наивный инстинкт — выдать одну ручку («просто задай размер батча»), и каждый сеньор видел, как этот инстинкт поднимал кого-то в 3 ночи. Нужны обе, потому что у каждой в одиночку есть провал, который закрывает другая.
Почему один размер застревает, а одно время переполняет
Убери max-wait, оставь только max-size: теперь медленный продюсер берёт батч в заложники. Трафик проседает в 2 ночи, элементы капают, батч никогда не дорастает до batch.size и потому не сбрасывается. Первое сообщение полупустого батча может лежать секундами — неограниченная латентность, которая растёт обратно пропорционально нагрузке. Это классический head-of-line stall: лекарство — таймер, который говорит «шли что есть».
Убери max-size, оставь только max-wait: теперь быстрый продюсер собирает монстра. Прилетает Чёрная пятница, элементы хлынули, и за окно в 50мс буфер раздувается до того, что downstream не проглотит — запрос больше брокерского message.max.bytes, пакет фрагментируется, транзакция разносит WAL, массив роняет консьюмер по OOM. Лекарство — лимит размера, который говорит «шли, пока не разросся». Нужны обе, потому что они ломаются в противоположные стороны: размер защищает throughput, время защищает латентность, и убрав любую, вы возвращаете тот баг, который другая и закрывала.
| Режим нагрузки | Что срабатывает первым | Что это значит | Рычаг тюнинга |
|---|---|---|---|
| Высокая нагрузка | max-size (буфер наполняется первым) | Упёрлись в throughput; таймер не успевает | Поднять batch.size — меньше, но толще сбросы |
| Низкая нагрузка | max-wait (таймер срабатывает первым) | Упёрлись в латентность; батчи мелкие, доминирует таймер | Подстроить linger.ms под SLO латентности |
| Ровно на безубыточности | Любой, примерно вместе | Окно хорошо подогнано под текущий трафик | Оставить; перепроверить при смене формы трафика |
Математика ускорения, по шагам
Смоделируем любую операцию на элемент как фиксированную стоимость F (накладные на вызов — syscall, сетевой round-trip, begin/commit транзакции) плюс переменную стоимость V*n (работа пропорционально payload размера n). N элементов по отдельности стоят:
N * (F + V*n)
Те же элементы одним батчем платят фиксированную стоимость один раз и ту же переменную работу:
F + V*(N*n)
Ускорение — это отношение:
speedup = (N*F + N*V*n) / (F + V*N*n)
Смотрим на две крайности. Когда доминирует фиксированная стоимость — F > V*n, то есть маленькие payload, где накладные на вызов и есть вся история — член N*F забивает всё и speedup → N. Сбатчили 100 элементов — стали быстрее в ~100 раз. Когда доминирует переменная — F < V*n, большие payload, где вы и так платите в основном за байты — член V*N*n забивает всё и speedup → 1: батчинг не даёт ничего, потому что не было фиксированной стоимости для амортизации. Перелом, точка безубыточности — это F = V*n: когда переменная стоимость одного элемента равна фиксированным накладным, батчинг начинает окупаться.
Конкретное число
Возьмём сетевую операцию: пакеты по 1КБ, round-trip 50мкс на вызов как фиксированная стоимость и батч из 100 элементов. По одному round-trip’ы стоят 100 * 50мкс = 5мс. Батчем вы платите round-trip один раз плюс байты — пусть ~150мкс всего. Это 5мс до 150мкс, ~33x ускорение, потому что здесь F (RTT 50мкс) сильно перевешивает V*n (время передачи на КБ). Ровно в этом режиме живёт Redis-пайплайнинг: опубликованный бенчмарк шлёт 10 000 PING за 1.185с без пайплайна и за 0.250с с пайплайном — ~5x — и разрыв растёт по мере роста RTT относительно работы на команду. Версия с syscall-ами та же по духу: syscall стоит ~1–5мкс, поэтому схлопывание 300k syscall-ов в ~4k через большие буферизованные записи делает накладные на вызов фактически нулевыми.
Почему это работает
Заметьте: безубыточность — на элемент, а не на батч. Если payload одного элемента уже стоит больше фиксированных накладных (V*n > F), никакой размер батча вас не спасёт — вы прочно в режиме speedup → 1, и батчинг только добавляет латентность. Вот почему батчить крошечные сообщения (логи, метрики, лукапы по ключу) — огромный выигрыш, а батчить уже большие блобы (видео-чанки, большие загрузки файлов) — почти бессмысленно.
Нагрузка решает, какой триггер главный
Поведение окна не статично — оно смещается с трафиком. При высокой нагрузке элементы хлынули, и буфер достигает max-size задолго до таймера; размер — доминирующий триггер, вы упёрлись в throughput. При низкой нагрузке ручеёк не наполняет буфер, поэтому таймер срабатывает первым; доминирует время, вы упёрлись в латентность. Практическая диагностика: смотрите средний размер батча против заданного max-size. Если батчи стабильно сбрасываются у max-size — побеждает размер, поднимайте его. Если сбрасываются мелкими и по таймеру — побеждает время, и поднимать linger.ms помогает только пока батч не начнёт наполняться раньше истечения таймера.
Разбор живой системы: max-size 10000 байт, max-wait 5мс, и вы видите батчи в среднем 8000 байт каждые 4мс. Таймер срабатывает первым (4ms < 5ms), но буфер не полон (8000 < 10000) — умеренная нагрузка, доминирует время. Поднятие max-wait увеличит батчи и throughput, но только до точки, где буфер наполняется раньше таймера.
Расставьте по порядку, что происходит с одним элементом в окне батчинга «размер + время»:
- 1 Элемент приходит и дописывается в буфер в памяти
- 2 Система проверяет: довёл ли он буфер до max-size?
- 3 Если не полон — таймер max-wait продолжает идти для самого старого элемента буфера
- 4 Что достигнуто первым — полный буфер ИЛИ истёкший таймер — запускает сброс
- 5 Весь батч уходит одной операцией, платя фиксированную стоимость один раз
Разумные дефолты и как реально тюнить
Разумные стартовые точки — max-wait 10–100мс и max-size 64КБ–1МБ; high-throughput-рецепт Kafka — batch.size 64КБ–256КБ с linger.ms 20–100мс, а сбалансированный продакшен-конфиг вроде batch.size=32768, linger.ms=10, compression.type=lz4, acks=1 даёт ~25k msg/s при латентности под 20мс. Но дефолты — стартовая линия, а не ответ. Сеньорский ход — выводить ожидание из SLO латентности, а не из жажды максимального throughput: берите наибольший linger.ms, который терпит ваш бюджет p99, затем подбирайте буфер так, чтобы он наполнялся у этого таймера на пиковой ожидаемой нагрузке. Дальше — проверяйте так, как нельзя на доске: проигрывайте реальный продакшен-трафик в staging, прогоняйте обе ручки и читайте фактическое распределение размеров батча и хвостовую латентность. Синтетическая равномерная нагрузка врёт; продакшен бёрстовый, и только реплей покажет, какой триггер доминирует на вашей реальной форме трафика.
Ваша система батчинга использует только max-size (без таймера). Ночью трафик падает. Какой провал?
Для payload по 4КБ, где фиксированная стоимость вызова ~50мкс, а передача на КБ ~40мкс, даст ли большой батч сильное ускорение?
У сервиса подтверждения платежей строгий SLO p99 латентности 25мс, но на пике нужен и высокий throughput. Как настроить окно батчинга?
- 01Почему системе батчинга нужны одновременно лимит размера и лимит времени, и что ломается при удалении каждого?
- 02Выведите формулу ускорения и объясните, где она идёт к N, а где к 1.
- 03max-size=10000 байт, max-wait=5мс, наблюдаемые батчи в среднем 8000 байт каждые 4мс. Что это говорит и что менять?
Двумерное окно — max-size плюс max-wait — ядро любой системы батчинга, и два лимита это OR: что сработает первым, то и шлёт батч. Нужны оба, потому что они ломаются в противоположные стороны: только размер застревает на медленном продюсере (батч не наполняется, латентность не ограничена), а только время даёт быстрому продюсеру собрать батч слишком большой для downstream. Какой триггер сработал, ещё и диагностирует режим — доминирует размер значит упёрлись в throughput (высокая нагрузка), доминирует время значит упёрлись в латентность (низкая). Математика ускорения — (N*F + N*V*n) / (F + V*N*n): идёт к N, когда доминирует фиксированная стоимость (F > V*n, маленькие payload), и к 1, когда доминирует переменная (F < V*n, большие payload), с безубыточностью на элемент при F = V*n — пакеты 1КБ через RTT 50мкс батчем ~33x. Тюньте, выводя max-wait из SLO латентности, подбирая буфер под наполнение у этого таймера на пике, затем проверяйте реплеем продакшен-трафика в staging — а не погоней за максимальным throughput на доске.
встречается в260
- Почему GraphQL получает N+1junior
- Механика DataLoader: батчинг на границе тикаmiddle
- Контракты batch-функции: порядок, формы, ошибкиmiddle
- Federation и lookahead: батчинг за пределами DataLoadermiddle
- Защита сложности запросов: depth, cost, persisted queriesmiddle
- Senior GraphQL API: scheduling-контракт, изоляция арендаторов, наблюдаемостьsenior
- Путь запроса: семь остановок от сокета до ответаjunior
- Accept и парсинг: от очереди ядра до типизированного запросаmiddle
- Маршрутизация и middleware: что выполняется и в каком порядкеmiddle
- Обработчик и ответ: от бизнес-логики до байтов на проводеmiddle
- Стриминг и backpressure: когда клиент читает медленнее, чем вы пишетеsenior
- Таймауты и хвостовая задержка: бюджеты, дедлайны и ловушка fan-outsenior
- Middleware и DI: два паттерна, формирующие любой backendjunior
- Пишем middleware: сигнатуры, next() и три модели фреймворковmiddle
- Инверсия управления: как зависимости добираются до классаmiddle
- Скоупы и время жизни DI: singleton, request, transientmiddle
- DI как шов для тестов: фейки, моки и граница, которая важнаsenior
- DI-контейнеры в продакшене: графы разрешения, циклы и когда не стоитsenior
- Блокирующий vs неблокирующий I/O: два способа ждатьjunior
- Event loop: один поток, упорядоченные фазыmiddle
- Что блокирует цикл: CPU-работа и синхронные вызовыmiddle
- Вынос CPU-работы: worker threads и пул libuvmiddle
- Backpressure и ограниченная конкурентностьsenior
- Пропускная способность под нагрузкой: хвостовая задержка и насыщениеsenior
- Зачем пул: цена создания соединенияjunior
- Размер пула: почему больше не значит быстрееmiddle
- Взятие и таймауты: очередь ожидания — настоящий дроссель задержкиmiddle
- Зачем идемпотентность: безопасные retryjunior
- Серверный state machine: четыре состояния idempotency keymiddle
- Стратегии retry: backoff, jitter и thundering herdmiddle
- Outbox и inbox: effectively-once через dual-write границуmiddle
- Конкурентность и архитектура кеша для идемпотентности на масштабеsenior
- Наблюдаемость, production-инциденты и дизайн для глобального масштабаsenior
- Event loop: один поток, три очередиjunior
- Задачи, микрозадачи и scheduler.yield()middle
- Точность таймеров, троттлинг и фоновая работаmiddle
- Голодание микрозадач, длинные задачи и LoAFsenior
- Event loop Node.js: фазы, nextTick и задержка циклаsenior
- React, Vue и наблюдаемость INP в продакшенеsenior
- Render pipeline: шесть стадий от байтов до пикселейjunior
- Цена стадий и модель процесса рендерераmiddle
- Инвалидация, dirty-биты и containmiddle
- Слои композитора: продвижение, перекрытие и память GPUmiddle
- Флейм-стрип DevTools и жизненный цикл кадраmiddle
- Layout thrash: форсированная синхронная компоновкаsenior
- BeginMainFrame, анимации на потоке compositor и память GPUsenior
- Observability в проде: LoAF, INP и полная поверхность атакиsenior
- Что такое V8 и почему производительность различается в 100 разjunior
- Четырёхуровневый JIT-конвейер V8 и профилированная тиеризацияmiddle
- Hidden classes, деревья переходов и расположение в памятиmiddle
- Inline caches, состояния IC и деоптимизацияmiddle
- Orinoco GC: параллельный scavenger, конкурентная разметка и барьеры записиmiddle
- Спекулятивный движок TurboFan и ловушка deopt-loopsenior
- V8 в production: Isolates, сжатие указателей и реальные аварииsenior
- Жизненный цикл service worker и стратегии кешированияmiddle
- Граничные случаи service worker: version skew, долговременность и ловушка навигацииsenior
- Что делает реконсилер: render vs commitjunior
- Объект fiber и дерево с двойной буферизациейmiddle
- Чистота фазы render и подшаги фазы commitmiddle
- Реконсиляция: эвристики диффа и ловушка ключейmiddle
- Приоритетные lanes, time-slicing и useTransitionmiddle
- Bailout, мемоизация и tearingsenior
- React Profiler, компилятор и продакшн-наблюдаемостьsenior
- Стратегии рендеринга: SSG, SSR, ISR, streaming и гидратацияjunior
- SSG, SSR, ISR, streaming и RSC — как работает каждая стратегияmiddle
- Цена гидратации: selective, progressive, острова, resumabilitymiddle
- Hydration mismatch: причины, обнаружение и правило детерминизмаsenior
- RSC, стратегия на маршрут и production-наблюдаемостьsenior
- Core Web Vitals: что измеряют LCP, INP и CLSjunior
- LCP: четыре фазы, одна доминирующая стоимостьmiddle
- INP: input delay, processing, presentationmiddle
- CLS: почему происходят сдвиги лейаута и как их остановитьmiddle
- Lab vs field: почему они расходятся и как использовать каждыйmiddle
- Трейдоффы метрик, RUM-атрибуция и цикл CI+полеsenior
- Общая картина: от URL до LCP до INP как эстафетаjunior
- Восемь слоёв трассировки: от service worker до второй навигацииmiddle
- Пять канонических поломок: где производство стабильно ломаетсяsenior
- Метод трёх треков: чтение трасс и построение системы мониторингаsenior
- Что такое cache stampede и почему он делает всё хужеjunior
- Лок и single-flight: ограничение параллельных rebuildmiddle
- XFetch: вероятностное раннее истечение без координацииmiddle
- Stale-while-revalidate и CDN request coalescingmiddle
- Детектирование stampede и дизайн TTL для продакшенаmiddle
- Метастабильный сбой, fencing-токены и production-постмортемыsenior
- Что такое отношение: таблицы, строки, ключи и ограниченияjunior
- Ограничения, ключи и типы данных Postgresmiddle
- Нормальные формы, денормализация и почему схемы «прилипают»middle
- JSONB, массивы и когда side table побеждаетmiddle
- Heap-хранилище, TOAST и выравнивание колонокsenior
- Целостность схемы: deferral, версионирование и сбои в продакшнеsenior
- Реляционная модель vs документные, wide-column, граф и key-valuesenior
- Что такое индекс и как он ускоряет запросыjunior
- Leading-column rule: почему порядок столбцов в composite-индексе важенmiddle
- Partial, expression и covering-индексыmiddle
- Типы индексов: GIN, GiST, BRIN, Hash, Bloom и HOT-обновленияmiddle
- Index-only scan, Visibility Map и INCLUDEsenior
- Типичные сбои в продакшне и аудит индексовsenior
- Упражнение по проектированию индексов: стратегия полнотекстового поискаsenior
- EXPLAIN и планы выполнения: что решает планировщик и почемуjunior
- Типы сканирования: Seq, Index, Bitmap, Index-Onlymiddle
- Алгоритмы соединения и каскад ошибок оценки строкmiddle
- pg_statistic, ANALYZE и производственная наблюдаемостьmiddle
- Расширенная статистика: исправление ошибок оценки для коррелированных колонокsenior
- Кеш планов, настройка константных стоимостей и внутренности планировщикаsenior
- Производственные режимы отказа и стабильность плановsenior
- MVCC: как Postgres раздаёт согласованные снимкиjunior
- Заголовок tuple и механика снимковmiddle
- HOT-обновления и уровни изоляцииmiddle
- VACUUM, bloat и autovacuummiddle
- CLOG, XID wraparound и MultiXactsenior
- SSI и production-тюнинг autovacuumsenior
- Реальные провалы MVCC, deployment-паттерны и распределённые снимкиsenior
- Connection pool: зачем амортизировать стоимость backend Postgresjunior
- Режимы PgBouncer: session, transaction и statementmiddle
- Размер пула: формула (ядра × 2) + шпинделей и двухуровневый стекmiddle
- Исчерпание пула и idle-in-transaction: сценарий отказа в 3 ночиmiddle
- Миграция на transaction mode: план развёртывания и prepared statements в PgBouncer 1.21middle
- Процессная модель Postgres и почему увеличение max_connections снижает производительностьsenior
- Ландшафт пулеров 2026, serverless connection storms и полная таксономия отказовsenior
- Что такое миграция схемы и почему она заменяет ad-hoc DDLjunior
- ADD COLUMN: мгновенно в PG 11+ против перезаписи в старом Postgresjunior
- Режим отказа очереди блокировок: почему мгновенный DDL может заморозить базуmiddle
- Безопасные DDL-паттерны: NOT VALID, CONCURRENTLY и исправления небезопасных операцийmiddle
- Expand-contract: нулевой простой для ломающих изменений схемыmiddle
- Advisory-блокировки, инструменты миграций и координация деплояsenior
- Таксономия сбоев миграций и дисциплина продакшнаsenior
- Зачем нужно шардирование: потолок одного Postgresjunior
- Выбор ключа шарда: стратегии hash, range, list и directorymiddle
- Партиционирование против шардирования: одно слово, два разных понятияmiddle
- Ко-локация и Citus: инвариант, делающий шардирование пригодным к использованиюmiddle
- Режим отказа hot shard: обнаружение, изоляция и долгосрочная политикаmiddle
- Schema-based шардирование и альтернативы мультиарендностиsenior
- Онлайн-решардинг, 2PC и операционная стоимость шардированияsenior
- Семь актов: от CREATE TABLE до Citusjunior
- Акты 1–3 в глубину: схема, индексы и статистика планировщикаmiddle
- Акты 4–6 в глубину: MVCC bloat, connection pooling и безопасные миграцииmiddle
- Акт 7 в глубину: шардинг, co-location и семиуровневый каскад трейдоффовmiddle
- Наблюдаемость, антипаттерны и производственный триажsenior
- Роли Raft, term и почему majority-кворум предотвращает split brainjunior
- Как Raft реплицирует log entry и решает, что его безопасно коммититьmiddle
- Выборы лидера в Raft: таймауты, правила голосования и четыре свойства безопасностиmiddle
- Raft в реальном мире: partition, медленный диск и клиентская маршрутизацияmiddle
- Расширения Raft: pre-vote, learner, snapshot и линеаризуемые чтенияsenior
- Raft в production: membership change, Multi-Raft и observabilitysenior
- Где происходит data fetching — и почему это решает LCPjunior
- Fetch waterfall''''ы — диагностика и лечение через Promise.allmiddle
- React Server Components и Suspense streamingmiddle
- Клиентский кэш: TanStack Query, SWR и stale-while-revalidatemiddle
- LCP, prefetch и race conditions в интерактивном fetchingmiddle
- Senior internals: RSC payload, слои кэша и production паденияsenior
- Биты в проводеjunior
- Математика задержкиmiddle
- Bufferbloat и перегрузкаsenior
- Граница физического уровняsenior
- Трёхстороннее рукопожатие TCPjunior
- Номера последовательности и состояние соединенияmiddle
- Управление потоком и перегрузкойmiddle
- BBR, производственная наблюдаемость и за пределами TCPsenior
- DNS: что делает и зачем существуетjunior
- Обход резолвера: перенаправления, типы записей и gluemiddle
- TTL, кеширование и распространение DNSmiddle
- Рукопожатие за 1 RTT: key share и ECDHEmiddle
- Возобновление сессии и 0-RTTmiddle
- CDN: контент по соседствуjunior
- Anycast и GeoDNS: маршрутизация к ближайшему edgemiddle
- Многоуровневый кеш и Cache-Controlmiddle
- Заголовок Vary и cache keysmiddle
- Stale-while-revalidate и cache stampedesenior
- Edge workers и edge-side compositionsenior
- CDN: операции и observabilitysenior
- WebSocket: HTTP-апгрейд до постоянного соединенияjunior
- Формат WebSocket-фрейма: opcodes, маскирование, фрагментацияmiddle
- WebSocket vs SSE vs long-polling: выбор правильного транспортаmiddle
- Backpressure в WebSocket: когда клиенты не успеваютmiddle
- Реконнект: jittered backoff, thundering herd, восстановление сообщенийsenior
- WebSocket в масштабе: HTTP/2 мультиплексирование, permessage-deflate, C10Msenior
- WebSocket в production: прокси, безопасность и распределённая архитектураsenior
- Что делают обратные проксиjunior
- Алгоритмы балансировки: от round-robin до power-of-two-choicesmiddle
- L4 vs L7 балансировка и сохранение IP клиентаmiddle
- Health checks, connection draining и slow startmiddle
- Session affinity, consistent hashing и правильное решениеmiddle
- Retry-бури, circuit breakers и load sheddingsenior
- Устойчивая архитектура LB: anycast, zone-aware маршрутизация и observabilitysenior
- Почему QUIC, а не TCP+TLSjunior
- QUIC-потоки и head-of-line blockingjunior
- Объединённое рукопожатие и 1-RTTmiddle
- Connection ID и миграция сетиmiddle
- Обнаружение потерь и управление перегрузкойmiddle
- Возобновление 0-RTT и шифрование пакетовsenior
- Развёртывание и стоимость CPUsenior
- DDoS: что это и почему работаетjunior
- Атаки усиления и истощение состоянияmiddle
- Ограничение скорости: алгоритмы и архитектураmiddle
- WAF, межсетевые экраны, mTLS и HSTSmiddle
- Отравление DNS-кэша и BGP-перехватsenior
- Эшелонированная защита и экономика атакsenior
- Двенадцать слоёв: один URL, семь действующих лицjunior
- DNS, TCP, TLS по очереди: куда уходят миллисекундыmiddle
- Критический путь рендеринга и Core Web Vitalsmiddle
- Перехват прокси и шлюзы безопасности: rate limiter, WAF, mTLSmiddle
- Альтернативные пути: QUIC 0-RTT, WebSocket upgrade, миграция соединенияmiddle
- Наблюдаемость: распределённые трейсы, USE/RED и семплированиеsenior
- Устойчивость: каскадные повторы, circuit breakers и error budgetsenior
- Что такое три сигнала: метрики, логи, трейсыjunior
- Метрики и cardinality: cost-модель time-series databasemiddle
- Логи и объём: cost-модель структурного логированияmiddle
- Трейсы и сэмплирование: cost-модель distributed tracingmiddle
- Join-ключи и exemplar''''ы: как три сигнала становятся компонуемымиmiddle
- Observability 2.0: широкие события и сдвиг стоимостиsenior
- Режимы сбоя и инженерная практика: cardinality budget''''ы, PII и сэмплированиеsenior
- Зачем нужны структурные логи: дневник против таблицыjunior
- Схема продакшн-лога: поля, которые несёт каждая строкаmiddle
- Log levels и маршрутизация алертовmiddle
- Стратегии sampling и стоимость логовmiddle
- PII-редакция и log injectionsenior
- Propagation trace-контекста в логахsenior
- OTel Logs Data Model и audit-логи как подсистемаsenior
- Сигналы OTel, Semantic Conventions и проводной формат OTLPmiddle
- Авто-инструментирование и ручные спаны: правило 80/20 в OTelmiddle
- Collector OTel: receivers, processors, exporters и паттерны развёртыванияmiddle
- Стратегии сэмплирования: head, tail и parent-basedmiddle
- Vendor-нейтральность, eBPF-инструментирование, Operator и OTel в браузере и serverlesssenior
- Эксплуатация OTel Collector: надёжность, version skew, режимы отказа и управлениеsenior
- RED и USE: два чек-листа, одна дисциплина триажаjunior
- Инструментация RED в Prometheus: счётчики, гистограммы и дисциплина cardinalitymiddle
- USE на Linux: CPU, память, диск, сеть и PSImiddle
- Golden signals, структура дашборда и auto-RED в service meshmiddle
- Cardinality как драйвер затрат: label, PII, exemplars и семплированиеmiddle
- Native histograms, SLO и паттерны production-сбоевmiddle
- SLI, SLO и error budget: надёжность в числахjunior
- Выбор SLI и SLO-целей: отношения, не ощущенияmiddle
- Multi-window multi-burn-rate-алертинг: почему AND лучше ORmiddle
- Error budget policy, latency SLO и составные journeysmiddle
- Iceberg SLI, математика составного SLO и SLA vs SLOsenior
- Продакшн-отказы SLO, самонаблюдаемость, безопасность и общая картинаsenior
- Flame graph: читаем картинку, которая показывает, куда ушло времяjunior
- Sampling vs instrumentation profiling: почему 99 Гц побеждает в productionmiddle
- Типы профилей: CPU, память, off-CPU, mutex — какой когда братьmiddle
- Continuous profiling: always-on flame graphs с eBPF и корреляцией trace-idmiddle
- Как flame graph строится из сэмплов и как использовать его в productionmiddle
- Linux perf, внутренности eBPF, PGO и ограничения sampling''''аsenior
- Profiling в production: безопасность, war stories, OTel profiles и дизайн инфраструктурыsenior
- Debugging-воронка: SLO → RED → trace → profilejunior
- Архитектура OTel: один SDK, четыре сигнала, один wire-форматmiddle
- Экономия на observability: удерживаем затраты в пределах 5% inframiddle
- Петля инцидента: от пейджера до постмортема до предотвращенияmiddle
- Масштаб, безопасность и ROI наблюдаемых системsenior
- At-most-once, at-least-once, exactly-once: три контракта доставкиjunior
- Три ножки сбоя — где реально происходят дубликаты и потериmiddle
- Consumer-side dedup: самый дешёвый путь к exactly-once processingmiddle
- Kafka exactly-once semantics: idempotent producer и транзакцииmiddle
- SQS visibility timeout, DLQ и outbox patternmiddle
- Exactly-once в production: impossibility-доказательство, гибридные паттерны и реальные инцидентыsenior
- Что такое OAuth и почему пароли — не ответjunior
- Authorization code flow с PKCEmiddle
- Валидация ID-токена и управление JWKS-кешемmiddle
- Ротация refresh-токенов и scope-based least privilegemiddle
- Sender-constrained токены: DPoP и mTLSsenior
- OAuth в production: audience атаки, observability и реальные провалыsenior