Все публикации
Все материалы сайта в обратном хронологическом порядке
Базы данных
Эксплуатация Redis и карта выбора: когда он, а когда нет
Финал серии — про эксплуатацию Redis в бою и про трезвый выбор. Драйверы Go и Java и настройка пула соединений, что и как мониторить, типовые инциденты (latency-спайки, OOM, split-brain, шторм соединений) и их разбор. И главное — карта решений: когда Redis это правильный инструмент, а когда честнее взять полноценную БД, брокер или другое хранилище.
Архитектура
Rate limiting и throttling: защита системы от перегрузки
Как ограничивать нагрузку: token bucket, leaky bucket, sliding window, распределённый rate limiting и чем throttling отличается от отказа
Архитектура
Тестирование распределённых систем: уровни, границы, асинхронность
Юнит-тесты не поймают то, что ломается между сервисами: несовместимый контракт, потерянное сообщение, гонку в eventual consistency. Как выстроить уровни для распределённой системы — юнит → интеграция (Testcontainers) → контрактные тесты (вместо хрупких e2e) → немного e2e, где тест-дубли ставить на границах, и как тестировать асинхронность и eventual так, чтобы тесты не были флаки. Стратегия, а не набор фреймворков
Базы данных
Streams, Lua и функции: программируемость Redis
Redis умеет не только хранить, но и выполнять логику на сервере. Разбираем три способа программируемости: Streams с consumer groups (журнал сообщений с подтверждениями), Lua-скрипты и Redis Functions (атомарные серверные процедуры), плюс обзор модулей. Честно проводим границу Streams vs Kafka — где Redis Streams достаточно, а где нужна полноценная брокерная платформа.
Безопасность
Keycloak на практике: realms, clients, потоки, деплой
От решения к практике: разворачиваем Keycloak 26.7.0 (Quarkus) в docker-compose с внешним PostgreSQL, разбираем анатомию realm (confidential vs public clients, redirect URI, realm- и client-роли, группы, client scopes), потоки authorization code + PKCE и client credentials, получаем первый access-token curl-ом к token endpoint и читаем реальный декодированный JWT (iss, aud=backend, exp, realm_access.roles). Realm-as-code через kc.sh export/import вместо click-ops, token lifespans и protocol mappers ролей.
Архитектура
Тестирование в разных языках: пирамида, Testcontainers, property-based
Одна дисциплина — пирамида тестов, дублёры, property-based и реальные зависимости через Testcontainers — в Go, Java и Python на одном домене. Что идиоматично, чем различаются экосистемы и почему на настройках по умолчанию property-тест находит реальный дефект ненадёжно во всех трёх сразу
Безопасность
Свой auth или готовый IdP: когда брать Keycloak
Не «как настроить Keycloak», а решение на уровень выше: когда вообще стоит брать готовый IdP вместо своего auth. Реальная цена «сделай сам» (восемь пластов — сессии, refresh, OAuth-флоу, MFA, passkeys, федерация — каждый отдельный проект и зона риска), что закрывает Keycloak, рамка «бай vs билд» (self-hosted vs managed Auth0/Cognito), РФ-угол on-prem и честная ops-цена stateful-сервиса
Архитектура
Защита от перегрузки: карта
Перегрузка — это не одна проблема и не один механизм. Лимит частоты, backpressure, сброс нагрузки, предохранители, автоскейл и наблюдаемость решают разные части задачи и стоят на разных рубежах. Карта показывает, что за что отвечает, в каком порядке срабатывает и куда идти за деталями
Базы данных
Память и вытеснение: как Redis живёт под давлением памяти
Redis держит данные в оперативной памяти — значит, память рано или поздно закончится. Разбираем, что происходит на границе: как устроен аллокатор и откуда берётся фрагментация, какие есть политики вытеснения (LRU/LFU/по TTL/noeviction), что значит upper bound через maxmemory и что делает Redis при OOM. Плюс инструменты диагностики: MEMORY DOCTOR, INFO memory.
Сообщения
Сквозные гарантии и жизнь пайплайна
Каждое звено обещает своё, а отвечать приходится за цепочку целиком: как at-least-once складывается в effectively-once, где заканчивается транзакция Kafka, почему дедуп на стоке обязателен и как пайплайн переживает replay, эволюцию схемы и битые события
Базы данных
Репликация, Cluster и Sentinel: Redis как распределённая система
Один Redis — это одно ядро и один узел отказа. Разбираем, как из него собирают распределённую систему: асинхронная репликация, автоматический failover через Sentinel, шардирование по hash slots в Cluster. И честно про цену: асинхронность означает возможную потерю подтверждённых записей, split-brain реален, а Sentinel — не консенсус-протокол уровня Raft. Команда WAIT смещает границу, но не отменяет её.
Архитектура
Эволюция схемы: что ломается молча в Avro, Protobuf и JSON Schema
Девять изменений схемы через Avro, Protobuf и JSON Schema в двух направлениях, и три исхода вместо двух: прочиталось, отказ и — самый дорогой — прочиталось неверно. Одно изменение дало три разных операционных ответа: два декодера и реестр схем
Сообщения
Kafka Streams: обработка без кластера
Kafka Streams — не сервер, а библиотека внутри вашего сервиса: state store в RocksDB, changelog-топик как способ пережить падение, exactly-once в обработке. Что это даёт, чем за это платят и когда вместо неё всё-таки нужен Flink
Сообщения
Собираем пайплайн: PostgreSQL → Debezium → Kafka → ClickHouse
Сквозная цепочка от изменения в PostgreSQL до строки в витрине: Debezium как коннектор Kafka Connect, outbox event router, snapshot и переход в streaming, сток в ClickHouse. Не про механику WAL и не про внутренности Kafka — про то, как это собирается вместе и где проходят швы
Безопасность
TLS-фундамент: цепочка доверия, рукопожатие и что видно в трафике
Десять поломок цепочки доверия на четырёх клиентах: исход везде одинаковый, а различает их сказанное — openssl называет все шесть причин отказа, Go и Java по четыре. Плюс имя сервера открытым текстом в первом же пакете и честный счёт сообщений 1.2 против 1.3
Базы данных
WAL на службе: репликация, CDC и PITR
WAL как источник изменений: физическая репликация (стриминг WAL) против логической (декодирование в события), CDC через Debezium (чтение WAL/binlog/oplog), PITR через WAL archiving — и подводные камни: переполнение слотов, retention, идемпотентность потребителя
Архитектура
Зачем бинарный формат и что он стоит: JSON, Avro и Protobuf на весах
Сколько на самом деле стоит бинарный формат: вес записи, вес схемы и что остаётся от разницы под сжатием. Плюс проверка того, что нужно иметь на руках, чтобы данные вообще прочитались — и почему у контрольного плеча этот вес равен нулю
Базы данных
Шардирование на практике: цена распределённых данных
Разложить данные по узлам — самая простая часть. Дальше начинается счёт: запрос без ключа шардирования идёт во все шарды, join между по-разному распределёнными таблицами Citus по умолчанию вообще отказывается планировать, глубокая страница тащит с шардов сотни тысяч строк ради двадцати, а добавленный узел сам по себе не берёт на себя ни одного шарда. Всё — замерами на живом кластере Citus
Go
encoding/json/v2 в Go 1.27: вы уже переехали, не написав ни строки
encoding/json в Go 1.27 работает поверх нового движка v2 по умолчанию — обновивший тулчейн уже переехал, ничего не переписывая. На бенчах стенда это стоит decode в полтора-два раза дороже, а поведение при этом не меняется вовсе: строгость и выигрыш по аллокациям даёт только явный переход на encoding/json/v2 и потоковый jsontext.
Базы данных
Персистентность Redis: RDB, AOF и границы надёжности
Redis умеет переживать перезапуск — но насколько надёжно? Разбираем два механизма персистентности честно: RDB-снимки, AOF-журнал, гибридный режим и политики fsync. Главный вопрос статьи — что именно теряется при сбое и почему Redis по умолчанию ближе к кэшу, чем к источнику истины. Проводим границу durability явно, а не на ощущениях.
Go
Слайсы и карты в Go: внутренности и подводные камни
Слайс — это заголовок (указатель, длина, ёмкость) над общим backing-массивом, и отсюда растут коварные баги: append молча перезаписывает «соседа», nil и пустой слайс не одно и то же. Карты рандомизируют порядок обхода и роняют процесс при конкурентной записи. Разбираем внутренности и подводные камни на живых примерах
Базы данных
WAL и аналоги в разных БД
Один принцип write-ahead, разные реализации: PostgreSQL WAL, MySQL redo log плюс binlog (две роли), MongoDB journal и oplog, Tarantool WAL и snapshot, SQLite WAL-mode, Redis AOF и WAL в LSM-движках — что общего и чем различаются
Базы данных
Один поток и событийный цикл: откуда у Redis скорость
Redis обрабатывает команды в одном потоке — и при этом отдаёт сотни тысяч операций в секунду. Разбираем, почему single-threaded не значит медленно: событийный цикл, I/O-мультиплексирование, threaded I/O в новых версиях, пайплайнинг. И честно про обратную сторону: где один поток становится узким местом и откуда берётся хвостовая latency.
Go
Итераторы в Go: range-over-func и пакет iter
Go 1.23 разрешил range по функции: iter.Seq и iter.Seq2 — это функции-«пуш-итераторы», которые получают yield и вызывают его на каждом элементе. Как это работает под капотом, как писать свои итераторы, как связаны slices/maps-итераторы, ранний break и очистка — на живых примерах
Go
Goroutine leak profile в Go 1.27: ловим утечки горутин в проде
Go 1.27 добавил профиль утёкших горутин — он выделяет именно те, что навсегда заблокированы на примитиве синхронизации. Что новый профиль видит, чего не видят pprof/goroutine и goleak, на воспроизводимых классах утечек, и как встроить его в мониторинг.
Базы данных
WAL: как устроен и как повышает надёжность
Write-ahead logging как фундамент надёжности: сначала журнал, потом данные; durability и crash recovery (redo/undo), checkpoints, fsync и group commit — и во что обходится эта гарантия и что она покупает
Базы данных
Эксплуатация, драйверы и карта выбора «Mongo или Postgres?»
Драйверы Go и Java, change streams как источник CDC, бэкап и мониторинг MongoDB — и итоговая карта выбора между MongoDB, PostgreSQL и ScyllaDB по модели данных, масштабированию, консистентности и эксплуатации
Go
Обработка ошибок в Go: значения, обёртки, паники
Ошибки в Go — обычные значения, а не исключения: их возвращают, оборачивают через %w, проверяют errors.Is/As сквозь цепочку и объединяют errors.Join. Разбираем sentinel и типизированные ошибки, когда уместны panic/recover, и знаменитый баг «типизированный nil в error != nil»
Базы данных
Redis вглубь: структуры данных и их внутренние кодировки
Redis — не «строковый кэш», а сервер структур данных. Разбираем strings/hashes/lists/sets/zsets/streams и то, что скрыто под ними: внутренние кодировки (listpack, intset, skiplist, quicklist) и правила переключения между компактным и «большим» представлением. Честно: когда какая структура уместна и во что она обходится по памяти и по времени.
Базы данных
Sharding вживую
Hashed и ranged shard key, chunk splitting, balancer, роутинг через mongos, config servers, zone sharding, jumbo chunks и resharding — на живом шардированном кластере, с хотспотами и тем, как их ловить
Сообщения
Flink DataStream API: когда SQL мало
Flink SQL/Table API и DataStream — два API над общим runtime, и для оконных агрегатов с джойнами декларативного хватает. Но реакция по таймеру, произвольное состояние, корреляция двух потоков с кастомной логикой, обогащение через broadcast/async и маршрутизация в side output живут в Java-первом DataStream API. Где кончается SQL и что даёт спуск: KeyedProcessFunction, состояние руками, event-time vs processing-time таймеры, connect + CoProcessFunction
Go
Интерфейсы в Go: неявность, itab и ловушка nil
Интерфейсы в Go удовлетворяются неявно, состоят из пары (тип, значение) и потому таят знаменитую ловушку: интерфейс с типизированным nil внутри сам НЕ равен nil. Разбираем маленькие интерфейсы, «accept interfaces, return structs», внутреннее устройство (itab), type assertions/switch и почему nil-интерфейс — не то, чем кажется
Архитектура
Flaky-тесты: почему мигают и как чинить
Flaky-тест не «случайный» — у каждого мигания детерминированная причина: гонка, время, порядок выполнения, обход map, sleep вместо синхронизации. Разбираем пять классов на живом Go-стенде с реальной частотой мигания и настоящим детектором гонок, чиним каждый детерминизмом — а не ретраями
Базы данных
Replica sets, oplog и concerns
Выборы в replica set, механика oplog, read и write concern, causal consistency и живой failover — с контрастом к стриминговой и логической репликации PostgreSQL
Go
Память в Go: стек, куча и escape-анализ
Где живёт значение — на стеке или в куче — в Go решает не программист, а escape-анализ компилятора. Что уводит переменную в кучу (возврат указателя, боксинг в interface, захват замыканием), как это увидеть через go build -gcflags=-m, чем это грузит сборщик мусора и как проверять бенчами — на живом стенде с реальным выводом
Безопасность
Конвейер для недоверенных файлов: архитектура, а не флаг
Заключительная часть серии: как построить приём пользовательских файлов так, чтобы уязвимость в парсере осталась локальной неприятностью. Рабочий конвейер на стенде, где каждая граница изоляции проверяется отдельно от остальных — включая случай, когда проба показывала «разрешено» по совершенно неверной причине.
Сообщения
Flink SQL, коннекторы и эксплуатация: от Table API до прода
Писать Flink-джобы на низкоуровневом API нужно не всегда: Table API и Flink SQL закрывают большую часть задач декларативно, включая стриминговые джойны и агрегации. Плюс то, без чего не выйти в прод: коннекторы (Kafka, CDC, lakehouse), управление параллелизмом, диагностика backpressure, тюнинг чекпоинтов и апгрейд джобы через savepoint без потери состояния. Завершает погружение практикой эксплуатации
Go
reflect в Go: когда оправдана рефлексия и чего она стоит
reflect даёт доступ к типам и значениям в рантайме — на нём стоят encoding/json, ORM, валидаторы. Но за гибкость платят: потеря типобезопасности, аллокации и заметное замедление. Разбираем Type/Value/Kind, изменяемость через reflect, три закона рефлексии и её цену — на бенчмарках рефлексия против прямого доступа
Go
net/http вглубь: сервисы на стандартной библиотеке (и почему не gin)
Стандартный net/http после Go 1.22 (роутинг по методу и пути, path values) + middleware-функции покрывают большинство HTTP-сервисов без фреймворка. Разбираем ServeMux, middleware, таймауты сервера и клиента — и дуализм gin: почему он самый популярный и почему для долгоживущего сервиса стоит держаться ближе к stdlib
Сообщения
Состояние и exactly-once в Flink: checkpoints, savepoints, 2PC
Стрим-процессор без надёжного состояния бесполезен: агрегаты, джойны, дедуп — всё это состояние, которое нельзя потерять при падении. Как Flink это решает: keyed vs operator state, state backends (heap vs RocksDB для состояния больше памяти), распределённые снапшоты через барьеры (алгоритм Chandy-Lamport), инкрементальные checkpoints и savepoints для апгрейда, и exactly-once end-to-end через two-phase commit в стоки
Go
Отладка конкурентности в Go: race detector, утечки горутин, дедлоки
Как ловить конкурентные баги в Go: race detector по-настоящему (как читать отчёт, оверхед, место в CI), поиск утечек горутин через goleak и pprof, дедлоки и встроенный детектор, профили блокировок и мьютексов
Безопасность
Тихие отказы: сервис сломан, а логи чисты
Повреждение кучи, которое никто не заметил: процесс отработал с кодом 0, в логах пусто. На стенде измерено, кто и когда ловит запись за границей буфера и сколько это стоит. Главная находка практическая: debug-аллокатор glibc обнаружил все проверенные смещения начиная с одного байта, обошёлся в единицы раз дороже по времени без заметного роста RSS — но по умолчанию он выключен, и включить его можно так, что он не включится.
Базы данных
Aggregation pipeline вглубь
Стадии aggregation pipeline, цена $lookup как join, оптимизатор конвейера, allowDiskUse и лимиты памяти — с Go и Java клиентами на живых данных, в контрасте с SQL GROUP BY и JOIN
Go
Паттерны конкурентности в Go: pipeline, semaphore, errgroup, singleflight
Рабочие паттерны конкурентности в Go: pipeline с отменой и очисткой, fan-in/fan-out, worker pool с ограничением параллелизма, semaphore, errgroup, singleflight и батчинг — и когда паттерн лишний
Базы данных
Индексы в Mongo вглубь: multikey, ESR, explain
Multikey-индексы на массивах, правило ESR (Equality-Sort-Range), partial/TTL/wildcard-индексы и чтение explain() в MongoDB — специфика движка индексов поверх общей теории B-tree
Сообщения
Модель Flink: dataflow, event-time, watermarks и окна
Что делает Flink настоящим стрим-процессором, а не «циклом по сообщениям»: dataflow-граф операторов на JobManager/TaskManager, различие event-time и processing-time (и почему первое — единственно честное для аналитики потоков), watermarks как механизм «мы уже видели всё до момента T», окна (tumbling/sliding/session) и что делать с опоздавшими данными. Фундамент серии про Flink
Языки
Тьюринг-полнота и выразительность: чему учит brainfuck
Для чистых вычислений brainfuck покрывает тот же класс функций, что и Python, — все вычислимые по Тьюрингу, ни одной меньше. И при этом на нём ничего не пишут. Этот разрыв и есть тема: вычислительная мощность и выразительность — две разные оси, а мы их путаем, потому что обычные языки высоки по обеим. Brainfuck разводит их в чистом виде — и заодно объясняет, почему тьюринг-полнота в конфиге или системе типов чаще беда, чем достоинство
Безопасность
SBOM видит, сканер молчит: слепое пятно вендоренных зависимостей
Контролируемый эксперимент на живом стенде: один и тот же бинарник FFmpeg, упакованный под каноническим именем, получает 65 уязвимостей, а под вендорским — ноль. Разница только в имени пакета. Почему сканеры образов сопоставляют находки по идентичности компонента, а не по содержимому файла, что из-за этого пропускает Jellyfin, и как это чинить в своём конвейере.
Go
avo, генерация и честный замер: а стоило ли
Генерация Go-ассемблера через avo вместо ручного письма, честный замер наивного Go против рукописного AVX2 через benchstat и чек-лист «когда asm не нужен» — возврат к привратнику серии
Базы данных
WiredTiger: движок хранения вживую
WiredTiger — не LSM, а B-tree с MVCC: снапшоты, checkpoint, journal и кеш с dirty/eviction вживую, с контрастом к PostgreSQL heap+btree и разбором, где заканчивается WAL и начинается специфика Mongo
Безопасность
PixelSmash: как 50-килобайтный видеофайл в папке роняет ваш сервер
Разбор CVE-2026-8461: heap out-of-bounds write в декодере MagicYUV (FFmpeg/libavcodec) из-за рассинхронизации slice_height с chroma vertical subsampling. Срабатывает не от клика по видео, а от генерации превью в файловом менеджере или сканирования библиотеки медиасервера — фикс в FFmpeg 8.1.2, но кто реально уязвим к RCE, а кто просто падает, сильно разнится. Вывод — про изоляцию декодера как рубеж обороны, который не зависит от скорости патчей.
Go
Модель памяти Go: happens-before и почему гонки — это не «иногда»
Что на самом деле гарантирует модель памяти Go: отношение happens-before, публикация данных через каналы, мьютексы и атомики, переупорядочивание операций и почему гонка данных делает программу некорректной — модель памяти перестаёт давать нужные гарантии, а не просто «изредка возвращает неверное значение»
Архитектура
Идентификаторы в разных языках и БД
Как одна задача — сгенерировать UUIDv7/ULID/Snowflake — решается в Go, Java и Rust (и почему ops/sec между языками сравнивать нельзя), как типы колонок PostgreSQL (uuid/bytea/text) обходятся с этими значениями и как ::text-каст ломает индекс, и как согласовать идентификатор с ключом шардирования, чтобы монотонный ключ не устроил горячий узел.
Базы данных
Эксплуатация ScyllaDB: мониторинг, backup и когда она вообще нужна
Метрики, backup/restore через snapshot, Alternator как DynamoDB-совместимый API — и итоговый разбор, когда ScyllaDB оправдана, а когда это избыточная сложность
Go
Как писать свой asm: calling convention, ABI, две архитектуры
Как писать собственный Go-ассемблер: регистровый ABI (ABIInternal/ABI0), структура пакета со стабом и .s-файлами, рукописный AVX2 для dot product на amd64 и его перенос на arm64/NEON с обязательным pure-Go fallback
Go
Контекст в Go: отмена, дедлайны, values и анти-паттерны
context.Context — единый механизм отмены, дедлайнов и передачи request-scoped данных сквозь цепочку вызовов. Как отмена распространяется по дереву горутин, почему context идёт первым аргументом и не хранится в структуре, чем опасен WithValue и как не потерять отмену — на живом стенде
Go
Тестирование в Go: table-driven, Testcontainers, -race
Практичное тестирование Go-сервиса: стандартный пакет testing и table-driven как фундамент, httptest для хендлеров, интеграционные тесты через testcontainers-go на реальных Postgres и Redis, детектор гонок -race и честное покрытие без самообмана — на одном сквозном стенде с живыми замерами
Базы данных
Документная модель и схема-дизайн: против реляционного рефлекса
BSON, embedding против referencing, денормализация и рост документа — как проектировать схему MongoDB запросом вперёд, а не таблицами, и где документ честная альтернатива JSONB в PostgreSQL, а где нет
Базы данных
Идентификаторы и производительность: локальность, bloat, WAL
Случайный ID (UUIDv4) деградирует вставку в PostgreSQL: ниже плотность листьев B-tree, больше WAL, крупнее первичный индекс — измерено на стенде против bigint и монотонного UUIDv7. Плюс кросс-движковый разбор: миф «UUID-PK раздувает вторичные индексы» верен для MySQL/InnoDB и неверен для PostgreSQL; и когда монотонный ключ создаёт горячий шард (MongoDB ranged), а когда нет (ScyllaDB и Mongo hashed).
Базы данных
Shard-aware драйверы ScyllaDB: Go и Java на практике
Сколько реально даёт шард-осведомлённая маршрутизация в gocql и Java-драйвере, почему апстрим и форк ScyllaDB не могут сосуществовать в одном проекте, и как честно измерить эффект без JIT-искажений
Go
Пакет sync и атомики в Go: примитивы синхронизации на практике
Когда каналов мало: Mutex и RWMutex (и почему RW не всегда быстрее), Once, Cond, WaitGroup, sync.Map и sync.Pool, атомарные операции и их семантика — с честным разбором цены контеншена и false sharing
Архитектура
Saga на практике: компенсации, изоляция, идемпотентность, tooling
Концепция саги проста, а прод — нет: компенсация это не rollback, а обратное семантическое действие, и её порядок, идемпотентность и «а если компенсация упала» решают, работает система или разваливается. Плюс изоляция: сага даёт ACD, не ACID — грязные чтения и потерянные обновления реальны, и с ними борются семантическими локами и контрмерами. Разбираем классификацию шагов (compensatable/pivot/retriable), персистентность саги, tooling (Temporal/Camunda/Axon) и тестирование с инъекцией отказов
Go
Как читать: дизассемблер и Plan 9-синтаксис
Как читать чужой Go-ассемблер: go tool objdump и -gcflags=-S, Plan 9-синтаксис (порядок операндов, суффиксы размера, псевдорегистры FP/SB/SP/PC) и разбор дизасма наивного dot product — доказательство того, что компилятор не векторизовал цикл
Go
Конкурентность в Go: горутины, каналы и context без подводных камней
Как в Go на самом деле устроена конкурентность: дешёвые горутины и M:N-планировщик, каналы против мьютексов, context для отмены, рабочие паттерны (worker pool, fan-in/out, pipeline) и типичные подводные камни — гонки, утечки горутин и дедлоки
Базы данных
Выбор идентификатора: bigint, UUID, ULID, Snowflake
Идентификатор — проектное решение с отложенной ценой. Разбор bigint, UUIDv4, UUIDv7/ULID, Snowflake, ObjectId по осям, которые реально влияют на систему: кто генерирует, монотонность и сортируемость, размер ключа, что утекает наружу, вероятность коллизий. Главная ось — не «UUID или число», а случайный против монотонного; дерево выбора и разбор мифов.
Архитектура
CQRS на практике: проекции, rebuild, консистентность, tooling
Разделить чтение и запись — идея на слайде. На проде всё в проекциях: как строить read-модели, как жить с их отставанием (read-your-writes ломается), как пересобирать проекцию без даунтайма (blue-green, чекпоинты, идемпотентное применение) и когда CQRS оправдан без Event Sourcing, а когда тащит его за собой. Разбираем sync vs async проекции, несколько read-моделей на запрос, tooling (Axon/EventStoreDB/Marten) и типовую ошибку — CQRS поверх обычного CRUD
Базы данных
От token ring к tablets: репликация и multi-DC в ScyllaDB
Как устроено распределение данных — от классического token ring к tablets, как ведёт себя multi-DC репликация при отказе ДЦ и что происходит с tablets при decommission узла
Базы данных
Consistency levels и LWT в ScyllaDB: что реально стоит кворум и Paxos
Разница между ONE/QUORUM/ALL на живых числах, во сколько раз LWT дороже обычной записи и что происходит с CAS-операциями под конкуренцией
Go
Go assembly: зачем оно вообще и где живёт в stdlib
Зачем в Go может понадобиться ассемблер, где он реально работает в stdlib (crypto, math/bits, bytes.IndexByte, runtime) и почему в 99% случаев правильный ответ — не писать asm. Знакомство со сквозным примером серии — dot product для []float64
Сообщения
MirrorMaker 2 и геораспределённый Kafka: репликация между кластерами, DR, active-active
Один кластер Kafka живёт в одном дата-центре — а бизнесу нужны катастрофоустойчивость и присутствие в нескольких регионах. Разбираем два подхода: растянутый (stretch) кластер против репликации отдельных кластеров через MirrorMaker 2; что MM2 на самом деле переносит (топики, offset’ы, ACL, конфиги) и как работает трансляция offset при failover; топологии active-passive/active-active/hub-and-spoke; RPO/RTO, failover и failback; цена латентности и трафика между регионами. С живым стендом из двух KRaft-кластеров и MM2.
Базы данных
Compaction, tombstones и repair в ScyllaDB: жизненный цикл данных под капотом
Как TWCS группирует sstable по времени записи, почему исторический backfill без USING TIMESTAMP ломает окна компакции, как реально считаются tombstones и почему repair на tablet-keyspace — не nodetool repair -pr
Zig
Zig: место среди C, Rust и C++
Где на карте системных языков находится Zig: почему это замена C, а не конкурент Rust, что дают comptime и явные аллокаторы, чем силён C-interop и кросс-компиляция, и где Zig пока не стоит брать
Сообщения
Kafka-клиенты в разных языках: драйверы, родословные, различия
Клиент Kafka делает куда больше, чем «подключиться»: партиционирование, батчинг, сжатие, управление offset, ребаланс, идемпотентность, транзакции — и всё это разные библиотеки реализуют по-разному. Три родословные (референсный JVM-клиент, обёртки над librdkafka на C, чистые реализации протокола), почему у Go сразу несколько драйверов (franz-go/sarama/segmentio/confluent) и чем они отличаются, и что из этого следует для фич, производительности и деплоя. С живыми примерами produce/consume на Java, Go, Rust, Python, C#, C++, Scala
Rust
Тестирование в Rust: cargo test, proptest, mockall, Testcontainers
Тестирование Rust-сервиса на живом стенде: юниты рядом с кодом против чёрного ящика в tests/, doc-тесты как проверяемая документация и их реальная цена, property-based через proptest, mockall против фейка и Postgres в контейнере
Сообщения
Экосистема Kafka: Connect, Schema Registry, ksqlDB
Что вокруг брокера: Kafka Connect для интеграций без своего кода (source/sink, SMT), Schema Registry для эволюции схем (Avro/Protobuf/JSON Schema) и ksqlDB/streaming SQL — что брать из экосистемы, а что писать самому
Базы данных
Архитектура ScyllaDB: shard-per-core и почему это меняет правила игры
Как устройство shard-per-core (Seastar, без блокировок между ядрами) распределяет нагрузку по шардам, что это даёт в задержке и throughput — на живом 3-узловом кластере
Базы данных
ClickHouse, TimescaleDB, DuckDB: что выбрать под аналитику
Карта выбора аналитической БД по нишам: масштабная аналитика на ClickHouse, аналитика и time-series внутри экосистемы PostgreSQL на TimescaleDB, встроенная локальная аналитика на DuckDB — с учётом стоимости и эксплуатации
Сообщения
Эксплуатация Kafka: KRaft, мониторинг, тюнинг, обновление
Kafka в проде: KRaft (без ZooKeeper), ключевые метрики (consumer lag, under-replicated, latency), тюнинг producer и consumer, partition reassignment и rack awareness, rolling upgrade и квоты — продакшн-чеклист
Базы данных
Когда нужна ScyllaDB и как думать данными: моделирование под wide-column
Чем wide-column-модель отличается от реляционной, как проектировать партиции «запрос-первым», почему плохой ключ партиции убивает производительность — на живых числах ScyllaDB
Архитектура
Event Sourcing на практике: event store, проекции, снапшоты, replay
Концепцию Event Sourcing легко полюбить и трудно эксплуатировать: где хранить события (EventStoreDB vs Kafka vs Postgres), как строить и перестраивать проекции (read models), зачем снапшоты и как их делать, как реплеить историю, что такое upcasting при эволюции событий, оптимистичный конкаренси-контроль через expected version — и как жить с append-only, когда приходит GDPR-запрос на удаление
Базы данных
ClickHouse и S3: многоуровневое хранение и внешние данные
Две грани S3 в ClickHouse: многоуровневое хранение (hot/cold-тиринг MergeTree через storage policies и TTL MOVE на S3, separation of storage/compute) и S3 table function для запроса и загрузки Parquet прямо из объектного хранилища. С живым стендом на MinIO
Kubernetes
Работающий кластер ещё не значит восстановимый: четыре отказа при bootstrap Kubernetes на Talos
Разбор четырёх отказов, случившихся при развёртывании Talos-кластера с нуля: дедлок helm –wait, незеркалированный реестр, переехавший чарт-репозиторий и PROXY protocol без прокси. Ни один не виден на работающем кластере, три из четырёх сломали бы восстановление прода. С разбором ложных гипотез и границей доказанного.
Performance
22 минуты вместо двух: как контейнер на каждый тест съедал прогон — и что помогло
Интеграционные тесты Go-сервиса шли 22 минуты и случайно падали по таймауту — списывали на медленную машину. Причина оказалась арифметической: 266 вызовов тестового хелпера поднимали 266 контейнеров Postgres. Разбираем переход на один контейнер и CREATE DATABASE … TEMPLATE, замеры до и после (×10 и ×36), воспроизводимый стенд, границы приёма — права, FORCE, размер шаблона, параллельность пакетов — и честную границу между тем, что измерено, и тем, что осталось правдоподобной гипотезой
Архитектура
Что выбрать: матрица решений по событийным паттернам
Финальная карта серии: когда хватит CRUD с audit log, когда нужен Outbox, CQRS, Event Sourcing, Saga или Temporal — по осям границ, истории, длительности процесса и требований к согласованности
Базы данных
Эксплуатация и тюнинг ClickHouse: merges, mutations, мониторинг, backup
Что нужно знать про ClickHouse в проде: parts и фоновые merges, почему mutations (ALTER UPDATE/DELETE) дорогие и асинхронные, мониторинг через system.*-таблицы, backup/restore и тюнинг — codec-сжатие колонок, гранулярность индекса, память запроса. С живыми числами и продакшн-чеклистом
Сообщения
Exactly-once и транзакции в Kafka
Как Kafka даёт exactly-once: идемпотентный producer, транзакции с transactional.id, атомарный consume-process-produce через sendOffsetsToTransaction и consumer read_committed — и где граница EOS (внешние сайд-эффекты), которую закрывает outbox
Java
Reactive на JVM: Project Reactor, WebFlux и когда он больше не нужен
Reactive-стек на JVM после Loom: как работает Project Reactor и WebFlux, что даёт backpressure, и честный ответ на вопрос, когда virtual threads делают reactive ненужным, а когда нет
Базы данных
Распределённый ClickHouse: шардирование, репликация, Keeper
Как ClickHouse масштабируется горизонтально: шардирование и репликация через ClickHouse Keeper, ReplicatedMergeTree и Distributed-таблицы, что ломается при падении узла — реплика недоступна против шард недоступен. Живой кластер 2 шарда × 2 реплики
Сообщения
Хранение в Kafka: retention, log compaction, tiered storage
Как Kafka хранит и чистит данные: сегменты лога, retention по времени и размеру, log compaction для keyed-топиков (снимок последнего значения), tiered storage и сжатие — и когда compaction нужен, а когда обычный retention
Java
Messaging на JVM: Kafka-клиенты, Spring Kafka и надёжная доставка
Работа с Kafka из JVM: официальный клиент, Spring Kafka, гарантии доставки и идемпотентность, сериализация и schema registry — что важно кроме «отправить сообщение»
Performance
Go 1.20 и RSA: что на самом деле замедлилось — и как ловить регрессии производительности
В Go 1.20 crypto/rsa перешёл на constant-time bigmod ради защиты от тайминговых атак — и просел по скорости. Разбираем на живой матрице версий, где просело сильнее (спойлер: подпись подорожала на 34–61%, а публичные проверка и шифрование — в 5–7 раз), почему, что это значит для JWT, и как поставить CI-гейт, который ловит такие регрессии до прода
Базы данных
Материализованные представления и real-time агрегации в ClickHouse
Материализованные представления в ClickHouse как триггеры на вставку, предагрегация через AggregatingMergeTree и SummingMergeTree, чтение потока из Kafka через Kafka engine, TTL и ретеншн, проекции — как строить обновляемые в реальном времени агрегаты
Java
Тестирование на JVM: JUnit 5, Testcontainers, MockK и Mockito
Практичное тестирование JVM-сервиса: JUnit 5 как фундамент, интеграционные тесты на реальной инфраструктуре через Testcontainers, моки (Mockito/MockK) и где граница между unit и integration
Сообщения
Репликация и надёжность Kafka: ISR, acks, durability
Как Kafka не теряет сообщения: лидеры и фолловеры, ISR, acks (0/1/all), min.insync.replicas, unclean leader election и идемпотентный producer — и как одной неверной настройкой превратить надёжный кластер в дырявый
Базы данных
ClickHouse-драйверы: когда какой (ch-go, clickhouse-go, JDBC, HTTP)
Драйвер ClickHouse — половина производительности: низкоуровневый колоночный ch-go против эргономичного clickhouse-go (native и database/sql), clickhouse-java client-v2 против clickhouse-jdbc, и HTTP-интерфейс. Живой бенчмарк вставки и запроса, когда какой оправдан, карта выбора
Базы данных
Надёжная работа с PostgreSQL из Go, Java и Rust: пулы, реплики, reconnect
Надёжность работы с PostgreSQL из приложения: пулы соединений, timeout, reconnect, чтение с реплик, failover, pgbouncer и аналоги — на Go, Java и Rust
Java
Профилирование JVM: async-profiler, JFR и JMH
Как честно измерять производительность JVM: async-profiler и flamegraph, Java Flight Recorder для продакшена, JMH для микробенчмарков и типичные ловушки JIT-разогрева
Java
JVM в production: конфигурация, graceful shutdown, observability и GC
Production-дисциплина для JVM-сервиса: конфигурация из env, graceful shutdown под оркестратором, observability через OpenTelemetry/Micrometer и понимание GC — что настроить, чтобы сервис жил под нагрузкой
Java
Сборка и упаковка JVM: Gradle, GraalVM native и минимальные образы
Как собрать и упаковать JVM-сервис: Gradle (Kotlin DSL) vs Maven, fat-jar vs jlink-рантайм, GraalVM native image и минимальные Docker-образы — что реально влияет на старт, размер и память
Java
Доступ к данным на JVM: JDBC, JPA/Hibernate, jOOQ и Spring Data
Слои доступа к данным на JVM: сырой JDBC, ORM (JPA/Hibernate), типобезопасный SQL (jOOQ), Spring Data и Kotlin Exposed — что выбрать под задачу и где ORM создаёт больше проблем, чем решает
Сообщения
Consumer groups и ребалансировка в Kafka
Как Kafka масштабирует чтение: consumer groups и назначение партиций, стратегии (range/roundrobin/sticky/cooperative), протоколы ребаланса (eager против incremental cooperative), static membership, rebalance storms и коммит offset — где теряются или дублируются сообщения
Java
Конкурентность на JVM: virtual threads, корутины и reactive
Три модели конкурентности на JVM: virtual threads (Loom), корутины Kotlin и reactive (Project Reactor) — как они устроены, чем платят и когда какая уместна
Базы данных
Индексы и языки/ORM: зависимость и особенности
Зависят ли индексы от языка программирования и как ORM влияют на их использование: генерируемые запросы и N+1, неявные приведения типов, prepared statements и план, миграции индексов и как из кода проверить, что индекс реально работает
Базы данных
ClickHouse из Go и Java: MergeTree, вставки и запросы
Как устроено семейство MergeTree (ORDER BY, PRIMARY KEY, партиционирование), почему в ClickHouse нельзя вставлять по одной строке и что дают async inserts, и как всё это выглядит из клиентов clickhouse-go и clickhouse-java — нативный протокол против HTTP
Java
Spring Boot вглубь: DI, стартеры, конфигурация и actuator
Как устроен Spring Boot под капотом: контейнер и DI, автоконфигурация и стартеры, профили и внешняя конфигурация, actuator для наблюдаемости — и где «магия» мешает контролю
Сообщения
Kafka: лог, топики, партиции — ментальная модель
Kafka — это распределённый лог, а не очередь: топики и партиции, offset, producer и consumer, как ключ определяет партицию и порядок, зачем репликация. Вводная серии «Kafka вглубь»: правильная ментальная модель и когда Kafka уместен, а когда нет
Архитектура
Надёжность распределённых систем: карта
Навигатор по надёжности распределённых систем: консенсус, согласованность, атомарность и транзакции, гарантии доставки сообщений и устойчивость под нагрузкой — как это связано и в каком порядке разбираться
Java
Kotlin для backend: null-safety, корутины и Ktor
Kotlin как backend-язык на JVM: null-safety на уровне типов, корутины и structured concurrency, DSL и фреймворк Ktor — где Kotlin реально выигрывает у Java и где это вопрос вкуса
Базы данных
Когда нужен OLAP: ClickHouse против PostgreSQL для аналитики
Чем OLAP-нагрузка отличается от OLTP, как колоночное хранение и векторное исполнение делают ClickHouse быстрым на аналитике, в какой момент PostgreSQL перестаёт тянуть агрегаты по большим таблицам — и где ClickHouse категорически не подходит
Базы данных
Паттерны и антипаттерны индексирования
Что делать и чего избегать с индексами: over-indexing и write-amplification, неиспользуемые и дублирующие индексы, bloat и обслуживание, covering под горячие запросы, online-создание без блокировок, индексы под пагинацию — и антипаттерн «индекс на всё»
Java
Современная Java: records, sealed-классы, pattern matching и virtual threads
Как изменился язык Java к 2026: records и sealed-классы, pattern matching для switch, текстовые блоки и virtual threads (Project Loom) — что из этого реально меняет стиль backend-кода
Базы данных
Мульти-хранилищный стенд: один сценарий по всем БД и карта выбора
Финал серии: единый сценарий (списание с инвариантом «баланс не в минус») реализован поверх PostgreSQL, Redis, MongoDB и ScyllaDB и прогнан одним нагрузчиком. Что каждая система гарантирует из коробки, что ломается под конкуренцией, цена корректности — и итоговая карта выбора
Базы данных
Индексы в разных БД: PostgreSQL, MongoDB, Tarantool
Один принцип, разные реализации: индексы в PostgreSQL (btree/GiN/GiST/BRIN, CONCURRENTLY, partial/expression), MongoDB (compound/multikey/text/2dsphere/TTL/partial/wildcard, правило ESR) и Tarantool (memtx TREE/HASH/BITSET/RTREE и vinyl LSM)
Базы данных
Брокеры и стриминг: транзакции в очереди и логе — RabbitMQ и Kafka
Что значит «транзакция» в брокере: AMQP-транзакции RabbitMQ против publisher confirms, транзакционный producer и exactly-once в Kafka, consume-process-produce и read_committed, границы EOS и outbox-паттерн как мост к БД. Примеры на Go и Java
Базы данных
Как выбирать и использовать индексы
Практика индексов: селективность и кардинальность, покрывающие индексы и index-only scan, составные индексы и порядок колонок, частичные и функциональные, и главное — почему индекс НЕ используется и как это увидеть
Сообщения
Messaging: выбрать и эксплуатировать — карта
Навигатор по messaging: как выбрать брокер (очередь vs лог vs шина), какие гарантии доставки бывают, как эксплуатировать кластер и как обрабатывать потоки данных — с картой всех статей по теме
Performance
Вероятностные структуры: Bloom-фильтры и компания — когда эффективны, когда нет
Bloom-фильтры, Cuckoo, HyperLogLog, Count-Min Sketch и родственники: как они экономят память и время ценой приблизительности, где реально эффективны (LSM-БД, кэш/CDN, дедупликация, аналитика уникальных), а где только вредят — с прикидкой параметров и примерами на Go и Java
Базы данных
KV и документные: «транзакций» почти нет — Redis, MongoDB, ScyllaDB
Что означает «транзакция» там, где нет классического ACID-движка: Redis MULTI/EXEC без rollback и WATCH-CAS, multi-document транзакции MongoDB поверх snapshot, LWT на Paxos в ScyllaDB и почему BATCH — это не транзакция. Примеры на Go и Java
Базы данных
Транзакции в реляционных БД на практике: PostgreSQL, изоляция и нагрузочный стенд
PostgreSQL как эталон управляемой изоляции: уровни в деле, SELECT FOR UPDATE, SERIALIZABLE с retry на 40001, advisory locks. Примеры на Go (pgx) и Java (JDBC) плюс нагрузочный стенд, воспроизводящий lost update и write skew под конкуренцией
Базы данных
Индексы в БД: зачем нужны, какие бывают и как устроены
Фундамент про индексы: зачем они (ускорение поиска ценой записи и места), какие бывают — B-tree, hash, bitmap, инвертированный (GiN), GiST, BRIN, R-tree, LSM — и как каждая структура устроена, что ускоряет и чем платит
Безопасность
Сканирование уязвимых зависимостей (SCA): Dependabot, osv-scanner, govulncheck
SCA на практике: почему Dependabot показывал 0, а osv-scanner нашёл полсотни; чем различаются базы advisory (GitHub Advisory, OSV, Go vuln DB, RustSec) и методы (presence-based против call-graph govulncheck); плейбук починки транзитивных CVE по экосистемам (Go, Maven, Python, Rust) и честная работа с no-fix и ложными срабатываниями
Архитектура
Consensus Landscape: тур по алгоритмам консенсуса через симулятор
Флагманский тур по ландшафту консенсуса: осваиваем Raft, Paxos, Zab и EPaxos, воспроизводя перевыборы, сетевые партиции и цену latency в интерактивном симуляторе.
Безопасность
Bubblewrap: песочница для недоверенного кода без root
Как запускать недоверенный бинарник, скрипт или сборку в песочнице без root с помощью Bubblewrap, что он изолирует, а что нет, и когда bwrap уместнее Docker, Podman или Firejail
Go
Go modules: go.mod, версионирование и управление зависимостями
go.mod, go.sum, семантический импорт версий, minimal version selection, replace/exclude, vendoring и workspaces (go.work). Как Go решает, какие версии зависимостей брать, почему MVS отличается от других менеджеров пакетов, и как этим управлять на практике
Базы данных
Аномалии и уровни изоляции: фундамент транзакций
С чего начинается транзакционность: ACID и BASE, каталог аномалий (dirty read, lost update, phantom, write skew), ANSI-уровни изоляции и их критика, блокировки против MVCC, snapshot isolation и почему это ещё не serializable
Rust
Rust в production: паттерны для надёжного backend
Production-паттерны для Rust backend: конфигурация через env, graceful shutdown, structured logging, OpenTelemetry трейсы, health checks, error handling стратегии
Rust
Rust в Docker: минимальные образы и cross-compilation
Как собирать Rust-сервисы в минимальные Docker-образы: multi-stage builds, musl vs glibc, cross-compilation, оптимизация размера. Практические рецепты для CI/CD
Сообщения
Эксплуатация NATS: nats CLI, мониторинг, backup и обновление кластера
Администрирование NATS: nats CLI и contexts, endpoints /varz /jsz /connz, prometheus-nats-exporter и Grafana, nats-top, backup/restore стримов и rolling upgrade кластера — с продакшн-чеклистом серии
Rust
Rust web-фреймворки: Axum vs Actix и выбор под задачу
Сравнение Axum и Actix-web: архитектура, производительность, ergonomics. Как выбрать фреймворк под конкретный backend-сценарий. Практические примеры: REST API, middleware, error handling
Сообщения
Безопасность и multi-tenancy в NATS: accounts, JWT, nkeys и TLS
Изоляция через accounts (глубже, чем vhost), exports/imports, три модели аутентификации (user/pass, nkeys, децентрализованный JWT через nsc и resolver) и TLS/mTLS — то, чего нет у соседей в таком виде
Базы данных
Подключение к Redis из Go, Java и Rust: что важно кроме простого PING
Практика подключения к Redis из Go, Java и Rust: timeout, pool, multiplexing, reconnect, а главное — как клиенты ведут себя с Sentinel и Cluster при failover и падении отдельных узлов
Rust
Rust async runtime: Tokio изнутри
Как устроен async runtime в Rust на примере Tokio: futures, waker, event loop. Чем отличается от goroutines в Go и virtual threads в Java. Когда async даёт выигрыш, а когда усложняет без пользы
Сообщения
NATS из Java: jnats, Core и JetStream паттерны
Те же паттерны на jnats: Connection и Dispatcher, request/reply, JetStream с pull-consumer через ConsumerContext, ack и redelivery, KV и graceful drain — зеркально к Go-статье серии
Performance
JVM-клиент под нагрузкой: gRPC ManagedChannel и HttpClient на HTTP/2
Клиент на JVM для highload: пул gRPC-каналов и java.net.http HttpClient поверх HTTP/2, deadlines под SLA и идемпотентный retry — параллель к Go-клиенту
Базы данных
Семантический поиск в OpenSearch: k-NN, эмбеддинги и гибридный поиск
Как искать по смыслу, а не по словам: k-NN плагин OpenSearch, векторные эмбеддинги, методы ANN (HNSW/Faiss/Lucene) и гибридный поиск, сочетающий лексику и семантику
Инфраструктура
Бэкапы ценного: фото, эскизы, проекты и готовность к потере
Как защитить необратимые данные — фото, свои эскизы и проекты: правило 3-2-1, проверка дисков и тест восстановления простыми словами, готовые бытовые сценарии без командной строки и облака (зашифрованный диск у близких) и что делать, если облако кажется дорогим
Сообщения
NATS из Go: nats.go, Core и JetStream паттерны
Практика на nats.go: подключение и reconnect, Drain и graceful shutdown, request/reply и queue groups, новый jetstream API с pull-consumer, ack и дедупликацией, KV — с оглядкой на идиомы клиентов Kafka и RabbitMQ
Performance
JVM-сервис под нагрузкой: virtual threads, пулы и reactive для 1000 in-flight
Как JVM держит ~1000 одновременных проверок: platform-пул против virtual threads и reactive (WebFlux), тред-модель и бэкпрешер правильно/неправильно/неоптимально
Наблюдаемость
OpenSearch Dashboards: Discover, визуализации и дашборды
Как работать с данными OpenSearch через Dashboards: index patterns, поиск в Discover, визуализации и дашборды, saved objects и доступ по ролям поверх security plugin
Сообщения
Надёжность и производительность NATS: гарантии, репликация и tuning
Матрица гарантий Core vs JetStream, влияние R3 на latency записи, slow consumer и flow control, storage file/memory, sizing и измерение throughput/latency через nats bench — трейдофф надёжность ↔ скорость
Performance
Go-клиент под нагрузкой: пул HTTP/2-соединений и потоки
Как клиенту на Go эффективно использовать HTTP/2: одно соединение — много streams, пул из 2–8 соединений, таймауты под SLA и идемпотентный retry
Базы данных
Retention в OpenSearch: ISM, rollover и жизненный цикл индексов
Как автоматически управлять жизненным циклом индексов в OpenSearch: политики ISM, переходы hot/warm/snapshot/delete по возрасту и размеру, rollover с write-алиасом и снапшоты перед удалением
Go
slog: структурированное логирование в стандартной библиотеке Go
log/slog (Go 1.21) — структурированное логирование в стандартной библиотеке: уровни, атрибуты, группы, JSON и text-хендлеры, With для контекста и связка с context. Как устроены Handler/Record, как писать свой хендлер и почему slog вытесняет самописные обёртки над log — на живых примерах вывода
Сообщения
Геораспределённый NATS: superclusters, gateways, leaf nodes и mirror-стримы
Особые гео-топологии NATS: gateways и supercluster с interest-propagation, leaf nodes для edge, асинхронная репликация стримов через mirror/source между регионами — и почему RAFT-группу нельзя растягивать через океан
Performance
HAProxy L4 vs L7 и HTTP/2: как масштабировать обработку между серверами
L4 против L7, разбор мифа «1 TCP = 1 backend» для HTTP/2, конфиги HAProxy правильно/неправильно/неоптимально и таймауты с retry под SLA
Базы данных
Полнотекстовый поиск в OpenSearch: запросы, анализаторы и подсветка результатов
Как устроен полнотекстовый поиск в OpenSearch: типы запросов, анализаторы для русского и английского языков, подсветка результатов, оптимизация релевантности и сравнение с полнотекстовым поиском в PostgreSQL и MongoDB
Сообщения
Классический кластер NATS: routes, RAFT и надёжный failover
Два уровня кластеризации NATS: full-mesh routes для Core и RAFT (meta-group + per-stream) для JetStream; кворум, реплики R3, placement и как кластер переживает падение ноды без потери данных
Performance
Бюджет задержки и выбор транспорта: highload под SLA < 300 мс
Из чего складывается бюджет 300 мс, почему Kafka не место в синхронном пути, HTTP/1.1 против HTTP/2 и когда WebSocket не нужен — на сквозном кейсе 2000–5000 rps
Базы данных
Сбор данных в OpenSearch: API, клиенты и bulk-загрузка
Как отправлять данные в OpenSearch из приложений на Go, Java, Rust и Python: REST и bulk, официальные клиенты, обработка ошибок и живой бенчмарк single vs bulk на 3.5.0
Архитектура
Гарантии доставки и идемпотентность: как получить effectively-once
Вся событийная архитектура держится на одной связке, которую редко проговаривают вслух: at-least-once доставка + идемпотентный консьюмер = effectively-once. Разбираем, почему сквозной exactly-once недостижим в принципе, чем at-least-once отличается от at-most-once, как сделать консьюмер идемпотентным (ключи идемпотентности, dedup-хранилище, естественная идемпотентность, окно дедупа) и где эта связка уже работает в серии — в outbox, saga и проекциях
Сообщения
JetStream: как NATS получает persistence, streams и гарантии доставки
Второй уровень NATS: streams и retention policies (limits/interest/workqueue), pull vs push consumers, ack и redelivery, дедупликация, KV и Object store — и чем это отличается от лога Kafka и очередей RabbitMQ
Архитектура
Досрочное погашение и архитектурные решения: почему ранняя коррекция курса обходится дешевле
Аннуитетный кредит как модель технического долга. Интерактивный калькулятор, реальные ставки ЦБ РФ и архитектурная аналогия: чем раньше вы меняете курс – тем дешевле это стоит
Базы данных
OpenSearch: индексы, маппинги и шаблоны
Как устроены индексы и маппинги в OpenSearch: dynamic vs explicit, типы полей и анализаторы, index и component templates, алиасы для ротации — с живой проверкой на 3.5.0
Сообщения
NATS для тех, кто знает Kafka и RabbitMQ: subjects, Core и request/reply
Ментальная модель NATS через знакомые понятия: subjects вместо exchanges и topics, встроенный request/reply, queue groups и почему Core NATS — это at-most-once транспорт без хранения
Архитектура
Что кладём в событие: notification vs event-carried state transfer
Самое базовое решение событийной архитектуры — что положить в событие: тонкое уведомление (просто «заказ изменился», ID) или толстое событие с полным состоянием. Первое слабо связывает, но провоцирует «GET-storm» обратно на источник; второе автономно, но раздувает payload, устаревает и тащит связанность по данным. Разбираем два паттерна из таксономии Фаулера, их компромиссы (связанность ↔ автономность ↔ staleness), версионирование нагрузки, приватность в событии и когда что выбирать
Инфраструктура
OpenSearch: установка кластера через Ansible, авторизация и работа с индексами
Как развернуть 3-нодный кластер OpenSearch официальным Ansible-плейбуком, настроить TLS через Vault PKI и security plugin с ролевым доступом
Go
Профилирование и бенчмаркинг в Go: как измерять без самообмана
Как в Go профилировать и бенчмаркить без самообмана: b.Loop и benchstat для честных замеров, чтение pprof (CPU/heap/allocs), execution trace и PGO, и типичные ошибки «оптимизации по ощущениям»
Архитектура
Хореография vs оркестрация: кто знает бизнес-процесс
Многошаговый процесс между сервисами координируют двумя способами: хореография — сервисы реагируют на события, единого дирижёра нет, поток эмерджентный; оркестрация — центральный координатор явно ведёт шаги и обрабатывает отказы. Разница не в технологии, а в том, ГДЕ живёт знание о процессе: размазано по сервисам или собрано в одном месте. Разбираем компромиссы, антипаттерны (event-спагетти vs god-оркестратор), когда что и почему реальные системы почти всегда гибрид
Архитектура
Ошибки, паники и исключения: как языки обращаются с отказами
Как Go, Rust, C++ и Java проводят границу между ожидаемым отказом и сломанным инвариантом, и как осознанно выбирать между возвратом ошибки, паникой и исключением
Go
sqlc и SQL-builders в Go: генерация кода из SQL vs конструирование запросов
Два подхода к работе с SQL в Go без ORM на одном домене: sqlc генерирует типизированный код из SQL, а SQL-builders (squirrel, goqu) конструируют запросы программно. Где каждый силён, где кусается и как их комбинировать
Сообщения
Streams в RabbitMQ: Kafka-подобный лог и можно ли заменить Kafka
Что такое streams в RabbitMQ — append-only лог с offset-чтением и репликацией, как их объявлять и читать (native stream-протокол и AMQP), super streams для партиционирования, честное сравнение с Kafka и разбор, где RabbitMQ Streams реально заменяет Kafka, а где нет
Go
ORM в Go: где он уместен и что выбрать между GORM и go-jet
ORM в Go: где такой подход оправдан, чем GORM отличается от EF/Hibernate, когда практичнее SQL-first go-jet, и какие есть альтернативы (sqlc, ent, bun)
Архитектура
Temporal: durable workflows вместо самодельных очередей
Что такое Temporal, какие задачи он решает, чем отличается от очередей и saga-оркестраторов и когда стоит его внедрять, а когда достаточно простого решения
Docker
Rootless Docker: стоит ли переходить
Что даёт rootless Docker по безопасности, где он удобен и какие ограничения приносит в реальной эксплуатации — и при чём здесь Podman
Go
PGX в Go: зачем уходить с pq и где проходит граница пользы
Как собрать нормальный data-access слой на pgx: чтение в структуры без sqlx, типы PostgreSQL (jsonb/array/nullable/timestamptz), транзакции, batch и CopyFrom, настройка pgxpool, режимы за pgbouncer и типичные сложности эксплуатации
Архитектура
Saga: распределённые транзакции без двухфазного коммита
Как паттерн Saga решает проблему распределённых транзакций, чем оркестрация отличается от хореографии и когда saga создаёт больше проблем, чем решает
Безопасность
HTTP/2 Bomb: как склейка двух старых приёмов кладёт веб-сервер
Разбор атаки HTTP/2 Bomb: HPACK-бомба и удержание через нулевое flow-control окно по отдельности известны десять лет, но вместе кладут nginx, Apache, IIS, Envoy и Pingora за секунды. Как устроен механизм на уровне фреймов, кто уязвим и что пропатчено, почему Angie (и khorost.tech) не тронут, как проверить свой сервер — и почему эту склейку первым увидел ИИ
Инфраструктура
Terraform для Docker-хостов и сетей: где проходит граница пользы
Где Terraform реально помогает в Docker-инфраструктуре — хост, firewall, генерация Ansible inventory, — а где только добавляет слой абстракции: lifecycle контейнеров и docker-сети. С рабочим примером стыка Terraform → Ansible из digital-cookbook
Go
Когда env уже мало: layered configuration в Go с confita
Когда env-only уже мало: как выстроить layered configuration в Go с confita — сквозной Config с группами, time.Duration/срезы/nested, приоритет слоёв, post-load валидация и где confita кусается
Архитектура
Контракты событий: schema evolution без боли
Событие как публичный контракт: naming, обратная и прямая совместимость, безопасные и ломающие изменения схемы, JSON против Avro/Protobuf, schema registry, consumer-driven contracts и upcasting
Инфраструктура
Ansible и Docker Compose: раскатываем сервисы без ручной магии
Как использовать Ansible для управления Docker Compose стеками: inventory, group_vars для нескольких окружений, шаблоны compose и .env, секреты через ansible-vault и модуль community.docker.docker_compose_v2 — с рабочим примером из digital-cookbook
Архитектура
Transactional Outbox/Inbox: события без распределённой транзакции
Как надёжно публиковать события при изменении данных без распределённой транзакции: outbox, relay/poller, inbox и дедупликация, idempotency key, ordering, poison messages и почему exactly-once — это иллюзия
Инфраструктура
Proxmox + Terraform: автоматизируем создание VM и контейнеров в домашней лаборатории
Как использовать Terraform для автоматического создания и управления виртуальными машинами и LXC-контейнерами в Proxmox VE: провайдер bpg/proxmox, cloud-init шаблоны, примеры VM и CT, типичные ошибки
Архитектура
CQRS: разделяем чтение и запись без лишнего пафоса
Что такое CQRS, зачем разделять модели чтения и записи, как это связано с event sourcing и где этот паттерн создаёт больше проблем, чем решает
Kubernetes
Kubernetes Gateway API: чем он лучше Ingress и когда переходить
Gateway API — новый стандарт управления входящим трафиком в Kubernetes. Чем он отличается от Ingress, какие задачи решает лучше, как оценивать готовность реализаций к production и когда переход действительно оправдан.
Архитектура
Event Sourcing: когда история важнее текущего состояния
Что такое event sourcing, какие задачи он решает лучше классического CRUD, где усложняет без пользы и на что смотреть перед внедрением
Архитектура
Архитекторы в IT: кто чем занимается и кому это нужно
Какие виды архитектуры бывают в IT, чем отличаются роли архитекторов, и почему архитектурные решения на практике принимают не только люди с «архитектор» в должности
Архитектура
Событийная архитектура без магии: карта понятий
Карта понятий событийной архитектуры: чем команда отличается от события, domain event от integration event, где брокер, где event store, где workflow engine — и как читать остальную серию
Архитектура
Распределённые конфигурации: etcd, Consul, Vault и когда они действительно нужны
Когда конфигурация через env и файлы перестаёт работать, какие задачи решают etcd, Consul и Vault, чем они отличаются и как не усложнить систему раньше времени
Архитектура
Сквозной итоговый кейс: собираем рабочую систему лунной базы
Финальная статья архитектурно-аналитической серии: один сценарий лунной базы, пройденный целиком — от problem statement и требований через доменную модель, C4, взаимодействия и согласованность до эксплуатации, чтобы увидеть, как все решения складываются в одну систему
Сообщения
Эксплуатация RabbitMQ: мониторинг и продакшн-чеклист
Что наблюдать в RabbitMQ через Prometheus и Grafana, как читать метрики во время failover и финальный продакшн-чеклист настроек отказоустойчивого кластера
Архитектура
Эксплуатация в архитектуре: как инженеры возвращают схему в реальность
Статья архитектурно-аналитической серии на примере лунной базы: почему эксплуатация — не этап после архитектуры, а её часть, и как наблюдаемость, деградация и восстановление должны проектироваться вместе с системой
Сообщения
Связываем кластеры RabbitMQ: Federation и Shovel
Асинхронная маршрутизация между кластерами RabbitMQ: чем federation отличается от shovel, как строить geo-распределение и DR-сценарии и когда что выбирать
Архитектура
Согласованность данных: где нужна строгая, а где достаточно «в итоге»
Статья архитектурно-аналитической серии на примере лунной базы: как выбирать уровень согласованности данных под реальные сценарии — строгая, eventual или пакетная — и почему «согласованность везде» ломает систему так же, как её отсутствие
Сообщения
Не потерять сообщение в RabbitMQ: durability, confirms, ack и DLQ
Durability и persistence, publisher confirms против тихих потерь, manual ack и prefetch, Dead Letter Queue и паттерн отложенной доставки через retry-queue, а также почему confirms предпочтительнее транзакций
Архитектура
Взаимодействия и интеграции: где ломается кажущаяся простота
Статья архитектурно-аналитической серии на примере лунной базы: как аналитика и архитектура по-разному смотрят на синхронные и асинхронные взаимодействия, REST, события, команды и очереди — и где простая на схеме интеграция оказывается дорогой
Сообщения
Отказоустойчивый RabbitMQ: quorum-очереди и failover без потерь
Почему одна нода RabbitMQ — не вариант, чем mirrored queues отличаются от quorum queues на Raft, какой трейдофф у строгого кворума и как развернуть кластер, переживающий падение ноды без потери сообщений
Архитектура
C4-модель для аналитика: не рисовать красиво, а думать точно
Статья архитектурно-аналитической серии на примере лунной базы: как использовать C4-модель не как способ рисовать красивые схемы, а как инструмент точного разговора между аналитикой, архитектурой, разработкой и инженерными командами
Архитектура
Как доменная модель ломает и спасает архитектуру
Статья архитектурно-аналитической серии на примере лунной базы: как ошибка в доменной модели превращается в ошибку архитектуры, а хорошая модель помогает точнее разделять контексты, взаимодействия и ответственность
Архитектура
DDD для аналитика без культа терминов
Зачем аналитику DDD, как bounded context и ubiquitous language помогают проектированию и почему доменная модель важнее терминов
Архитектура
Требования как архитектурные драйверы
Как требования превращаются в архитектурные драйверы, почему NFR часто важнее use cases и где видна будущая цена решений
Архитектура
Problem statement: симптомы, причины и метрики
Как не путать симптом с причиной, как формулировать problem statement и почему метрики нужны до архитектурного решения
Инфраструктура
imgproxy в production: обработка изображений на лету, S3, кеширование и подпись URL
Как вынести resize и конвертацию картинок в WebP/AVIF в отдельный сервис: подписанные URL, кеш перед imgproxy, сложности деплоя и реальные цифры — на примере khorost.tech
Архитектура
Почему аналитику недостаточно только требований
Где аналитика начинает влиять на архитектуру и почему одних требований недостаточно для проектирования сложной системы
Архитектура
Архитектура, аналитика и лунная база: о чём эта серия
Почему для серии об архитектуре и аналитике выбран кейс лунной базы и чем мысленный эксперимент полезнее абстрактного enterprise-примера
Инструменты
LikeC4: архитектура как код — от DSL до интерактивных диаграмм
Как описывать архитектуру системы кодом с помощью LikeC4: DSL для C4-модели, автоматическая генерация диаграмм, версионирование в Git, встраивание в документацию и сравнение с Mermaid, PlantUML и Structurizr
Инструменты
Git: от первого коммита до уверенной работы в команде
Учебный материал по Git: от базовых концепций до уверенной работы с ветками, конфликтами и командным workflow. Без магии, с объяснением что происходит внутри
AI
Паттерны снижения трения при работе с AI-ассистентами: разбор статьи Rahul Garg
Разбор статьи с martinfowler.com о пяти паттернах эффективной работы с AI-ассистентами в разработке: Knowledge Priming, Design-First Collaboration, Context Anchoring, Encoding Team Standards и Feedback Flywheel — с микропримерами, личным опытом и критическим взглядом
Инструменты
Как настроить окружение для изучения языка программирования
Универсальный гайд по настройке рабочего окружения для изучения любого языка: установка runtime, выбор редактора, первый запуск, менеджер зависимостей и альтернативный путь через Docker
Инфраструктура
Как ArgoCD выгнал меня из Nexus: переезд на Harbor, Verdaccio и Athens
История о том, как один artifact-сервер незаметно стал лицензионной ловушкой, и почему я разменял монолитный Nexus на три специализированных open-source сервиса
Базы данных
Миграции для ScyllaDB в Go: scyllamigrate, gocqlx/migrate, golang-migrate и goose
Практический разбор миграций для ScyllaDB в Go: scyllamigrate, gocqlx/migrate, golang-migrate и goose. Что лучше подходит для CQL, где важна зрелость экосистемы и какие риски есть у каждого подхода
Docker
Docker Compose для production без Kubernetes
Когда Docker Compose всё ещё подходит для production и как выстроить вокруг него вменяемый процесс эксплуатации
Инфраструктура
Закон об иностранных словах и IT: когда Deployment стал Разверженіемъ
Федеральный закон 168-ФЗ об ограничении иностранных слов вступил в силу 1 марта 2026. Что это значит для IT-индустрии, документации, курсов и повседневного общения разработчиков
Сообщения
RabbitMQ, Kafka, NATS и Redis: как не выбирать messaging layer по моде
Выбор брокера сообщений: чем в реальности различаются RabbitMQ, Kafka, NATS и Redis (Lists, Pub/Sub, Streams), какие задачи они решают лучше всего и где начинаются типовые ошибки выбора
Rust
Rust для backend: где он действительно уместен
Где Rust в backend даёт реальный выигрыш, а где переплата сложностью. Кейсы Discord, Cloudflare, Figma. Сравнение с Go и Java, диаграмма принятия решения, примеры кода
Kubernetes
Kubernetes для домашней лаборатории: когда он действительно нужен
Kubernetes в домашней лаборатории и небольших системах: когда он действительно полезен, какие задачи решает, где добавляет лишнюю сложность и как понять, нужен ли он именно вам
Java
Java для backend и контейнеров: где она по-прежнему очень сильна
Java в современном backend и контейнерной эксплуатации: где она особенно сильна, какие у неё реальные компромиссы, как выглядит контейнеризация на практике и почему образ языка как «тяжёлого энтерпрайза из прошлого» уже давно слишком упрощён
Архитектура
System Design без культа идеальных схем
Системный дизайн без академизма и культа «идеальных схем»: с чего начинать проектирование, как думать про контекст и trade-offs, и почему хорошая архитектура почти никогда не выглядит как красивая универсальная диаграмма
Docker
Docker Buildx и multi-arch образы: одна сборка для amd64 и arm64
Как собирать и публиковать multi-arch Docker-образы через buildx для amd64 и arm64: manifest list, кэширование, QEMU vs нативные builders и проверка результата
Наблюдаемость
OpenTelemetry Collector: зачем он нужен и как на него правильно смотреть
Зачем нужен отдельный слой сбора телеметрии, как Collector устроен, сколько ресурсов потребляет, какие deployment-паттерны бывают, типичные ошибки и когда он действительно оправдан
Docker
Docker volumes: как использовать тома правильно для скорости, надёжности и контроля доступа
Как правильно использовать Docker volumes и bind mounts, почему это влияет на производительность и надёжность, и как ограничивать доступ к данным
Go
Go: конфигурация через env без хаоса
Как выстроить конфигурацию Go-приложения через env vars без расползания параметров, неочевидных дефолтов и ошибок старта
Инфраструктура
Docker-хосты в Proxmox: LXC или VM
Как выбрать между LXC и VM в Proxmox для Docker-нагрузок и не усложнить себе сопровождение
Базы данных
Redis: где он помогает, а где только усложняет систему
Redis: когда он действительно нужен, какие паттерны и анти-паттерны встречаются чаще всего, где проходят его ограничения и почему “просто поставим кэш” — плохая постановка задачи
Инфраструктура
Proxmox VE: что это такое, какие есть подписки и когда он уместен
Proxmox VE: модель лицензирования и подписок, основные возможности, кластер, backup и честные плюсы и минусы
Docker
Golden builder image и Docker Registry: ускоряем сборку и публикуем образы
Когда нужен golden builder image, как его сопровождать и как работать с Docker Registry вне Docker Hub
Docker
Production-сборка Docker-образов: secrets, proxy, healthcheck и CI
Практики production-сборки Docker-образов: линтеры, сканирование, BuildKit secrets, proxy, healthcheck и разделение build-time и runtime
Docker
Multi-stage builds в Docker: собираем Go-приложение правильно
Как уменьшить Docker-образ Go-приложения с помощью multi-stage сборки и не потерять удобство эксплуатации
Go
Graceful shutdown в Go: завершаемся правильно
Как корректно завершать Go-сервис, не теряя запросы, останавливая фоновые задачи и закрывая ресурсы