Go Roadmap: Middle 3 / Senior-grade (2025-2026)
Подробный roadmap для подготовки к собеседованию на позицию Middle 3 / Middle+ / Senior Junior Go-разработчика в крупных компаниях РФ и СНГ (Яндекс, Авито, Озон, ВК, Тинькофф, Сбер).
Источники: Habr, Хабр Карьера, vc.ru, Reddit r/golang, dev.to, Medium, официальные блоги (Go Blog, Datadog, Uber, Cloudflare), статьи 2024-2026 гг.
Дата составления: май 2026 (актуально для Go 1.24–1.26).
Введение: контекст рынка
Заголовок раздела «Введение: контекст рынка»В 2025-2026 годах Go де-факто стал основным языком для backend в high-load системах в РФ. Яндекс, Авито, Озон, Тинькофф, ВК, Сбер массово используют Go для платформенных сервисов. На уровне Middle 3 от кандидата ждут:
- Уверенное владение внутренностями языка и runtime (scheduler, GC, memory model, escape analysis).
- Production-опыт с k8s, distributed systems, очередями (Kafka/NATS), Postgres.
- Архитектурное мышление — уметь обосновать trade-off, нарисовать систему на 1-10 млн RPS.
- Системный дизайн — спокойно проектировать URL shortener, чат, ленту, очередь.
- Production debugging — pprof, flamegraph, troubleshooting инцидентов.
- Soft skills и менторство — code review, ADR, RFC, рост джунов.
Зарплатный коридор (Москва, 2026, на руки):
- Middle 2: 250-350k₽
- Middle 3 / Middle+: 350-500k₽
- Senior: 500-750k₽ (Озон Банк, Яндекс — выше всех)
1. Эксперт-уровень внутренностей Go
Заголовок раздела «1. Эксперт-уровень внутренностей Go»1.1 Внутренности компилятора
Заголовок раздела «1.1 Внутренности компилятора»Этапы компиляции Go: Lexing → Parsing → Type checking → SSA (Static Single Assignment) → Machine code. На уровне Middle 3 надо понимать что компилятор:
- Делает escape analysis во время type checking — определяет, может ли переменная жить на стеке.
- Генерирует SSA-форму — промежуточное представление, где каждая переменная присваивается ровно один раз. SSA позволяет оптимизации: inlining, dead code elimination, common subexpression elimination, bounds check elimination.
- Применяет PGO (Profile-Guided Optimization) с Go 1.21+ — оптимизация по реальным production-профилям.
# Посмотреть SSA для функцииGOSSAFUNC=myFunc go build .# Создаст ssa.html с подробной информацией
# Посмотреть escape analysisgo build -gcflags="-m -m" .
# Посмотреть инлайн-решенияgo build -gcflags="-m=2" .Escape Analysis: алгоритм
Заголовок раздела «Escape Analysis: алгоритм»Escape Analysis — это граф-анализ: компилятор строит граф ссылок между переменными, помечает «корни» (возвращённые указатели, глобалы, горутины) и пропагирует марки. Если переменная не доходит до корня — она не escape, остаётся на стеке.
Типичные причины escape:
- Возврат указателя на локальную переменную
- Сохранение указателя в глобал
- Передача в interface{} (часто), в горутину
- Слишком большой объект (>64KB) — сразу на heap
fmt.Println(x)—xуходит вinterface{}→ heap
// Stack:func sum() int { arr := [10]int{1, 2, 3} return arr[0]}
// Heap (потому что &arr возвращается):func leak() *int { arr := 42 return &arr // escape to heap}Стек в Go дешевле кучи в ~5x (нет GC pressure, нет атомиков). Грамотный escape analysis может дать 2-10x ускорение и снизить GC overhead на 50-90%.
Источник: Mastering Escape Analysis in Go, Go Optimization Guide — Stack Allocations
GC Pacer Math
Заголовок раздела «GC Pacer Math»Go GC — concurrent tri-color mark-and-sweep на основе Dijkstra. Pacer — пропорциональный регулятор, решающий, когда запустить новый GC цикл. Цель: держать GC проportional к скорости аллокаций.
Формула (упрощённо):
heap_target = heap_marked * (1 + GOGC/100)GOGC=100(default) — GC стартует, когда heap вырос вдвое относительно живых данныхGOGC=200— GC реже, меньше CPU overhead, больше памятиGOGC=off— GC только при достижении GOMEMLIMIT
Mark Assist: если приложение аллоцирует быстрее, чем GC размечает, runtime «штрафует» горутины — заставляет их помогать GC пропорционально объёму аллокаций.
Источник: GC Pacer Redesign Proposal, Ardan Labs: GC Pacing
1.2 Runtime Internals: scheduler, futex, netpoll
Заголовок раздела «1.2 Runtime Internals: scheduler, futex, netpoll»GMP-модель
Заголовок раздела «GMP-модель»- G (goroutine) — задача, легковесный стек начиная с 2-8 KB (растёт по необходимости).
- M (machine) — OS thread.
- P (processor) — логический процессор, владеет local run queue, timers, mcache. Количество =
GOMAXPROCS.
Каждая M может выполнять G только если держит P. Локальная очередь P имеет 256 слотов. Work stealing: пустые P крадут половину задач у занятых.
Preemption (с Go 1.14+): asynchronous preemption на основе сигналов (SIGURG на Unix), горутина может быть прервана даже без явных function calls. sysmon (системный monitor-поток) каждые 10ms помечает долгие goroutine как preemptible.
Парковка горутин: futex + netpoll
Заголовок раздела «Парковка горутин: futex + netpoll»На Linux Go runtime использует futex (fast userspace mutex) для парковки M-потоков. Когда M простаивает — он засыпает в futex, ядро его потом разбудит.
Netpoller: когда горутина делает сетевую операцию (read/write на socket), который не готов:
- Runtime регистрирует fd в epoll (Linux) / kqueue (macOS) / IOCP (Windows).
- Горутина паркуется через
gopark, M освобождается под другие G. - Когда kernel сигнализирует о готовности fd, netpoller возвращает горутину в run queue.
Состояние pdWait — защита от race condition: горутина «в процессе засыпания, ещё не полностью паркована».
Источник: Go Netpoller and Runtime Behavior, Go Scheduler 2025 Deep Dive
1.3 Assembly в Go (Plan 9 синтаксис)
Заголовок раздела «1.3 Assembly в Go (Plan 9 синтаксис)»Когда писать руками:
- Тяжёлые криптографические/хеш-операции (SHA-256, AES, CRC32)
- SIMD (см. ниже)
- Атомики на нестандартных архитектурах
- Низкоуровневые системные вызовы
// func addASM(a, b int) intTEXT ·addASM(SB), NOSPLIT, $0-24 MOVQ a+0(FP), AX MOVQ b+8(FP), BX ADDQ BX, AX MOVQ AX, ret+16(FP) RETIntrinsics — компилятор автоматически переводит некоторые функции в нативные инструкции CPU: math/bits.LeadingZeros64() → LZCNT, math/bits.OnesCount64() → POPCNT, sync/atomic.AddInt64() → LOCK XADD.
SIMD в Go (Single Instruction Multiple Data)
Заголовок раздела «SIMD в Go (Single Instruction Multiple Data)»Текущее состояние: SIMD доступен через hand-written assembly (например, segmentio/asm, stuartcarnie/go-simd).
Go 1.26+ изменения: ввели GOEXPERIMENT=simd — пакет simd для AMD64 с архитектурно-специфичными intrinsics. Avoids assembly boundary overhead.
// Hypothetical Go 1.26+ SIMD APIimport "simd"func sumFloats(data []float32) float32 { var v simd.Float32x8 for i := 0; i+8 <= len(data); i += 8 { v = v.Add(simd.LoadFloat32x8(data[i:])) } return v.HorizontalSum()}Источник: SIMD in Go, Go Proposal #73787 SIMD Intrinsics
1.4 Linkname tricks
Заголовок раздела «1.4 Linkname tricks»//go:linkname — директива компилятора, позволяющая «склеить» имя из вашего пакета с private-функцией стандартной библиотеки. Используют для:
- Доступа к
runtime.nanotime()(быстрееtime.Now()) - Доступа к
runtime.fastrand() - В библиотеках (xxhash, gops)
//go:linkname nanotime runtime.nanotimefunc nanotime() int64⚠️ Опасно: Go team может убрать private-функцию в любой версии. С Go 1.23+ ввели ограничения на linkname для нестандартных пакетов.
1.5 PGO — Profile-Guided Optimization
Заголовок раздела «1.5 PGO — Profile-Guided Optimization»Доступно с Go 1.21, production-ready с 1.24. Дает 2-14% улучшение CPU usage без изменения кода.
Workflow:
- Соберите CPU profile с production:
curl localhost:6060/debug/pprof/profile?seconds=30 > default.pgo - Положите
default.pgoрядом сmain.go. go build .— Go автоматически использует профиль для оптимизации (агрессивный inlining, deduplication, layout).
Реальные кейсы:
- Uber: применили PGO на десятки сервисов, до 7% CPU saving.
- Cloudflare: интегрировали PGO в pipeline сборки.
- Google: 5-7% улучшение на internal workloads.
Источник: PGO docs, Uber Boosted Performance with PGO (InfoQ 2025), Datadog Save 14% CPU with PGO
1.6 Memory Ballast Pattern и его конец
Заголовок раздела «1.6 Memory Ballast Pattern и его конец»Memory Ballast — старый трюк (популяризован Twitch ~2019): при старте аллоцировать большой byte slice (например, 1 GiB), чтобы heap target GC был высоким и GC реже срабатывал.
// Старая практика (НЕ ИСПОЛЬЗОВАТЬ):ballast := make([]byte, 10<<30) // 10 GiB_ = ballast❌ Проблемы:
- Не portable между ОС (Linux vs macOS overcommit разный).
- Тяжело подобрать правильный размер.
- Зависит от внутренностей GC, которые могут поменяться.
✅ С Go 1.19+ используют GOMEMLIMIT:
1.7 GOMEMLIMIT (Go 1.19+) — soft memory limit
Заголовок раздела «1.7 GOMEMLIMIT (Go 1.19+) — soft memory limit»GOMEMLIMIT — мягкий лимит для runtime, говорит GC «не давай хипу превысить N байт».
Правильная настройка в k8s:
env: - name: GOMEMLIMIT valueFrom: resourceFieldRef: resource: limits.memory # ИЛИ через soft limit (90% от k8s limit): - name: GOMEMLIMIT value: "900MiB" # если k8s limit = 1Giresources: limits: memory: "1Gi"Best practices 2025:
- Установите
GOMEMLIMITв ~90% от k8s memory limit (10% запас на goroutine stacks, cgo, off-heap). GOGC=off+GOMEMLIMIT=900MiB— GC только при достижении лимита (для memory-bound сервисов).- Для high-throughput:
GOGC=200,GOMEMLIMIT=...— реже GC, больше throughput. - Сочетайте с
GOMAXPROCS(Uber automaxprocs читает cgroups).
Источник: Ardan Labs: Kubernetes Memory Limits and Go, Weaviate GOMEMLIMIT Game Changer
1.8 runtime/debug и runtime/metrics
Заголовок раздела «1.8 runtime/debug и runtime/metrics»import ( "runtime/debug" "runtime/metrics")
// Set memory limit programmaticallydebug.SetMemoryLimit(900 * 1024 * 1024)debug.SetGCPercent(200)
// FreeOSMemory — попросить runtime вернуть память ОС (после большого batch-job)debug.FreeOSMemory()
// Стектрейс для диагностики паникdebug.PrintStack()
// runtime/metrics — структурированный доступ к метрикам runtimesamples := []metrics.Sample{ {Name: "/sched/latencies:seconds"}, {Name: "/gc/cycles/total:gc-cycles"}, {Name: "/memory/classes/heap/objects:bytes"},}metrics.Read(samples)С Go 1.25+ добавили FlightRecorder — облегчённая альтернатива полному tracing для production.
1.9 sync.Map internals
Заголовок раздела «1.9 sync.Map internals»type Map struct { mu Mutex read atomic.Value // содержит readOnly{m: map[any]*entry, amended: bool} dirty map[any]*entry misses int}Принцип: два внутренних map.
read— lock-free (читается через atomic), но не содержит новых ключей.dirty— защищён мьютексом, содержит свежие записи.
Жизненный цикл:
- Запись нового ключа → идёт в
dirty(с lock). - Чтение существующего ключа → lock-free из
read. - Чтение ключа, которого нет в
read, но есть вdirty→misses++. - Когда
misses >= len(dirty)→ promotion:dirtyстановится новымread, старый dirty = nil.
Когда использовать:
- ❌ Не подходит для произвольных нагрузок (map+RWMutex часто быстрее).
- ✅ Хорош при read-heavy + редкие записи (например, кэш конфигурации).
- ✅ Когда ключи практически не пересекаются между горутинами (disjoint keys).
var cache sync.Map
// Storecache.Store("key", "value")// Loadv, ok := cache.Load("key")// CompareAndSwap (Go 1.20+)cache.CompareAndSwap("key", "old", "new")// LoadAndDelete — atomicv, ok := cache.LoadAndDelete("key")Источник: Inside sync.Map, VictoriaMetrics: sync.Map Right Tool
1.10 Slice growing internals
Заголовок раздела «1.10 Slice growing internals»type SliceHeader struct { Data uintptr Len int Cap int}Правила роста (с Go 1.18+, в Go 1.20 уточнились):
- Если cap < 256: новый cap = 2 * old cap (двойной рост).
- Если cap >= 256: новый cap = old cap + (old cap + 3*256) / 4 (примерно +25%).
Подводные камни:
appendможет (а может и нет) выделить новый underlying array → мутации через старый slice могут «потеряться».- Sub-slice держит ссылку на весь underlying array → memory leak.
- При
s = s[1000:]GC не освободит начало массива.
// Memory leak:big := make([]byte, 10<<20) // 10 MiBsmall := big[0:3]// small держит ссылку на весь bigruntime.GC()// big не освобождён
// Fix:small := make([]byte, 3)copy(small, big[0:3]) // независимая копияИсточник: Tricky Golang interview: Slice Header
1.11 Map internals: buckets, overflow, evacuation
Заголовок раздела «1.11 Map internals: buckets, overflow, evacuation»Pre-Go 1.24 (старая bucket-based реализация):
- Map = array из buckets, каждый держит 8 key-value.
- Когда bucket переполнен — создаётся overflow bucket (linked list).
- При load factor > 6.5 запускается evacuation: создаётся buckets array вдвое больше, элементы инкрементально перемещаются.
Go 1.24+: Swiss Tables:
- Принципиально новая реализация: extendible hashing + table splitting.
- 8-slot groups, SIMD-friendly metadata.
- Когда таблица достигает 128 групп → splits на две таблицы (~1024 entries копируется).
- Нет overflow buckets, нет долгих evacuation pauses.
Реальный кейс (Datadog, 2025): миграция на Swiss Tables сэкономила сотни ГБ памяти и снизила P99 latency для больших maps.
// Хорошие практики:m := make(map[string]User, 1000) // pre-allocate если знаете размер// vs:m := make(map[string]User) // будут многократные resize
// Опасно (для read-heavy):m := make(map[K]V)go func() { m["x"] = v }() // ⚠️ data race!// Решение: sync.Map ИЛИ map+RWMutexИсточник: How Go 1.24’s Swiss Tables saved Datadog GBs, Go Blog: Faster maps with Swiss Tables
2. Concurrency — экспертный уровень
Заголовок раздела «2. Concurrency — экспертный уровень»2.1 Channel internals
Заголовок раздела «2.1 Channel internals»type hchan struct { qcount uint // элементов в очереди dataqsiz uint // размер кольцевого буфера buf unsafe.Pointer // массив elemsize uint16 closed uint32 elemtype *_type sendx uint // позиция записи recvx uint // позиция чтения recvq waitq // очередь ожидающих читателей (sudog) sendq waitq // очередь ожидающих писателей (sudog) lock mutex}sudog (“suspended goroutine”) — структура для парковки горутины, ожидающей на канале:
type sudog struct { g *g next *sudog prev *sudog elem unsafe.Pointer // куда положить/откуда взять данные c *hchan // ...}Алгоритм send (упрощённо):
Заголовок раздела «Алгоритм send (упрощённо):»- Lock канала.
- Если есть ждущий receiver в
recvq→ напрямую копируем элемент в егоsudog.elem, разблокируем G, unlock, return. - Если в buffered канале есть место → копируем в buf[sendx], sendx++, unlock, return.
- Иначе создаём
sudog, кладём вsendq, паркуем горутину (gopark). - Когда receiver разбудит — продолжаем выполнение.
close(ch):
Заголовок раздела «close(ch):»- Маркирует
closed=1. - Будит ВСЕ горутины из
recvq(они получат zero value, ok=false). - Будит ВСЕ горутины из
sendq(они получат panic: send on closed channel).
⚠️ Известная гонка: «sender может ли узнать, что канал закрыт?» — нет универсального способа без race. Закрывать должен только sender, и только если он единственный.
Pattern: «who closes what»
Заголовок раздела «Pattern: «who closes what»»// ОК — один producer, один consumergo func() { defer close(ch) for x := range source { ch <- transform(x) }}()
// ОК — fan-out: один producer закрывает, fan-in закрывает aggregatedout := make(chan int)var wg sync.WaitGroupfor _, in := range inputs { wg.Add(1) go func(c <-chan int) { defer wg.Done() for v := range c { out <- v } }(in)}go func() { wg.Wait() close(out)}()Источник: Go Channels: Runtime Internals Deep Dive (Gabor Koos, 2025)
2.2 sync.Mutex internals
Заголовок раздела «2.2 sync.Mutex internals»Mutex в Go = гибрид spinlock + semaphore.
type Mutex struct { state int32 // битовое поле: locked|woken|starving|waiterCount sema uint32 // семафор для парковки}Состояния:
- Normal mode: новая горутина пытается захватить через CAS + короткий spin (если CPU > 1 и P не загружен), потом паркуется через
runtime_SemacquireMutex. - Starvation mode (с Go 1.9): если goroutine ждёт > 1ms — флаг starving, mutex передаётся первой в очереди (FIFO).
Mutex profiling:
go test -mutexprofile=mutex.out -mutexprofilefraction=1go tool pprof mutex.out// Включить в коде:runtime.SetMutexProfileFraction(1) // 1 = сэмплировать всёruntime.SetBlockProfileRate(1)2.3 Custom synchronization primitives
Заголовок раздела «2.3 Custom synchronization primitives»Lock-free MPSC queue
Заголовок раздела «Lock-free MPSC queue»Multi-Producer Single-Consumer на atomic CAS:
type Node struct { next atomic.Pointer[Node] value any}
type MPSC struct { head atomic.Pointer[Node] // только consumer пишет head tail atomic.Pointer[Node] // producers пишут tail}
func (q *MPSC) Push(v any) { n := &Node{value: v} prev := q.tail.Swap(n) prev.next.Store(n) // линкуем после swap}
func (q *MPSC) Pop() (any, bool) { head := q.head.Load() next := head.next.Load() if next == nil { return nil, false } q.head.Store(next) return next.value, true}Готовые библиотеки:
cyub/ringbuffer— SPSC/SPMC/MPSC/MPMC ring bufferhedzr/go-ringbuf— MPMC lock-free genericLENSHOOD/go-lock-free-ring-buffer
Wait-free vs Lock-free
Заголовок раздела «Wait-free vs Lock-free»- Lock-free: хотя бы один поток гарантированно завершит операцию за конечное число шагов.
- Wait-free: КАЖДЫЙ поток завершит за конечное число шагов (сильнее).
В Go wait-free алгоритмы редки — большинство «lock-free» из-за CAS-loop.
2.4 ABA-проблема
Заголовок раздела «2.4 ABA-проблема»Когда CAS видит «то же значение», но между двумя проверками значение успело смениться и вернуться. Классическая проблема lock-free stack.
Решение в Go:
- Tagged pointer (atomic счётчик в верхних битах указателя).
unsafe.Pointer+ version counter.- Использовать
sync/atomic.Valueс immutable снапшотами.
В Go из-за GC ABA встречается реже (GC сохраняет память), но всё ещё актуальна в low-level structures.
2.5 False sharing и cache line padding
Заголовок раздела «2.5 False sharing и cache line padding»CPU кэш-линия = 64 байта (обычно). Если две переменные на разных ядрах лежат в одной линии — invalidation pingpong, performance drop в 5-10x.
// Плохо:type Counters struct { A int64 B int64 // лежит в той же кэш-линии}
// Хорошо:type Counters struct { A int64 _ [56]byte // padding до 64 bytes B int64 _ [56]byte}Benchmark (реальные числа): 45ns/op → 7ns/op (6.4x speedup) при contention. Но: padding увеличивает память, имеет смысл только в hot path с high contention.
В Go 1.21+ есть runtime.CPUCacheLineSize() (experimental).
Источник: False Sharing in Go (Genchi Lu), 100 Go Mistakes #92
2.6 errgroup + singleflight
Заголовок раздела «2.6 errgroup + singleflight»import ( "golang.org/x/sync/errgroup" "golang.org/x/sync/singleflight")
// errgroup: запускаем N задач, возвращаем первую ошибку, отменяем остальныхg, ctx := errgroup.WithContext(ctx)for _, url := range urls { url := url g.Go(func() error { return fetch(ctx, url) })}if err := g.Wait(); err != nil { log.Error(err)}
// singleflight: предотвращаем дубликаты запросов (cache stampede)var group singleflight.Groupresult, err, shared := group.Do("user:42", func() (any, error) { return db.GetUser(42)})// shared=true → этот вызов разделил результат с другимиПрименение singleflight:
- Cache miss → миллион параллельных запросов в БД? Только один реальный, остальные ждут результат.
- TLS handshake deduplication.
- Кэш warming.
2.7 Параллелизм vs Concurrency (Rob Pike)
Заголовок раздела «2.7 Параллелизм vs Concurrency (Rob Pike)»“Concurrency is dealing with lots of things at once. Parallelism is doing lots of things at once.”
- Concurrency — структура программы (несколько independent flows).
- Parallelism — выполнение (одновременно на разных ядрах).
Go-программа может быть concurrent но не parallel (GOMAXPROCS=1).
2.8 Дизайн API с правильной concurrency-моделью
Заголовок раздела «2.8 Дизайн API с правильной concurrency-моделью»Принципы:
- Каналы не возвращаются из публичных API (кроме узких случаев — pipelines).
- Context — первый аргумент, всегда
ctx context.Context. - Передавайте read-only каналы (
<-chan T) если получатель не должен писать. - Обработка graceful shutdown через context.Done() + завершение горутин.
- Bounded concurrency через worker pool / semaphore.
// Хороший API:type Service struct { workers int}
func (s *Service) Process(ctx context.Context, items []Item) error { sem := make(chan struct{}, s.workers) g, ctx := errgroup.WithContext(ctx) for _, item := range items { item := item sem <- struct{}{} g.Go(func() error { defer func() { <-sem }() return s.handleOne(ctx, item) }) } return g.Wait()}Источник: Three Dots Labs, Encore Advanced Go Concurrency
3. Производительность production
Заголовок раздела «3. Производительность production»3.1 Continuous Profiling
Заголовок раздела «3.1 Continuous Profiling»Инструменты:
- Pyroscope (Grafana) — open-source, удобный, scrape-style.
- Parca — еще один CNCF проект, базируется на eBPF.
- Datadog Continuous Profiler — managed.
- Polar Signals (Conprof origin).
// Pyroscope SDK integrationpyroscope.Start(pyroscope.Config{ ApplicationName: "my.app", ServerAddress: "http://pyroscope:4040", ProfileTypes: []pyroscope.ProfileType{ pyroscope.ProfileCPU, pyroscope.ProfileAllocObjects, pyroscope.ProfileAllocSpace, pyroscope.ProfileInuseObjects, pyroscope.ProfileInuseSpace, pyroscope.ProfileGoroutines, pyroscope.ProfileMutexCount, pyroscope.ProfileMutexDuration, pyroscope.ProfileBlockCount, pyroscope.ProfileBlockDuration, },})Overhead pprof в production: ~1-2% CPU. Goroutine dump — STW ~1ms на 10к горутин.
3.2 Анализ heap dumps
Заголовок раздела «3.2 Анализ heap dumps»# Heap profile (память сейчас alloc'd)curl -o heap.out http://localhost:6060/debug/pprof/heapgo tool pprof -http=:8080 heap.out
# Allocations за всё время (для поиска hot allocators)curl -o allocs.out http://localhost:6060/debug/pprof/allocsgo tool pprof -http=:8080 -alloc_space allocs.out
# Diff двух heap'овgo tool pprof -base heap_before.out heap_after.outСтандартные команды в pprof:
top— топ функций по памятиlist <funcName>— построчная аннотацияweb— graphviz call graphpeek <regex>— кто вызывает функцию
3.3 Eliminating allocations in hot paths
Заголовок раздела «3.3 Eliminating allocations in hot paths»Чек-лист:
- Используйте
sync.Poolдля часто аллоцируемых объектов. - Pre-allocate slices/maps через
make([]T, 0, N). bytes.Buffer/strings.Builderвместо+=.fmt.Sprintfдорогой — используйтеstrconv.AppendInt.- Не передавайте мелкие структуры по указателю (escape to heap).
- Interface conversions аллоцируют — избегайте в hot path.
[]byte↔stringконверсии копируют — используйтеunsafe.String/SliceData(Go 1.20+).
var bufPool = sync.Pool{ New: func() any { return new(bytes.Buffer) },}
func format(s string) string { buf := bufPool.Get().(*bytes.Buffer) defer bufPool.Put(buf) buf.Reset() buf.WriteString("[INFO] ") buf.WriteString(s) return buf.String() // здесь будет копия}3.4 Cache-friendly код (Data-Oriented Design)
Заголовок раздела «3.4 Cache-friendly код (Data-Oriented Design)»SoA vs AoS:
// Array of Structs (cache-unfriendly для batch обработок одного поля):type Entity struct { X, Y, Z float64 Velocity Vector Color color.RGBA}entities := make([]Entity, 1_000_000)
// Struct of Arrays (cache-friendly):type Entities struct { X, Y, Z []float64 Velocity []Vector Color []color.RGBA}При обработке только координат — SoA в разы быстрее (cache hit rate ~100%).
3.5 Linker optimizations
Заголовок раздела «3.5 Linker optimizations»# Минимальный binarygo build -ldflags="-s -w" -trimpath -o app .# -s removes symbol table# -w removes DWARF debug info
# С Go 1.20+ method dead code eliminationgo build -ldflags="-checklinkname=0" .
# UPX compression (не рекомендуется для prod)upx --best --ultra-brute appDatadog кейс 2025: уменьшили размер Agent binaries на 77% за счёт устранения reflective method calls и tree-shaking.
3.6 Cold start optimization
Заголовок раздела «3.6 Cold start optimization»Для serverless / Lambda / Cloud Run:
- Использовать
-buildmode=pieНЕЛЬЗЯ (медленнее старт). - Lazy init глобалов (init() блоки замедляют старт).
- Использовать
embedдля статики вместо file system reads. - Готовый PGO профиль → меньше первичной компиляции в runtime.
3.7 Connection pool tuning
Заголовок раздела «3.7 Connection pool tuning»db, err := sql.Open("pgx", dsn)db.SetMaxOpenConns(25) // зависит от Postgres max_connectionsdb.SetMaxIdleConns(10)db.SetConnMaxLifetime(time.Hour) // защита от утечек на стороне Postgresdb.SetConnMaxIdleTime(10 * time.Minute)Правило: MaxOpenConns * число_pod ≤ pg_max_connections * 0.8 (оставить запас).
Если используете PgBouncer transaction mode — не используйте prepared statements (или PgBouncer 1.21+ с поддержкой).
4. Дизайн крупных систем (микросервисные паттерны)
Заголовок раздела «4. Дизайн крупных систем (микросервисные паттерны)»4.1 Saga Pattern
Заголовок раздела «4.1 Saga Pattern»Распределённая транзакция = серия локальных транзакций + compensating actions.
Два варианта:
-
Choreography (хореография): сервисы общаются через events, каждый сам решает.
OrderCreated → InventoryReserved → PaymentCharged → OrderConfirmed↓ (если отказ)InventoryReservationCancelled (compensation) -
Orchestration (оркестрация): центральный orchestrator (например, Temporal) управляет потоком.
// Temporal Saga в Gofunc OrderWorkflow(ctx workflow.Context, order Order) error {var saga Sagasaga.AddCompensation(cancelInventory)if err := workflow.ExecuteActivity(ctx, ReserveInventory, order).Get(ctx, nil); err != nil {return saga.Compensate(ctx)}saga.AddCompensation(refundPayment)if err := workflow.ExecuteActivity(ctx, ChargePayment, order).Get(ctx, nil); err != nil {return saga.Compensate(ctx)}return workflow.ExecuteActivity(ctx, ConfirmOrder, order).Get(ctx, nil)}
4.2 CQRS (Command Query Responsibility Segregation)
Заголовок раздела «4.2 CQRS (Command Query Responsibility Segregation)»Разделение моделей read и write:
- Commands меняют состояние (без возврата данных) → доменная модель + write-side DB.
- Queries читают (без побочных эффектов) → денормализованные read models + read-side DB / cache.
Применять, когда read и write нагрузки сильно различаются.
4.3 Event Sourcing
Заголовок раздела «4.3 Event Sourcing»Хранить события, а не текущее состояние. Текущее состояние = свёртка событий.
✅ Плюсы: полный аудит, time travel, легко добавлять новые проекции. ❌ Минусы: сложность, eventual consistency, миграции данных.
4.4 Outbox / Inbox Pattern
Заголовок раздела «4.4 Outbox / Inbox Pattern»Проблема: невозможно атомарно записать в БД И отправить сообщение в Kafka (dual write).
Outbox Pattern:
- В одной транзакции пишем в бизнес-таблицы И в
outboxтаблицу. - Отдельный процесс (Debezium / собственный poller) читает
outboxи публикует в Kafka. - CDC через WAL (PostgreSQL logical replication) → events в Kafka.
CREATE TABLE outbox ( id UUID PRIMARY KEY, aggregate_type TEXT, aggregate_id UUID, event_type TEXT, payload JSONB, created_at TIMESTAMPTZ DEFAULT now());Inbox Pattern: на стороне consumer — таблица inbox для дедупликации обработанных событий.
// При получении сообщенияexists, err := tx.QueryRow("SELECT 1 FROM inbox WHERE id = $1", msg.ID).Scan(&one)if exists { return nil // already processed}// бизнес-логика...tx.Exec("INSERT INTO inbox (id, processed_at) VALUES ($1, now())", msg.ID)tx.Commit()Источник: Outbox Pattern with Debezium, Saga Pattern with Examples in Go (2025)
4.5 Circuit Breaker
Заголовок раздела «4.5 Circuit Breaker»Состояния: Closed → Open → Half-Open → Closed.
- При N подряд ошибках → Open (запросы не идут к нижестоящему).
- После timeout → Half-Open (пускает один запрос). Успех — Closed, провал — Open.
Библиотеки: sony/gobreaker, failsafe-go, afex/hystrix-go.
import "github.com/sony/gobreaker"
cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "PaymentService", MaxRequests: 3, Interval: 10 * time.Second, Timeout: 30 * time.Second, ReadyToTrip: func(counts gobreaker.Counts) bool { return counts.ConsecutiveFailures > 5 },})result, err := cb.Execute(func() (any, error) { return paymentClient.Charge(amount)})4.6 Bulkhead
Заголовок раздела «4.6 Bulkhead»«Переборка корабля» — изоляция ресурсов между классами запросов. Реализация: отдельные пулы горутин/connection pools/thread pools для разных downstream сервисов. Если один сервис «зависнет», он не отъест все ресурсы.
type Bulkhead struct { sem chan struct{}}
func (b *Bulkhead) Execute(fn func() error) error { select { case b.sem <- struct{}{}: defer func() { <-b.sem }() return fn() case <-time.After(100 * time.Millisecond): return ErrBulkheadFull }}4.7 Retry + Exponential Backoff + Jitter
Заголовок раздела «4.7 Retry + Exponential Backoff + Jitter»import "github.com/cenkalti/backoff/v4"
err := backoff.Retry(func() error { return makeRequest()}, backoff.WithContext( backoff.NewExponentialBackOff(), ctx,))Правила:
- Retry только идемпотентных операций (или с идемпотентным ключом).
- Exponential backoff: 100ms, 200, 400, 800…
- Full jitter: random(0, base) — предотвращает thundering herd.
- Cap на max retries и total timeout.
4.8 Idempotency Key
Заголовок раздела «4.8 Idempotency Key»Клиент посылает Idempotency-Key: <uuid> → сервер хранит результат первого вызова, при повторных с тем же ключом возвращает закэшированный ответ. Stripe-style.
func (h *Handler) CreatePayment(w http.ResponseWriter, r *http.Request) { key := r.Header.Get("Idempotency-Key") if cached, ok := h.idempotencyCache.Get(key); ok { json.NewEncoder(w).Encode(cached) return } result := h.processPayment(...) h.idempotencyCache.Set(key, result, 24*time.Hour) json.NewEncoder(w).Encode(result)}4.9 Distributed Transactions: глубоко
Заголовок раздела «4.9 Distributed Transactions: глубоко»- 2PC (Two-Phase Commit): coordinator + participants → блокирующий, single point of failure. Используется в XA транзакциях.
- 3PC: добавляет pre-commit phase → меньше блокировок, но больше сообщений.
- TCC (Try-Confirm-Cancel): каждая операция имеет 3 фазы. Бизнес-уровень.
- Saga: см. выше — отсутствие глобальных блокировок, eventual consistency через compensation.
В современных микросервисах 2PC практически не используется — слишком дорог в latency и доступности.
4.10 Distributed Locks: подводные камни
Заголовок раздела «4.10 Distributed Locks: подводные камни»Redis Redlock (Antirez vs Kleppmann):
Kleppmann (2016, до сих пор актуально) критикует:
- Clock skew: Redlock полагается на синхронизированное время — это нарушение асинхронной модели.
- GC pause / OS scheduler pause: процесс может «заснуть» дольше TTL, лок «истёк», но процесс об этом не знает → два процесса в критической секции.
- Нет fencing tokens: рандомное значение не монотонно — downstream не может отвергнуть stale locks.
Что делать:
- Для advisory locks (защита от случайного двойного запуска cron): Redlock ОК.
- Для корректности (защита денег): использовать fencing tokens через consensus (etcd, ZooKeeper) + проверять на стороне resource.
- Альтернативы: etcd lease, PostgreSQL advisory locks (
pg_advisory_lock), Apache ZooKeeper recipes.
// PostgreSQL advisory lock — простая и надёжная альтернатива:_, err := db.ExecContext(ctx, "SELECT pg_advisory_lock($1)", lockID)defer db.ExecContext(ctx, "SELECT pg_advisory_unlock($1)", lockID)// ... critical sectionИсточник: Martin Kleppmann: How to do distributed locking, Antirez: Is Redlock safe?
4.11 Distributed Consensus: Raft, Paxos
Заголовок раздела «4.11 Distributed Consensus: Raft, Paxos»Raft (понятнее Paxos, более популярен):
- Leader election (terms, votes).
- Log replication (leader пишет → majority подтверждает → commit).
- Safety: term + index гарантируют linearizability.
Используется в: etcd, Consul, CockroachDB, TiKV, YDB, Hazelcast.
В Go есть production-grade библиотека: go.etcd.io/raft/v3 — используется в etcd, k8s, Docker Swarm, CockroachDB, TiDB.
// Минималистичный пример (псевдокод etcd raft)node := raft.StartNode(config, peers)for { select { case rd := <-node.Ready(): saveToStorage(rd.HardState, rd.Entries, rd.Snapshot) send(rd.Messages) for _, entry := range rd.CommittedEntries { apply(entry) } node.Advance() }}Paxos: более старый, сложнее реализовать. Используется в Google Chubby, Megastore.
4.12 Stream Processing: Kafka Streams, Flink
Заголовок раздела «4.12 Stream Processing: Kafka Streams, Flink»- Kafka Streams (JVM-only) — DSL для transform → join → aggregate над Kafka topics.
- Apache Flink — stateful stream processing, поддержка exactly-once, window operations, event time processing.
- Materialize — Postgres-совместимая streaming database.
Для Go: нет нативных эквивалентов, но есть goka (Lovoo) — облегчённая Kafka Streams-подобная библиотека на Go.
4.13 Data Lake / Lakehouse
Заголовок раздела «4.13 Data Lake / Lakehouse»- Data Lake: raw данные в object storage (S3, GCS) в форматах Parquet/ORC/Avro.
- Lakehouse: data lake + ACID-транзакции + schema enforcement. Технологии: Delta Lake, Apache Iceberg, Apache Hudi.
- Запросы через Trino/Presto, Spark, Databricks.
В России: Яндекс DataLens + S3 + Trino + ClickHouse — типичный стек.
4.14 CDC (Change Data Capture)
Заголовок раздела «4.14 CDC (Change Data Capture)»Debezium — стандарт де-факто для CDC:
- PostgreSQL: через logical replication slots (
wal2json,pgoutput). - MySQL: через binlog.
- MongoDB: через oplog.
- Публикует change events в Kafka.
Альтернативы: Maxwell, Striim, AWS DMS.
Кейсы:
- Outbox pattern (как описано выше).
- Реплицировать Postgres → ClickHouse для аналитики.
- Sync микросервисных БД (избегая sync RPC).
- Build search index (Elasticsearch) из Postgres.
5. Архитектура — уровень техлида
Заголовок раздела «5. Архитектура — уровень техлида»5.1 ADR (Architecture Decision Records)
Заголовок раздела «5.1 ADR (Architecture Decision Records)»Формат (Michael Nygard):
# ADR-007: Use Outbox Pattern for Event Publishing
## StatusAccepted
## ContextWe need to publish events to Kafka after DB commits.Direct calls cause dual-write inconsistency.
## DecisionUse Outbox table + Debezium for CDC.
## Consequences+ Atomicity guaranteed- Latency +50ms (acceptable)- Extra infra: Debezium + Kafka ConnectХранить в docs/adr/NNNN-title.md в репозитории. Tool: adr-tools CLI.
5.2 C4 Model
Заголовок раздела «5.2 C4 Model»4 уровня документации:
- Context — система и её внешние акторы.
- Container — приложения, БД, сервисы.
- Component — модули внутри container.
- Code — class diagram (опционально).
Инструменты: Structurizr, C4-PlantUML, draw.io с C4-шаблонами.
5.3 Module Boundaries + DDD стратегический
Заголовок раздела «5.3 Module Boundaries + DDD стратегический»Strategic DDD:
- Bounded Context — изолированная модель домена.
- Context Map — отношения между bounded contexts: Partnership, Shared Kernel, Customer-Supplier, Conformist, Anti-Corruption Layer, Open Host Service, Published Language.
- Ubiquitous Language — словарь, общий для бизнеса и кода.
Эвристики для границ:
- Один Bounded Context = одна команда (Conway’s Law).
- Один BC = одна модель «Order», даже если в логистике и продажах разные смыслы.
- Don’t share DB schema между BC.
5.4 API Versioning
Заголовок раздела «5.4 API Versioning»Три подхода:
- URL versioning:
/v1/users,/v2/users— самый простой. - Header versioning:
API-Version: 2,Accept-Version: 2. - Content-type versioning:
Accept: application/vnd.company.user+json; version=2.
Для gRPC: в proto файле выделять major-версию в пакет: myapi.v1, myapi.v2.
5.5 Backward / Forward Compatibility
Заголовок раздела «5.5 Backward / Forward Compatibility»Protobuf:
- Не удалять field numbers (mark as reserved).
- Не менять types.
- Не переименовывать enum values.
- Wire format гарантирует совместимость (unknown fields игнорируются).
JSON:
- Можно добавлять fields (опциональные).
- Не удалять, не менять types существующих.
- Опасно полагаться на field order.
5.6 Schema Registry
Заголовок раздела «5.6 Schema Registry»Confluent Schema Registry — централизованное хранилище схем (Avro/Protobuf/JSON Schema) для Kafka. Producers/consumers получают schema по ID.
Compatibility levels:
BACKWARD— новые consumers могут читать старые данные.FORWARD— старые consumers могут читать новые данные.FULL— оба.*_TRANSITIVE— для всех предыдущих версий.
Karapace — open-source альтернатива Confluent (Aiven). Совместим API. Используется в Российских инсталляциях.
5.7 Multi-tenant архитектура
Заголовок раздела «5.7 Multi-tenant архитектура»3 стратегии:
- Pool model: общая БД, tenant_id в каждой таблице. Самый дешёвый, но риск утечки данных.
- Bridge model: shared cluster, separate schemas per tenant.
- Silo model: отдельные БД на tenant. Максимальная изоляция, дорого.
Чаще всего: silo для enterprise, pool для self-serve.
5.8 Strangler Fig (для распилки монолита)
Заголовок раздела «5.8 Strangler Fig (для распилки монолита)»Постепенное замещение функциональности монолита микросервисами. Между клиентом и монолитом ставят facade/proxy, который маршрутизирует часть запросов на новый сервис. Со временем монолит «обернут» и можно убить.
Шаги:
- Identify seam (модуль/feature для извлечения).
- Build new service with same API.
- Route writes/reads через facade.
- Migrate data (dual-write или CDC).
- Decommission old code.
5.9 Event Storming
Заголовок раздела «5.9 Event Storming»Workshop-техника от Alberto Brandolini:
- Стикеры orange — domain events (“OrderPlaced”).
- Стикеры blue — commands (“PlaceOrder”).
- Стикеры yellow — aggregates (“Order”).
- Стикеры pink — external systems.
- Стикеры purple — policies/reactions.
Цель: разметить временную линию домена → выявить bounded contexts.
5.10 Trade-off мышление
Заголовок раздела «5.10 Trade-off мышление»Основные ось trade-offs:
- Consistency vs Availability (CAP) — в partition: что выбрать?
- Consistency vs Latency (PACELC) — даже без partition: ждать quorum или вернуть быстрее?
- Performance vs Cost — кэш vs больше CPU vs больше disk.
- Time-to-market vs Quality — MVP vs proper engineering.
- Sync vs Async — простота vs масштабируемость.
- Centralized vs Distributed — operational simplicity vs scale.
На интервью: никогда не давайте однозначный ответ. Сначала уточняйте контекст, затем озвучивайте trade-offs.
6. Базы данных — production-grade
Заголовок раздела «6. Базы данных — production-grade»6.1 PostgreSQL Deep Dive
Заголовок раздела «6.1 PostgreSQL Deep Dive»Query Planner
Заголовок раздела «Query Planner»- Cost-based optimizer на основе статистики (
pg_statistic). EXPLAIN ANALYZE BUFFERS— must-have для оптимизации.pg_stat_statements— топ-запросы по cumulative time.
Типы индексов
Заголовок раздела «Типы индексов»- B-tree: default, equality/range, sorted.
- Hash: только equality, реже используется.
- GIN (Generalized Inverted): для arrays, JSONB, full-text search (
tsvector). - GiST (Generalized Search Tree): geometric data, ranges, KNN.
- SP-GiST: space-partitioned (quadtree, kd-tree).
- BRIN (Block Range): для огромных таблиц с естественной сортировкой (time-series).
- Bloom: для multi-column equality, extension.
Partial Indexes
Заголовок раздела «Partial Indexes»CREATE INDEX idx_active_users ON users (last_login)WHERE deleted_at IS NULL;-- Индекс охватывает только 1% активных пользователей,-- но используется в 90% запросов.Реальный кейс: query time с 4.3s → 5ms за счёт partial index.
Covering Indexes (Go 11+)
Заголовок раздела «Covering Indexes (Go 11+)»CREATE INDEX idx_orders_user_status ON orders (user_id, status) INCLUDE (total);-- Index-only scan: не нужно лезть в heap для total6.2 HA: Patroni / Repmgr
Заголовок раздела «6.2 HA: Patroni / Repmgr»Patroni (по типу Stolon, Zalando) — лидер для PostgreSQL HA:
- Использует etcd/Consul/ZooKeeper для leader election.
- Автоматический failover.
- Streaming replication + sync standby.
Repmgr (2ndQuadrant): альтернатива, более «ручная», но проще установка.
Архитектура production:
[App] → [PgBouncer] → [Patroni primary] ↓ streaming repl [Standby 1] [Standby 2] ↓ async repl [Reporting replica]6.3 PgBouncer modes
Заголовок раздела «6.3 PgBouncer modes»| Mode | Когда возвращается в pool | Подходит для |
|---|---|---|
| Session | После disconnect клиента | Long-lived sessions, prepared statements |
| Transaction | После commit/rollback | Самый частый выбор для микросервисов |
| Statement | После statement | Очень редко, ломает многие фичи Postgres |
В transaction mode НЕ работают:
LISTEN/NOTIFY- Session-level
SET(используйтеSET LOCAL) - Prepared statements (PgBouncer 1.21+ это починил частично)
- Temporary tables
6.4 pg_stat_statements, pg_stat_activity
Заголовок раздела «6.4 pg_stat_statements, pg_stat_activity»-- Топ запросов по cumulative timeSELECT query, calls, total_exec_time, mean_exec_timeFROM pg_stat_statementsORDER BY total_exec_time DESCLIMIT 20;
-- Текущая активностьSELECT pid, usename, application_name, state, query, query_startFROM pg_stat_activityWHERE state != 'idle';
-- БлокировкиSELECT blocked_locks.pid AS blocked_pid, blocking_locks.pid AS blocking_pidFROM pg_catalog.pg_locks blocked_locksJOIN pg_catalog.pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktypeWHERE NOT blocked_locks.granted;6.5 Logical Replication
Заголовок раздела «6.5 Logical Replication»С Postgres 10+: publication/subscription, не вся БД, а отдельные таблицы.
-- На источникеCREATE PUBLICATION my_pub FOR TABLE orders, users;
-- На приёмникеCREATE SUBSCRIPTION my_subCONNECTION 'host=source dbname=mydb'PUBLICATION my_pub;Применения:
- Online migration major version.
- CDC через Debezium (на основе logical replication).
- Multi-region read replicas.
6.6 VACUUM и bloat
Заголовок раздела «6.6 VACUUM и bloat»PostgreSQL использует MVCC: при UPDATE/DELETE старая версия (tuple) остаётся, помечается dead.
VACUUM— освобождает место под новые tuples (в той же странице).VACUUM FULL— переписывает таблицу (блокирующая операция).pg_repack— non-blocking аналог VACUUM FULL.
Autovacuum tuning:
autovacuum_vacuum_scale_factor = 0.05 # default 0.2 — слишком поздно для больших таблицautovacuum_vacuum_cost_delay = 0 # больше нагрузка — но быстрееautovacuum_max_workers = 6 # default 3На горячих таблицах ставьте per-table:
ALTER TABLE orders SET ( autovacuum_vacuum_scale_factor = 0.01, autovacuum_vacuum_cost_limit = 2000);Источник: Snowflake: Postgres Vacuum Explained, Percona: Tuning Autovacuum
6.7 Distributed SQL: CockroachDB, YDB
Заголовок раздела «6.7 Distributed SQL: CockroachDB, YDB»CockroachDB:
- PostgreSQL wire compatible.
- Raft-based replication.
- Sharded by primary key ranges.
- Geo-distributed.
- Strong consistency (serializable).
YDB (Yandex):
- Open source с 2022.
- Кастомный YQL (SQL-подобный).
- Hybrid: OLTP + OLAP.
- Используется в Yandex.Cloud, в Яндекс Такси, Лавке, Маркете.
- В РФ — основной выбор для distributed SQL.
Сравнение:
| Свойство | CockroachDB | YDB | TiDB | YugabyteDB |
|---|---|---|---|---|
| Wire | PostgreSQL | YDB SDK / YQL | MySQL | PostgreSQL |
| Consensus | Raft | distributed | Raft (TiKV) | Raft |
| HTAP | нет | да | да | частично |
Источник: YDB.tech, CockroachDB vs TiDB vs YugabyteDB 2025
6.8 Tarantool (актуально для VK, Mail)
Заголовок раздела «6.8 Tarantool (актуально для VK, Mail)»In-memory DB + app server, Lua-скриптинг + WAL персистентность.
- Очень высокая пропускная: до 1M RPS на одном ядре.
- Используется в VK / Mail.ru: профили, ленты, кэши.
- Реплицируется master-master или master-replica.
В 2025-2026 (VK Tech): релиз Tarantool DB 3.0, открытое ядро + enterprise edition.
Go драйвер: tarantool/go-tarantool/v2.
conn, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})data, err := conn.Do(tarantool.NewSelectRequest("space").Index("primary").Key([]any{42})).Get()6.9 ClickHouse
Заголовок раздела «6.9 ClickHouse»Column-oriented analytical DB:
- Hibernate/MergeTree engine: данные хранятся колоночно, в part’ах (immutable файлы).
- Vectorized execution: SIMD-friendly, batch processing колонок.
- Partition by date обычно.
- Не для OLTP! Нет ACID, нет точечных UPDATE/DELETE (хотя есть
ALTER TABLE ... UPDATE— но не для частых операций). - Идеален для аналитики, логов, метрик. Используется в Яндекс, Авито, Cloudflare.
CREATE TABLE events ( timestamp DateTime, user_id UInt64, event_type LowCardinality(String), payload String) ENGINE = MergeTree()PARTITION BY toYYYYMM(timestamp)ORDER BY (event_type, user_id, timestamp);Go драйверы: clickhouse-go/v2 (нативный binary protocol), chproxy.
6.10 Vector Databases (для RAG/AI)
Заголовок раздела «6.10 Vector Databases (для RAG/AI)»Топ-3 в 2025:
- pgvector — extension к Postgres, простой, бесплатный, хорош до 10M векторов.
- Qdrant (написан на Rust, есть Go SDK) — purpose-built, отлично для production.
- Milvus — масштабируется лучше, сложнее operate.
-- pgvectorCREATE EXTENSION vector;CREATE TABLE embeddings (id INT, vec vector(1536));CREATE INDEX ON embeddings USING ivfflat (vec vector_cosine_ops);
SELECT id FROM embeddings ORDER BY vec <=> query_vec LIMIT 10;Применение: семантический поиск, RAG (Retrieval-Augmented Generation), рекомендации.
7. Очереди и стриминг
Заголовок раздела «7. Очереди и стриминг»7.1 Kafka Deep Dive
Заголовок раздела «7.1 Kafka Deep Dive»Core concepts
Заголовок раздела «Core concepts»- Topic = именованный лог, partitioned, replicated.
- Partition — единица параллелизма; messages внутри partition упорядочены.
- Replication Factor обычно 3.
- ISR (In-Sync Replicas) — реплики, актуальные относительно лидера.
Controller
Заголовок раздела «Controller»В Kafka 2.x: один из брокеров — controller (выбирается через ZooKeeper). В Kafka 3.0+: KRaft mode — Kafka использует свой собственный Raft для metadata, без ZooKeeper. С Kafka 4.0 (2025) — KRaft стал default.
Producer
Заголовок раздела «Producer»- Acks:
0(fire-and-forget),1(leader подтвердил),all/-1(все ISR подтвердили). - idempotent producer:
enable.idempotence=true— у producer есть PID, sequence number → broker отвергает дубликаты при retry. - Transactional producer:
transactional.id, методыbeginTransaction(),send(),commitTransaction(). Группирует записи в атомарную транзакцию.
Exactly-Once Semantics (EOS)
Заголовок раздела «Exactly-Once Semantics (EOS)»- Producer: idempotence + transactions.
- Consumer:
isolation.level=read_committed(видит только commit’нутые транзакции). - Consumer offsets коммитятся в той же транзакции что и output writes (“read-process-write” exactly-once).
- Kafka 4.0+ значительно ускорил transaction commits в KRaft mode.
Consumer Groups
Заголовок раздела «Consumer Groups»- Партиции распределяются между consumers группы.
- Rebalance при добавлении/удалении consumer (или sticky rebalance — меньше движений).
- Static membership (
group.instance.id) — не делать rebalance при кратковременном disconnect.
Schema Evolution в Kafka
Заголовок раздела «Schema Evolution в Kafka»- Producer пишет с schema ID (через Schema Registry).
- Consumer читает по schema ID + актуальная для consumer схема → автоматическое converting.
Источник: Confluent: Exactly-Once Semantics
7.2 Go-клиенты Kafka
Заголовок раздела «7.2 Go-клиенты Kafka»Сравнение (актуально 2025):
| Библиотека | Pros | Cons |
|---|---|---|
franz-go (twmb/franz-go) | Самая быстрая, feature-complete, pure Go, поддержка ВСЕХ Kafka features | API более низкоуровневый |
| segmentio/kafka-go | Простой API, чистый Go, хорошие production-history | Не все фичи (transactions неполные) |
sarama (IBM/sarama) | Самый старый, много примеров | Падающая поддержка, не поддерживает context |
| confluent-kafka-go | Лучшая поддержка от Confluent | CGo dependency (librdkafka), кросс-компиляция боль |
Современный выбор: franz-go для новых проектов, kafka-go если нужен простой API.
7.3 NATS JetStream продвинуто
Заголовок раздела «7.3 NATS JetStream продвинуто»JetStream = persistent layer над NATS Core.
js, _ := jetstream.New(nc)stream, _ := js.CreateStream(ctx, jetstream.StreamConfig{ Name: "ORDERS", Subjects: []string{"orders.>"}, Storage: jetstream.FileStorage, Replicas: 3,})
consumer, _ := stream.CreateConsumer(ctx, jetstream.ConsumerConfig{ Durable: "order-processor", AckPolicy: jetstream.AckExplicitPolicy, MaxDeliver: 5, AckWait: 30 * time.Second, FilterSubject: "orders.created",})
// Pull-consumer (рекомендуется)msgs, _ := consumer.Fetch(100, jetstream.FetchMaxWait(5*time.Second))for msg := range msgs.Messages() { process(msg) msg.Ack()}Особенности:
- KV store + Object Store как абстракции над streams.
- Cluster (Raft).
- Хорош для low-latency messaging внутри одного DC.
- Хуже Kafka для high-throughput (>100k/sec) и для очень больших ретеншенов.
7.4 Pulsar базово
Заголовок раздела «7.4 Pulsar базово»Apache Pulsar — конкурент Kafka:
- Topic = subscription model (несколько типов: exclusive, shared, key_shared, failover).
- Storage tier (Apache BookKeeper) отделён от broker.
- Geo-replication из коробки.
- Tiered storage (S3 archive старых данных).
Go: apache/pulsar-client-go. В РФ почти не используется (Kafka + NATS доминируют).
7.5 Backpressure в streaming
Заголовок раздела «7.5 Backpressure в streaming»Проблема: producer быстрее consumer → накапливаются сообщения → OOM.
Решения:
- Bounded channels/buffers.
- Rate limiting producer’а (
golang.org/x/time/rate). - Pause/resume polling consumer’а (Kafka: poll более редко).
- Drop strategies (для метрик): отбрасывать старые / выборочно.
- Reactive Streams pattern (request-N model).
7.6 DLQ Patterns
Заголовок раздела «7.6 DLQ Patterns»Dead Letter Queue — топик/очередь для сообщений, которые не удалось обработать после N попыток.
func handleMessage(ctx context.Context, msg Message) error { err := process(msg) if err != nil { msg.RetryCount++ if msg.RetryCount >= 5 { return sendToDLQ(ctx, msg, err) } return retryWithBackoff(ctx, msg) } return nil}Best practices:
- DLQ — для непреодолимых ошибок (поломанный payload).
- Алерт на любое попадание в DLQ.
- Tool для re-drive (повторная попытка после фикса) DLQ → main topic.
- Сохранять контекст ошибки (last error, attempt count, stack).
8. Cloud Native / Kubernetes продвинуто
Заголовок раздела «8. Cloud Native / Kubernetes продвинуто»8.1 Operators в Go
Заголовок раздела «8.1 Operators в Go»Kubebuilder — официальный SDK для написания operators на Go.
kubebuilder init --domain example.com --repo example.com/my-operatorkubebuilder create api --group apps --version v1 --kind MyAppСгенерированная структура:
api/v1/myapp_types.go— CRD spec/status.internal/controller/myapp_controller.go— Reconcile loop.config/— Kustomize манифесты.
Reconcile pattern
Заголовок раздела «Reconcile pattern»func (r *MyAppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { var app appsv1.MyApp if err := r.Get(ctx, req.NamespacedName, &app); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) }
// Ensure Deployment matches spec desired := buildDeployment(app) if err := ctrl.SetControllerReference(&app, desired, r.Scheme); err != nil { return ctrl.Result{}, err } if err := r.Patch(ctx, desired, client.Apply, client.ForceOwnership, client.FieldOwner("myapp-operator")); err != nil { return ctrl.Result{}, err }
// Update status app.Status.Phase = "Running" if err := r.Status().Update(ctx, &app); err != nil { return ctrl.Result{}, err }
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil}Принципы:
- Idempotency — Reconcile может вызываться сколько угодно, результат тот же.
- Level-based, not edge-based — реагируем на desired state, не на events.
- Status subresource — отделяется от Spec для оптимизации.
- Finalizers — для cleanup перед удалением.
8.2 CRD дизайн
Заголовок раздела «8.2 CRD дизайн»Best practices:
- Версионирование: v1alpha1 → v1beta1 → v1.
- Validating webhook: проверять CR на admission.
- Conversion webhook: для миграции между версиями.
- OpenAPI schema в CRD — для валидации в k8s API.
- Status conditions — стандартный pattern из k8s API.
status: conditions: - type: Ready status: "True" lastTransitionTime: "2026-05-21T10:00:00Z" reason: Reconciled message: "All resources created"8.3 Admission Webhooks
Заголовок раздела «8.3 Admission Webhooks»Validating admission: валидирует объекты при create/update. Mutating admission: модифицирует (например, добавляет sidecars, default values).
Реализация на Go через sigs.k8s.io/controller-runtime/pkg/webhook.
func (m *MyAppValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { app := obj.(*appsv1.MyApp) if app.Spec.Replicas < 1 { return nil, fmt.Errorf("replicas must be >= 1") } return nil, nil}8.4 Service Mesh: Istio, Linkerd, Ambient
Заголовок раздела «8.4 Service Mesh: Istio, Linkerd, Ambient»Istio:
- Polyglot service mesh.
- Envoy sidecar в каждом pod.
- Control plane: istiod.
- Фичи: mTLS, traffic shifting, observability, policy.
Linkerd:
- Простой, lightweight.
- Собственный proxy (linkerd2-proxy) на Rust.
- Меньше features, но проще operate.
Ambient mesh (Istio 2024+):
- Sidecarless: ztunnel (per node) + waypoint proxies (опционально).
- Меньше resources overhead.
- Постепенный uptake — пока что не все features работают.
8.5 Kubernetes API Extensions
Заголовок раздела «8.5 Kubernetes API Extensions»3 уровня:
- Aggregated API Server — добавить свой API server (например, metrics-server).
- CRDs + Operator — самый частый путь.
- CSI/CNI/CRI plugins — для storage/networking/container runtime.
8.6 Multi-cluster, Multi-region
Заголовок раздела «8.6 Multi-cluster, Multi-region»- Kubefed (deprecated) → KCP / Cluster API.
- Argo CD + GitOps для multi-cluster deploy.
- Submariner — network connectivity между clusters.
- Multi-cluster Services API — стандарт для cross-cluster service discovery.
Для микросервисов: чаще проще активный-пассивный регион + DNS failover, чем active-active multi-region.
9. Observability — уровень SRE
Заголовок раздела «9. Observability — уровень SRE»9.1 OpenTelemetry полностью
Заголовок раздела «9.1 OpenTelemetry полностью»Три pillar’а:
- Traces — distributed traces со span’ами.
- Metrics — числовые временные ряды.
- Logs — структурированные логи (с TraceID для correlation).
Go SDK setup
Заголовок раздела «Go SDK setup»import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc")
exp, _ := otlptracegrpc.New(ctx)tp := trace.NewTracerProvider( trace.WithBatcher(exp), trace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceName("my-service"), semconv.ServiceVersion("v1.2.3"), )),)otel.SetTracerProvider(tp)defer tp.Shutdown(ctx)
// Использованиеtracer := otel.Tracer("my-package")ctx, span := tracer.Start(ctx, "operation")defer span.End()Semantic Conventions
Заголовок раздела «Semantic Conventions»Стандартизированные имена attributes:
http.method,http.status_code,http.urldb.system,db.statement,db.operationmessaging.system,messaging.destination.namerpc.system,rpc.service,rpc.method
В Go runtime (через runtime/metrics):
go.memory.used,go.memory.limit,go.gc.duration,go.goroutine.count
Baggage
Заголовок раздела «Baggage»Baggage — propagated key-value через distributed trace. Не путать с span attributes (только на spaн’е).
bag, _ := baggage.New(baggage.NewKeyValueProperty("tenant_id", "42"))ctx = baggage.ContextWithBaggage(ctx, bag)// Передаётся через HTTP/gRPC headers (W3C Baggage)⚠️ Не клади много данных в baggage — это вес каждого outgoing request.
Exemplars
Заголовок раздела «Exemplars»Exemplar — связь между метрикой и конкретным trace ID. Когда видишь spike в P99 latency → клик → попадаешь в тот самый trace.
// Prometheus + OTel exemplarshist := prometheus.NewHistogramVec(...)hist.With(labels).(prometheus.ExemplarObserver).ObserveWithExemplar( duration.Seconds(), prometheus.Labels{"trace_id": traceID},)9.2 SLO / SLI / SLA, Error Budgets
Заголовок раздела «9.2 SLO / SLI / SLA, Error Budgets»Определения:
- SLI: квантитативная метрика (% successful requests).
- SLO: target value (99.9% over 30 days).
- SLA: контракт с пользователем (с финансовыми последствиями).
- Error Budget = 100% - SLO.
Пример:
- SLI:
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) - SLO: 99.9% за 30 дней.
- Error budget: 0.1% × N запросов = бюджет ошибок.
Burn rate alerting (multi-window, multi-burn-rate):
- 2% бюджета за 1 час (быстро жжём) → P1 alert.
- 10% бюджета за 6 часов (медленно жжём, но накапливается) → P2 alert.
Error budget policy:
- Бюджет не исчерпан → можно деплоить.
- Бюджет исчерпан → стоп фич, только bug fixes / reliability work.
Источник: Google SRE Workbook: Implementing SLOs
9.3 RED method, USE method
Заголовок раздела «9.3 RED method, USE method»RED (для request-driven сервисов):
- Rate — requests/sec
- Errors — errors/sec
- Duration — latency distribution
USE (для resources: CPU, disk, network):
- Utilization
- Saturation (queue depth)
- Errors
Дополняют друг друга: RED — взгляд снаружи (как клиент), USE — взгляд изнутри.
9.4 Postmortems
Заголовок раздела «9.4 Postmortems»Blameless postmortem:
- Timeline (точные временные метки).
- Impact (затронутые SLO, пользователи, $).
- Root cause (5 whys).
- Detection (как заметили?).
- Action items (с owner и deadline).
Tooling: Notion, Confluence, Linear, специализированные incident.io.
9.5 Production Debugging
Заголовок раздела «9.5 Production Debugging»Чек-лист на проде:
- Метрики: что выросло/упало? (Grafana, Datadog)
- Логи: ищем ERROR в окне инцидента (Loki, ELK).
- Tracing: смотрим failing traces (Jaeger, Tempo, Datadog APM).
- Profiling: live pprof endpoint (если безопасно).
- Goroutine dump:
curl /debug/pprof/goroutine?debug=2.
Частые проблемы:
- Goroutine leak →
NumGoroutine()растёт линейно. - Connection leak → max_open_conns исчерпан.
- Cache stampede → singleflight forgotten.
- Memory leak → heap profile diff (before vs after).
- Slow queries →
pg_stat_statements.
9.6 Chaos Engineering
Заголовок раздела «9.6 Chaos Engineering»Принципы (Netflix Chaos Manifesto):
- Hypothesize about steady state.
- Vary real-world events.
- Run in production.
- Automate experiments.
- Minimize blast radius.
Инструменты:
- Chaos Mesh (CNCF) — для k8s, удобный UI, fault injection (network, pod, IO, time).
- LitmusChaos (CNCF) — Hub предопределённых экспериментов, удобно для CI/CD.
- Gremlin — commercial.
# Chaos Mesh: убиваем 30% pod'ов сервисаapiVersion: chaos-mesh.org/v1alpha1kind: PodChaosmetadata: name: pod-failure-examplespec: action: pod-failure mode: fixed-percent value: "30" duration: "60s" selector: namespaces: - default labelSelectors: "app": "my-service"В 2025: LitmusChaos выпустили MCP Server для интеграции с AI ассистентами.
Источник: Chaos Engineering 2025 Guide
10. Security — продвинуто
Заголовок раздела «10. Security — продвинуто»10.1 mTLS, SPIFFE/SPIRE
Заголовок раздела «10.1 mTLS, SPIFFE/SPIRE»mTLS: обе стороны (client и server) предоставляют certs.
SPIFFE (Secure Production Identity Framework For Everyone) — стандарт workload identity (CNCF). SPIRE — reference implementation SPIFFE.
spiffe://example.org/ns/default/sa/my-serviceWorkflow:
- SPIRE Agent (на каждой ноде) аттестует workload (через k8s labels, container image hash, etc.).
- Выдаёт SVID (SPIFFE Verifiable Identity Document) — короткоживущий X.509 cert или JWT.
- Auto-renewal до expiry.
Go SDK: go-spiffe/v2.
source, _ := workloadapi.NewX509Source(ctx)defer source.Close()
tlsConfig := tlsconfig.MTLSClientConfig(source, source, tlsconfig.AuthorizeAny())client := &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}Используют: Bloomberg, Pinterest, Uber, Square. В РФ — внедряется на крупных платформах.
10.2 Secrets Management
Заголовок раздела «10.2 Secrets Management»HashiCorp Vault — лидер. Acquired by IBM в 2025. SOPS (Mozilla) — для GitOps (зашифрованные YAML/JSON в Git). Sealed Secrets (Bitnami) — k8s native, encrypted в кластере. External Secrets Operator — bridge между Vault/AWS Secrets Manager и k8s Secrets.
Best practices:
- Never hardcode secrets.
- Short-lived dynamic credentials (Vault DB roles).
- Rotation automation.
- Audit logs.
- Encryption at rest + in transit.
- File-mounted secrets > environment variables (env видны в /proc).
10.3 SBOM (Software Bill of Materials)
Заголовок раздела «10.3 SBOM (Software Bill of Materials)»Syft (Anchore) — генерация SBOM из контейнеров, директорий, jar.
syft my-image:latest -o cyclonedx-json > sbom.jsonGrype (Anchore) — поиск vulnerabilities по SBOM.
grype sbom:./sbom.jsonСтандартные форматы: CycloneDX, SPDX.
10.4 Sigstore, cosign
Заголовок раздела «10.4 Sigstore, cosign»Sigstore — keyless code signing для open-source supply chain.
- Fulcio: short-lived certificates (OIDC).
- Rekor: transparency log (tamper-evident).
- Cosign: CLI для signing/verification.
# Sign imagecosign sign --yes my-registry/my-image:v1.0
# Verifycosign verify --certificate-identity-regexp '.*' --certificate-oidc-issuer-regexp '.*' my-registry/my-image:v1.010.5 Supply Chain Security
Заголовок раздела «10.5 Supply Chain Security»SLSA (Supply chain Levels for Software Artifacts) framework:
- L1: документированный build process.
- L2: tamper-resistant build platform.
- L3: trusted, verifiable provenance.
- L4: highest assurance.
Минимальный pipeline 2025:
- CI: build → run tests → generate SBOM (Syft).
- Sign artifact (cosign).
- Create SLSA provenance.
- Push to registry.
- At deploy: verify signature + provenance.
10.6 Threat Modeling (STRIDE)
Заголовок раздела «10.6 Threat Modeling (STRIDE)»Spoofing — подмена identity. Tampering — изменение данных. Repudiation — отрицание действий. Information disclosure — утечка. Denial of service. Elevation of privilege.
Сессии threat modeling: рисуем data flow diagram → ищем для каждого компонента STRIDE угрозы → mitigations.
10.7 Шифрование, KMS
Заголовок раздела «10.7 Шифрование, KMS»AWS KMS / GCP Cloud KMS / Yandex KMS:
- Envelope encryption: данные шифруем DEK (data encryption key), DEK шифруем KEK (key encryption key) в KMS.
- Auto-rotation KEK.
- Audit log использования.
Go: cloud.google.com/go/kms, github.com/aws/aws-sdk-go-v2/service/kms.
client, _ := kms.NewClient(ctx)ciphertext, _ := client.Encrypt(ctx, &kmspb.EncryptRequest{ Name: "projects/p/locations/l/keyRings/k/cryptoKeys/key", Plaintext: plainData,})11. Лидерство и софт-скиллы (важно на Middle 3)
Заголовок раздела «11. Лидерство и софт-скиллы (важно на Middle 3)»11.1 Менторинг джунов
Заголовок раздела «11.1 Менторинг джунов»Принципы:
- Дай задачу с границами — джун должен понимать “что”, иметь свободу в “как”.
- Pair programming — 30 мин в неделю с каждым.
- Code review как обучение, не как gatekeeping.
- Спрашивай “почему”, а не указывай “что”.
- Регулярные 1:1 — статус, рост, проблемы.
11.2 Code Review
Заголовок раздела «11.2 Code Review»Чек-лист:
- Корректность: решает ли PR задачу?
- Архитектура: вписывается в существующий код?
- Concurrency: data races, goroutine leaks, deadlock?
- Производительность: hot path аллокации, N+1 queries?
- Тесты: покрытие, edge cases, table-driven?
- Безопасность: SQL injection, secrets in code, weak crypto?
- Читаемость: naming, комментарии для “почему”, не “что”.
Тон:
- ✅ “What do you think about extracting this into a separate function?”
- ❌ “This is wrong. Rewrite.”
11.3 Tech Design Review
Заголовок раздела «11.3 Tech Design Review»Структура design doc:
- Problem statement — что решаем?
- Goals & Non-goals — границы.
- Proposed Solution — текущий вариант.
- Alternatives Considered — что отбросили и почему.
- Trade-offs — что теряем.
- Migration Plan — как развернуть без даунтайма.
- Open Questions — что неясно.
Длина: 1-3 страницы для small change, до 10-15 для крупной системы.
11.4 Estimation
Заголовок раздела «11.4 Estimation»Принципы:
- Power of 2: оценивай в 1, 2, 4, 8, 16… — точность ниже, чем кажется.
- 3-point estimation: best / nominal / worst (PERT).
- Buffer 20-50% на «unknown unknowns».
- Estimates не дедлайны — отдельные понятия.
- Decompose до задач ≤ 1 неделя.
11.5 Работа со стейкхолдерами
Заголовок раздела «11.5 Работа со стейкхолдерами»- Product Managers: говори про business value, не про tech detail.
- Designers: эмпатия, не «это нельзя».
- Other Teams: write things down (ADR/RFC), документация — лучший diplomat.
- CTO / VP: говори в SLI/SLO/$ языке.
11.6 Документация
Заголовок раздела «11.6 Документация»Иерархия:
- CHANGELOG — что изменилось.
- README — как запустить.
- CONTRIBUTING — как контрибутить.
- docs/architecture — high-level.
- docs/adr/ — решения.
- docs/runbook/ — на случай инцидента.
11.7 Карьерный план Middle 3 → Senior
Заголовок раздела «11.7 Карьерный план Middle 3 → Senior»См. Раздел 17-18.
12. System Design на Middle 3 интервью
Заголовок раздела «12. System Design на Middle 3 интервью»Каждая задача — 45-60 минут, кандидат должен:
- Уточнить требования (5-10 мин): RPS, размеры, SLA.
- Estimate capacity (5 мин).
- High-level design (15 мин): нарисовать boxes & arrows.
- Deep dive (15-20 мин): один-два компонента детально.
- Trade-offs, edge cases (5-10 мин).
12.1 URL Shortener (TinyURL/bit.ly)
Заголовок раздела «12.1 URL Shortener (TinyURL/bit.ly)»Требования: 100M URLs/day, redirect P99 < 50ms, 100:1 read:write, custom aliases.
Capacity:
- 100M/day = ~1200 writes/sec.
- 100:1 → 120k reads/sec.
- 5 лет storage = 100M × 365 × 5 ≈ 180B URLs.
- Длина short URL: 7 символов base62 = 62^7 = 3.5T — хватит.
Architecture:
[CDN] ↓[API Gateway + Rate Limit] ↓[App Server (Go)] —→ [Redis cluster] (cache, TTL 24h) —→ [Database (Postgres / Cassandra)] ↘ [Counter Service (Zookeeper)] для unique IDsАлгоритм short-code:
- Подход A: счётчик + base62 → коллизий 0, но предсказуемо.
- Подход B: hash(url) первые 7 байт base64 → коллизии возможны → check + retry.
- Подход C: pre-generated unused IDs в БД, app server бронирует пачку.
Edge cases:
- Custom alias collision → 409.
- Same long URL → возвращать существующий short.
- Bot crawling → rate limit + CAPTCHA.
12.2 Distributed Cache (Memcached/Redis-like)
Заголовок раздела «12.2 Distributed Cache (Memcached/Redis-like)»Требования: < 1ms latency, 10TB capacity, eventual consistency.
Архитектура:
- Consistent hashing для шардирования (с virtual nodes для уменьшения rebalance).
- Replication: каждый ключ — primary + 2 replicas.
- Eviction: LRU / LFU / TTL.
- Cache patterns: cache-aside, write-through, write-behind, refresh-ahead.
Cache stampede protection:
- Singleflight: только один request за key.
- Probabilistic early refresh: refresh с вероятностью, растущей при приближении TTL.
- Lock + busy-loop ожидания.
12.3 Notification System
Заголовок раздела «12.3 Notification System»Требования: push + email + SMS, 1M notifications/sec, user preferences, idempotency.
Архитектура:
[Sender API] → [Kafka topic per channel] ↓ [Push worker] → [APNs/FCM] [Email worker] → [SES] [SMS worker] → [Twilio] ↓ [Tracking DB] [DLQ]Особенности:
- User Preferences Service: rate limits, quiet hours, opt-outs.
- Templating Service: шаблоны с подстановкой.
- Retry with exponential backoff.
- Bounce handling (для email).
12.4 Rate Limiter
Заголовок раздела «12.4 Rate Limiter»Алгоритмы:
- Fixed window: counter за минуту → проблема burst на границе окна.
- Sliding window log: sorted set с timestamps → точно, но дорого.
- Sliding window counter: counter текущего + предыдущего окна, взвешенно.
- Token bucket: пополнение N токенов/сек, расходуем при request.
- Leaky bucket: queue с фиксированной скоростью выхода.
Distributed implementation:
- Redis с Lua scripting (атомарность).
- Локальное счёт + periodic sync (для очень высокого throughput).
- Sliding window log в Redis sorted set:
local now = tonumber(ARGV[1])local window = tonumber(ARGV[2])redis.call('ZREMRANGEBYSCORE', KEYS[1], 0, now - window)local count = redis.call('ZCARD', KEYS[1])if count < tonumber(ARGV[3]) then redis.call('ZADD', KEYS[1], now, now) return 1endreturn 012.5 Распределённая очередь (Kafka/SQS-like)
Заголовок раздела «12.5 Распределённая очередь (Kafka/SQS-like)»См. раздел 7. Ключевые точки:
- Partitioning (хэш ключа).
- Replication (leader + followers, ISR).
- Persistence (commit log на диск).
- Consumer offsets — где остановились.
- Ordering guarantee — внутри partition.
- Delivery semantics: at-most-once, at-least-once, exactly-once.
12.6 Поиск (Elasticsearch-style)
Заголовок раздела «12.6 Поиск (Elasticsearch-style)»Архитектура:
- Indexing pipeline: writes → CDC → Kafka → Indexer → Elasticsearch.
- Inverted index: term → list of doc IDs.
- Sharding by doc ID hash.
- Replication: replica для read availability.
- Scoring: TF-IDF / BM25 + bizness rules + ML re-ranking.
Особенности:
- Eventual consistency (latency 1-10s от записи до index).
- Full-text + filter + facets.
- Autocomplete: prefix trie / edge n-grams.
12.7 Чат (WhatsApp/Telegram-like)
Заголовок раздела «12.7 Чат (WhatsApp/Telegram-like)»Требования: 100B msgs/day, real-time delivery, end-to-end encryption optional.
Архитектура:
[Client] ←-WebSocket--→ [Gateway (sticky session)] ↓ [Chat Service (Go)] ↓ [Cassandra/ScyllaDB messages] + [Redis presence] ↓ on offline [Push Notification Service]Ключевые решения:
- WebSocket для real-time + reconnection.
- Message ID generation: Snowflake (timestamp + machine + seq).
- Storage: wide-column (Cassandra) для conversations.
- Read receipts: пишем при delivery + read.
- Group chats: fanout на write (deliver к каждому участнику).
- Encryption: Signal protocol для E2EE (опционально).
12.8 Лента (Twitter/Instagram feed)
Заголовок раздела «12.8 Лента (Twitter/Instagram feed)»Подходы:
- Pull (lazy): при открытии ленты собираем посты от подписок. Просто, но медленно для users с тысячами подписок.
- Push (fanout-on-write): при post — рассылаем в Redis ленты подписчиков. Быстро read, но дорого write для celebrities (10M подписчиков).
- Hybrid: pull для celebrities + push для обычных пользователей.
Архитектура:
[Post Service] → [Fanout Service] → [Redis Timeline per user] ↓ [ML Ranker (рекомендации)] → final feed12.9 Платёжная система
Заголовок раздела «12.9 Платёжная система»Ключевые принципы:
- Idempotency (идемпотентные ключи на любой операции).
- Double-entry bookkeeping (для аудита: каждая транзакция — две записи).
- Strong consistency (часто SQL DB, не NoSQL).
- Audit log — append-only, immutable.
- Reconciliation — daily/hourly: сверка наших данных с внешними системами.
- Saga для multi-step transactions.
- PCI DSS compliance — не хранить карточные данные, только tokens.
12.10 Логистика / GPS-трекинг
Заголовок раздела «12.10 Логистика / GPS-трекинг»Архитектура:
- MQTT для приёма телеметрии (миллионы курьеров).
- Stream processing (Flink/Kafka Streams) для агрегации.
- Geo-spatial DB: PostGIS, Elasticsearch geo_point, или специализированные (Tile38).
- Map matching — снапим GPS к дорожной сети.
- ETA prediction — ML модель + actuals from history.
13. Алгоритмы и data structures на собесе
Заголовок раздела «13. Алгоритмы и data structures на собесе»13.1 LeetCode паттерны (Top-15)
Заголовок раздела «13.1 LeetCode паттерны (Top-15)»- Two Pointers — sorted array, в т.ч. 3sum.
- Sliding Window — substring проблемы.
- Fast/Slow Pointers (Floyd) — linked list cycles.
- Merge Intervals — overlapping intervals.
- Cyclic Sort — array с числами в диапазоне.
- In-place Reversal of Linked List.
- Tree BFS/DFS — level order, path sum.
- Topological Sort — DAG.
- Union Find — connected components.
- Binary Search — sorted/almost-sorted.
- Heap (Top K) — priority queue.
- Backtracking — permutations, combinations.
- DP — knapsack, LCS, edit distance.
- Greedy — interval scheduling.
- Bit Manipulation — XOR tricks.
13.2 Конкурентные задачи (mutex/channel-based)
Заголовок раздела «13.2 Конкурентные задачи (mutex/channel-based)»Classic problems
Заголовок раздела «Classic problems»- Concurrent Map:
sync.RWMutexvssync.Map. - Worker Pool with graceful shutdown (см. ниже).
- Rate Limiter (token bucket).
- Channel-based semaphore.
- Producer-Consumer с bounded buffer.
- Pipeline pattern (stage1 → stage2 → stage3).
- Fan-out/Fan-in для параллельной обработки.
- Reader-Writer lock от руки.
- Barrier для N горутин.
- Implementing context.Context от руки.
Worker Pool with graceful shutdown
Заголовок раздела «Worker Pool with graceful shutdown»Классическая задача на собесе Авито/Яндекс:
type WorkerPool struct { workers int tasks chan Task wg sync.WaitGroup}
func NewWorkerPool(workers int) *WorkerPool { return &WorkerPool{ workers: workers, tasks: make(chan Task), }}
func (p *WorkerPool) Start(ctx context.Context) { for i := 0; i < p.workers; i++ { p.wg.Add(1) go func(id int) { defer p.wg.Done() for { select { case <-ctx.Done(): return case task, ok := <-p.tasks: if !ok { return } task.Run(ctx) } } }(i) }}
func (p *WorkerPool) Submit(t Task) error { select { case p.tasks <- t: return nil default: return ErrQueueFull }}
func (p *WorkerPool) Shutdown() { close(p.tasks) p.wg.Wait()}13.3 System-level задачи
Заголовок раздела «13.3 System-level задачи»- LRU Cache — на двусвязном списке + map. O(1) get/put.
- LFU Cache — сложнее: 2 hashmap + sorted linked list.
- Skip List — реализовать.
- Bloom Filter — реализовать.
- Consistent Hashing ring.
- Trie — для autocomplete.
- Token Bucket Rate Limiter.
- Concurrent Queue (lock-free).
- TimerWheel — для миллионов таймеров.
- B+ Tree (для DB engine).
Sample: LRU Cache на Go
Заголовок раздела «Sample: LRU Cache на Go»type LRUCache struct { capacity int cache map[int]*list.Element list *list.List}
type kv struct{ k, v int }
func NewLRU(cap int) *LRUCache { return &LRUCache{ capacity: cap, cache: make(map[int]*list.Element), list: list.New(), }}
func (c *LRUCache) Get(k int) (int, bool) { if e, ok := c.cache[k]; ok { c.list.MoveToFront(e) return e.Value.(*kv).v, true } return 0, false}
func (c *LRUCache) Put(k, v int) { if e, ok := c.cache[k]; ok { e.Value.(*kv).v = v c.list.MoveToFront(e) return } if c.list.Len() == c.capacity { oldest := c.list.Back() c.list.Remove(oldest) delete(c.cache, oldest.Value.(*kv).k) } e := c.list.PushFront(&kv{k, v}) c.cache[k] = e}14. Типичные вопросы на собеседовании Middle 3 Go (100+)
Заголовок раздела «14. Типичные вопросы на собеседовании Middle 3 Go (100+)»A. Internals (deep dive scheduler, GC, memory)
Заголовок раздела «A. Internals (deep dive scheduler, GC, memory)»1. Расскажи про GMP-модель Go scheduler. Что такое work stealing?
G — goroutine, M — OS thread, P — processor (логический). Каждый P имеет local run queue (256). M выполняет G только когда держит P. Когда P пуст — он крадёт половину задач из чужого P (work stealing). Глобальная очередь — fallback. С Go 1.14 — async preemption через сигналы (SIGURG), долгие goroutines прерываются sysmon-потоком каждые 10ms.
2. Что такое sysmon? Какая у него функция?
Системный монитор-поток, не привязан к P. Каждые 10ms проверяет: blocked syscalls (отнимает P), preemptable goroutines (sets stack guard), netpoll события, форс GC если давно не было.
3. Что произойдёт при GOMAXPROCS=1 и двух CPU-bound горутинах?
Они будут выполняться по очереди на единственном P через preemption (async с 1.14). До 1.14 — одна могла монополизировать CPU если не делала функциональных вызовов.
4. Как работает сборщик мусора в Go? Какие фазы?
Concurrent tri-color mark-and-sweep на основе Dijkstra. Фазы: STW prep (микросекунды) → Concurrent mark (с write barrier, mark assist) → STW mark termination → Concurrent sweep. Pacer решает когда стартовать на основе пропорции скорости аллокаций.
5. Что такое write barrier?
Код, вставляемый компилятором перед каждой записью указателя в objects во время concurrent mark phase. Помечает старый указатель как достижимый, чтобы GC не пропустил при concurrent изменении графа объектов.
6. Расскажи про escape analysis. Когда переменная попадает в кучу?
Компилятор анализирует, может ли время жизни переменной выйти за рамки функции. Если да — heap. Причины: возврат указателя, передача в interface, в горутину, слишком большой объект (>64KB), сохранение в глобал.
go build -gcflags="-m"показывает решения.
7. Что такое GOGC и GOMEMLIMIT?
GOGC — процент роста heap для запуска GC (default 100, т.е. удвоение). GOMEMLIMIT (с 1.19) — soft memory limit, GC старается не превысить. В контейнерах: GOMEMLIMIT=90% от limit, GOGC=100 или 200.
8. Почему советуют GOGC=off + GOMEMLIMIT?
Для memory-bound сервисов: GC будет запускаться только при достижении GOMEMLIMIT (а не при удвоении). Меньше CPU overhead, эффективнее память. Подходит для long-lived сервисов без бурных скачков аллокаций.
9. Что такое PGO? Какой профит в production?
Profile-Guided Optimization (Go 1.21+). Подаёшь компилятору CPU-профиль с production → агрессивный inlining/devirtualization для горячих функций. 2-14% улучшение CPU. Uber, Datadog, Google используют.
10. Как работает мап в Go?
До 1.24: открытая адресация по бакетам (по 8 элементов), коллизии → overflow buckets. Resize при load factor > 6.5. С 1.24: Swiss Tables — SIMD-friendly metadata, extendible hashing с table splitting вместо incremental evacuation.
11. Что произойдёт если в map писать из двух горутин без синхронизации?
Race condition. С -race детектируется. В runtime есть проверка concurrent writes — программа упадёт с
fatal error: concurrent map writes.
12. Slice — что внутри? Что происходит при append?
Slice — struct {data ptr, len, cap}. append: если len < cap → пишем в существующий array. Если len == cap → новый array (с роста 2x до 256, потом ~1.25x), копируем. Возвращается новый slice header.
13. Почему s := make([]int, 0, 1000) — это хорошая практика?
Pre-allocate capacity → нет повторных allocations при append, меньше GC pressure, predictable performance.
14. Что такое sync.Map? Когда использовать?
Concurrent map с двумя внутренними map (read + dirty). Read — lock-free через atomic.Value, dirty — под mutex. Promotion dirty → read когда misses достигают len(dirty). Хорош для read-heavy + disjoint keys (разные горутины обращаются к разным ключам). Часто map+RWMutex быстрее для смешанных нагрузок.
15. Чем отличается buffered от unbuffered канала?
Unbuffered — синхронный (sender блокируется до приёма). Buffered — асинхронный до cap, потом блокируется. Unbuffered полезен для synchronization point, buffered — для smoothing burst.
16. Что произойдёт при чтении из закрытого канала?
Получаем zero value + ok=false. Для уже находящихся в буфере значений — сначала их, потом zero. Запись в закрытый канал — panic.
17. Что такое sudog?
Suspended goroutine — структура в runtime, представляет горутину, ожидающую на канале. Хранит указатель на g, элемент данных, prev/next для очереди. Кладётся в hchan.recvq/sendq.
18. Как работает select со стандартными default и timeout?
Runtime пытается каждый case в случайном порядке (pseudo-random для fairness). Если ни один не готов и есть default — выполнит default. С timeout —
case <-time.After(d):создаёт канал, который сработает через d.
19. Утечка time.After — что это и как избежать?
time.Afterсоздаёт*Timerкоторый остаётся в runtime до срабатывания. Если в hot path → миллионы Timer. Решение:timer := time.NewTimer(d); defer timer.Stop().
20. Что такое context.Context? Какие виды?
Интерфейс для cancellation, deadline, values. Реализации: emptyCtx (Background, TODO), cancelCtx (WithCancel/WithCancelCause), timerCtx (WithDeadline/WithTimeout), valueCtx (WithValue). Должен быть первым аргументом функций.
21. Что не нужно класть в context.Value?
Optional параметры функции, конфигурацию. Только request-scoped данные: trace ID, user ID, tenant ID. Иначе теряется type safety и явность API.
22. Что такое linkname?
//go:linkname myname runtime.functionName— компиляторская директива, позволяет вызывать private функцию из стандартной библиотеки. Опасно, может сломаться в новой версии Go.
23. Как профилировать Go-программу?
Импортировать
net/http/pprof, открыть:6060/debug/pprof/. Профили: CPU, heap (in-use), allocs (total), goroutine, mutex, block.go tool pprof -http=:8080 profile.out— UI. С 1.21+ есть PGO интеграция.
24. Чем отличается heap profile от allocs?
Heap — что сейчас alloc’ed в куче (live objects). Allocs — все аллокации за всё время работы программы (включая GC’нутые). Для поиска hot allocators — allocs. Для memory leak — heap diff.
25. Что такое runtime/trace? Когда использовать?
Покажет goroutine timeline: что когда выполнялось, syscalls, GC pauses, scheduler events. Тяжелее pprof.
runtime/trace.Start(file)+ смотретьgo tool trace trace.out. Для расследования latency проблем.
B. Concurrency expert level
Заголовок раздела «B. Concurrency expert level»26. Реализуй worker pool с graceful shutdown через context.
См. пример в разделе 13.2.
27. Что такое fan-in / fan-out?
Fan-out: один producer → N workers через распределение задач. Fan-in: N продюсеров → один aggregated канал. Часто комбинируют для пайплайна.
28. errgroup — что делает и когда использовать?
golang.org/x/sync/errgroup— group горутин с context cancellation и сбором первой ошибки. Первая ошибка отменяет context для остальных. Удобно для concurrent requests с правильной отменой.
29. Что такое singleflight?
golang.org/x/sync/singleflight— дедупликация одинаковых in-flight операций. Только один вызов идёт, остальные ждут результат. Защита от cache stampede.
30. Как реализовать рейт-лимитер?
Token bucket: канал размера N, тикер пополняет. Или
golang.org/x/time/rate(стандарт). Для distributed — Redis (sorted set / counter with TTL).
31. Что такое starvation в Go mutex?
Если goroutine ждёт > 1ms — mutex входит в starvation mode: lock передаётся FIFO ждущим, новые тред-в спин блокируются. Защита от голодания. С Go 1.9+.
32. Какие race condition могут быть с map?
Concurrent read + write → panic. Concurrent only-reads → ОК. Concurrent writes → panic. Решение: sync.Map или RWMutex.
33. Goroutine leak — как обнаружить?
runtime.NumGoroutine()мониторить во времени. pprof goroutine endpoint → смотреть стектрейсы. С Go 1.25+ есть synctest, с 1.26+ — goroutineleak профиль.
34. Почему defer в цикле может быть проблемой?
Все defer накапливаются и выполнятся только при return функции. Если в цикле открываешь файлы и делаешь
defer f.Close()— все файлы открыты до конца функции. Решение: выносить в отдельную функцию.
35. Channel или mutex — что выбрать?
“Share memory by communicating” — channel для передачи owner-ship данных. Mutex — для защиты доступа к shared state. Не догма: счётчики проще через atomic/mutex, передача события — через channel.
36. Что такое spinlock в Go?
Активное ожидание (CPU крутит loop, проверяя условие). Используется в runtime mutex для коротких блокировок (пара десятков циклов). В user space —
runtime.Gosched()или ждать через channel.
37. False sharing — что и как избежать?
Две переменные на разных горутинах попадают в одну CPU cache line (64B) → invalidation pingpong. Решение: padding
_[56]byteмежду ними. Актуально для счётчиков в high-contention сценариях.
38. Реализуй concurrent queue (lock-free).
Через
atomic.Pointer(Go 1.19+). MPSC проще: head пишет только consumer, tail — producers через Swap. См. раздел 2.3.
39. ABA-проблема — что это?
CAS видит “то же значение”, но между чтением и CAS оно поменялось и вернулось. В Go GC снижает риск (память не освобождается), но в low-level structures — tagged pointers / version counters.
40. Реализуй semaphore через channel.
type Semaphore chan struct{}func New(n int) Semaphore { return make(Semaphore, n) }func (s Semaphore) Acquire() { s <- struct{}{} }func (s Semaphore) Release() { <-s }C. БД + распределённые системы
Заголовок раздела «C. БД + распределённые системы»41. Чем отличаются isolation levels в Postgres?
Read Uncommitted (Postgres = Read Committed по факту), Read Committed (default), Repeatable Read (snapshot isolation на старте транзакции), Serializable (SSI — Serializable Snapshot Isolation). REPEATABLE READ предотвращает non-repeatable read, SERIALIZABLE еще и phantom read.
42. Что такое MVCC?
Multi-Version Concurrency Control. UPDATE не перезаписывает, а создаёт новую версию. У каждого tuple — xmin (transaction inserted), xmax (deleted/updated by). Readers видят snapshot на момент start (Repeatable Read) или на момент statement (Read Committed). Не блокируют writers.
43. Что такое VACUUM и почему нужен autovacuum?
MVCC оставляет dead tuples (старые версии). VACUUM освобождает место для повторного использования. Без autovacuum — таблица растёт, deteriorates. На крупных таблицах — кастомные настройки (scale_factor=0.05).
44. Какие типы индексов в Postgres?
B-tree (default, sorted/range), Hash, GIN (arrays, JSONB, FTS), GiST (geo, range, KNN), SP-GiST, BRIN (для отсортированных больших таблиц).
45. Когда использовать partial index?
Когда индексируем только подмножество строк (например,
WHERE deleted_at IS NULL). Уменьшает размер индекса в десятки раз, ускоряет writes (меньше обновлять индекс).
46. EXPLAIN ANALYZE — на что смотреть?
Actual vs Estimated rows (если планер сильно ошибается → ANALYZE), Buffers (logical/physical reads), Loops × per-row cost. Seq Scan на больших таблицах — обычно проблема.
47. PgBouncer — какие режимы?
Session (после disconnect), Transaction (после commit/rollback — самый частый), Statement (после statement, ломает много фич). В transaction mode не работают prepared statements (до 1.21).
48. Replication: какие виды в Postgres?
Physical (streaming): репликация WAL, реплика — точная копия. Logical (10+): pub/sub на уровне таблиц/действий, можно фильтровать, разные версии.
49. Distributed transactions — какие подходы?
2PC (блокирующий, deprecated), Saga (хореография/orchestration с compensations), TCC (Try-Confirm-Cancel), Outbox для async events.
50. Что такое Saga? В чём отличие хореографии и оркестрации?
Saga = последовательность local transactions с компенсаторами. Хореография: сервисы подписаны на events друг друга, сами решают. Оркестрация: центральный orchestrator (Temporal) управляет потоком.
51. Outbox pattern — зачем нужен?
Чтобы атомарно записать в БД и отправить событие в Kafka. В одной транзакции пишем в outbox таблицу + бизнес-таблицу. Debezium (CDC) читает WAL и публикует в Kafka. Гарантирует consistency.
52. Идемпотентность — как обеспечить?
Idempotency-Key header → сохраняем результат первого запроса с этим key. Повторы возвращают тот же результат. Хранить с TTL (24h обычно).
53. Distributed lock — на чём реализовать?
Redis Redlock (с оговорками Kleppmann — clock skew, GC pauses), etcd lease (consensus-based, надёжнее), Postgres advisory locks (
pg_advisory_lock), ZooKeeper recipes.
54. CAP-теорема — что это?
Consistency, Availability, Partition tolerance. В partition можно выбрать только 2. На практике partition неизбежен → выбираем между CP (etcd, MongoDB strong) и AP (Cassandra, DynamoDB). Современная формулировка PACELC добавляет latency vs consistency в normal mode.
55. Что такое quorum?
Большинство (N/2 + 1) узлов. Для writes — нужно подтверждение от quorum. Для reads — quorum или sloppy quorum. Гарантирует, что любой write пересечётся с любым read.
56. Raft consensus — расскажи на пальцах.
Лидер избирается голосованием (terms, votes). Лидер реплицирует log entries на followers. Когда majority подтвердила — commit. При partition: только partition с majority может продолжать writes. etcd, Consul, CockroachDB используют.
57. Kafka exactly-once — как работает?
Idempotent producer (PID + sequence number, broker отвергает дубликаты). Transactional producer (writes в несколько partitions + offset commits атомарно). Consumer с
isolation.level=read_committed. Read-process-write exactly-once.
58. Kafka ISR — что это?
In-Sync Replicas. Реплики, актуальные относительно leader.
acks=allждёт подтверждения от всех ISR. Если реплика отстаёт > replica.lag.time.max.ms → выкидывается из ISR.
59. Чем отличается Kafka от RabbitMQ?
Kafka — лог, immutable, partitioned, для high-throughput streaming. RabbitMQ — message queue, push модель, гибкая роутинг (exchanges), для task distribution. Kafka — для events, RabbitMQ — для tasks.
60. NATS JetStream vs Kafka?
JetStream — lightweight, in-DC, простой operate, KV/Object store как бонус. Kafka — heavyweight, для huge throughput (>100k/sec), ecosystem (Connect, Streams), exactly-once.
D. Архитектура + микросервисы
Заголовок раздела «D. Архитектура + микросервисы»61. DDD — что такое bounded context?
Граница, внутри которой term имеет определённое значение. Внутри BC — единая модель. Между BC — explicit translations (через ACL). Каждая команда обычно владеет одним BC.
62. CQRS — когда применять?
Когда read и write нагрузки сильно различаются или модели семантически расходятся. Read-side можно денормализовать, кэшировать, использовать другую БД. Не для каждой системы — overhead.
63. Event Sourcing — плюсы и минусы?
Плюсы: полный audit, time travel, новые проекции легко добавлять. Минусы: сложность, eventual consistency, схемы события эволюционируют (нужны upcasters), нет простых query — материализуй проекции.
64. Strangler Fig — как распиливать монолит?
Facade перед монолитом. Часть запросов начинает идти на новый сервис. Постепенно расширяем зону покрытия. Старый код удаляется когда покрытие 100%. Dual-write или CDC для данных.
65. Backward / Forward compatibility — как обеспечить?
Не удалять/менять fields (Proto: mark reserved). Только добавлять optional. Schema Registry для контроля. В JSON — игнорировать unknown fields на consumer.
66. API versioning — какие подходы?
URL (
/v1/,/v2/) — самый простой. Header (API-Version: 2). Content-type. Для gRPC — пакеты с major-версией в имени.
67. Schema Registry — зачем?
Централизованное хранение схем (Avro/Proto/JSON Schema). Producer сериализует с schema ID, consumer десериализует по нему. Гарантирует compatibility (BACKWARD, FORWARD, FULL).
68. Что такое Anti-Corruption Layer?
Слой-адаптер на границе bounded context, переводит модели чужой системы в свою. Изолирует от изменений внешней системы.
69. Circuit Breaker — состояния и зачем?
Closed (нормально), Open (отказ — не пускаем запросы), Half-Open (пробуем). Защищает от cascading failures: когда downstream упал, не добиваем его retry’ями.
70. Bulkhead pattern?
Изолированные пулы ресурсов (threads, connections) для разных downstream. Если один умер — остальные работают.
71. Idempotency vs At-Least-Once vs Exactly-Once?
At-least-once: возможны дубликаты, надо идемпотентно обрабатывать. At-most-once: возможна потеря. Exactly-once: дорого, обычно эмулируется через at-least-once + идемпотентность.
72. SLI vs SLO vs SLA?
SLI — индикатор (% успешных). SLO — внутренний таргет (99.9%). SLA — контракт с клиентом, с финансовыми санкциями.
73. Что такое error budget?
100% - SLO = доля ошибок, которые мы можем позволить. Если бюджет исчерпан — стоп фич, только bug fixes. Если есть — можно деплоить новое.
74. Multi-tenant architecture — какие модели?
Pool (shared DB, tenant_id), Bridge (shared cluster, separate schemas), Silo (отдельные БД). Выбор зависит от requirements isolation и стоимости.
E. System Design
Заголовок раздела «E. System Design»75. Спроектируй URL shortener. См. раздел 12.1. 76. Спроектируй rate limiter (distributed). См. раздел 12.4. 77. Спроектируй чат-приложение. См. раздел 12.7. 78. Спроектируй ленту (Twitter feed). См. раздел 12.8. 79. Спроектируй платёжную систему. См. раздел 12.9. 80. Спроектируй distributed cache. См. раздел 12.2. 81. Спроектируй поиск. См. раздел 12.6. 82. Спроектируй систему уведомлений. См. раздел 12.3. 83. Спроектируй распределённую очередь. См. раздел 12.5. 84. Спроектируй GPS-трекинг. См. раздел 12.10.
F. Production debugging
Заголовок раздела «F. Production debugging»85. Сервис «течёт» по памяти — твои действия?
- Подтвердить через мониторинг (RSS растёт линейно). 2) Снять heap profile + diff через час. 3) Посмотреть top allocators. 4) Проверить goroutine leak. 5) Проверить connection pools (не закрытые соединения). 6) Если непонятно — runtime/trace.
86. P99 latency вырос в 5 раз — что делать?
- Что изменилось? (deploys, traffic, downstream). 2) Какой компонент медленный? (traces, db queries). 3) GC pause spike? (runtime/metrics). 4) CPU profile в моменте. 5) Локально воспроизвести при нагрузке.
87. Goroutine leak — как найти?
runtime.NumGoroutine()мониторинг./debug/pprof/goroutine?debug=2→ стектрейсы. Ищем повторяющиеся — где блокировка. Часто — забытый context cancel, channel без receiver.
88. Service medvedi подаёт 502, downstream вернулся в норму. Почему?
Возможно: connection pool забит (idle conns живые, но broken). Решение: SetConnMaxLifetime. Или: circuit breaker не сбросился. Или: DNS кэш устарел.
89. БД медленно отвечает — куда смотреть?
pg_stat_statementsтоп запросов. 2)pg_stat_activity— текущие. 3) Locks (pg_locks). 4) EXPLAIN ANALYZE на проблемных. 5) Bloat (pgstattuple). 6) IO:pg_stat_io. 7) Network: latency между app и db.
90. Goroutine deadlock в проде — как разобрать?
kill -QUIT pidили pprof goroutine. Смотрим: 1) на чём заблокированы. 2) кто держит lock. 3) есть ли circular wait. Профилактика: всегда defer Unlock(), single-direction lock acquisition.
G. Observability / SRE
Заголовок раздела «G. Observability / SRE»91. OpenTelemetry — три pillar’а?
Traces (spans), Metrics (counters/histograms/gauges), Logs (структурированные с TraceID).
92. RED vs USE?
RED — для request-driven (Rate, Errors, Duration). USE — для resources (Utilization, Saturation, Errors). Дополняют.
93. Что такое burn rate alerting?
Алерт на скорость съедания error budget. Multi-window (1h fast burn, 6h medium, 24h slow) с разной чувствительностью. От Google SRE.
94. Sampling в tracing — head vs tail?
Head: решение sample/drop на старте запроса (всегда стабильно по trace). Tail: после завершения trace, по факту (можем seleсtивно сохранить slow/error).
95. Что хранить в логах? Что выкинуть?
Структурированно, JSON. TraceID, span ID, request ID. User ID (если можно по PII политике). Никогда: secrets, PCI-данные, JWT целиком. Уровень: INFO в проде, DEBUG отключён.
H. Security
Заголовок раздела «H. Security»96. mTLS — как работает?
Обе стороны (client + server) предоставляют сертификаты. Каждая верифицирует другую по CA. SPIFFE/SPIRE — рекомендованный способ автоматизации в Kubernetes.
97. SBOM — что и зачем?
Software Bill of Materials — список всех dependencies артефакта. Generate’им через Syft, сканируем уязвимости через Grype. Часть supply chain security.
98. SQL injection в Go — как избежать?
Всегда
db.Query("SELECT $1", arg), неfmt.Sprintf. Используем placeholders. ORM сами это делают. Никогда не interpolировать user input.
99. JWT — какие риски?
Незашифрованные claims (читаются всеми, кто перехватил). Алгоритм none (примут unsigned). Длительный TTL (нельзя отозвать). Решения: refresh tokens, revocation list, short TTL.
I. Лидерство / soft skills
Заголовок раздела «I. Лидерство / soft skills»100. Расскажи о сложном code review — как ты его провёл?
Конкретный пример. Тон: empathy не gatekeeping. Фокус: корректность > архитектура > стиль. Spotted issues: race conditions, missing tests, security.
101. Как ты ментораешь джунов?
Регулярные 1:1, парное программирование, постановка задач с границами (что — чёткое, как — свобода). Code review как обучение (вопросы, не команды).
102. Расскажи про сложный технический conflict в команде.
Конкретный пример. Подход: ADR с trade-offs, обсуждение в группе, ответственное решение. Важно: разделять идею и носителя.
103. Как ты оцениваешь задачи?
Декомпоз до < 1 недели. Power of 2 (1, 2, 4, 8 дней). Buffer 30%. Three-point estimation (best/nominal/worst). Estimates ≠ commitments.
104. Расскажи о провале — что научило?
Конкретный пример (incident, deploy gone wrong, missed requirement). Lessons learned: process, tooling, communication. Постмортем без поиска виноватых.
105. Как ты документируешь архитектурные решения?
ADR в репозитории (markdown). Структура: Context, Decision, Consequences. Регулярные tech design reviews. C4 диаграммы для high-level.
15. Pet-проекты / open source для Middle 3
Заголовок раздела «15. Pet-проекты / open source для Middle 3»15.1 Идеи серьёзных pet-проектов
Заголовок раздела «15.1 Идеи серьёзных pet-проектов»-
Distributed Cache (Redis-like) — consistent hashing, replication, eviction. Запушить в open-source с benchmarks vs Redis.
-
Lightweight Service Mesh — gRPC proxy с mTLS, circuit breaker, retry, observability. Альтернатива Linkerd для маленьких проектов.
-
Time Series Database — append-only, partitioning, compression (delta-of-delta, gorilla). Сравнить с VictoriaMetrics.
-
Kubernetes Operator для какого-нибудь stateful application (например, PostgreSQL HA или Redis cluster).
-
Distributed Job Scheduler — типа Celery/Sidekiq, но на Go. Redis backend, retry, priorities, scheduling.
-
Real-time Analytics Pipeline — Kafka → Stream Processor → ClickHouse/Pinot → API.
-
Blockchain From Scratch — PoW consensus, P2P networking, transaction validation. Хорошо для понимания распределённых систем.
-
HTTP/2 Reverse Proxy — типа Caddy, но фокус на хайлоад. TLS termination, rate limit, cache.
-
Custom DBMS — собственный embedded DB на Go: B+ tree, WAL, MVCC, SQL parser. Курс CMU 15-445 в помощь.
-
Container Runtime — простой OCI-compatible runtime на Go. Чтобы понять как работают cgroups, namespaces.
15.2 Как контрибутить в крупные Go open-source
Заголовок раздела «15.2 Как контрибутить в крупные Go open-source»Стратегия:
- Начни с good first issue / help wanted labels.
- Документация / тесты — easy wins.
- Bug fixes — следующий шаг.
- Features — только после погружения.
Топ проектов:
- kubernetes/kubernetes — огромный, но есть кучка sigs (storage, scheduling, etc.).
- etcd-io/etcd — core distributed system.
- cockroachdb/cockroach — отличная codebase, можно учиться.
- prometheus/prometheus — metrics ecosystem.
- grafana/loki, grafana/tempo — observability.
- istio/istio — service mesh.
- vitessio/vitess (YouTube/PlanetScale) — MySQL шардинг.
- influxdata/influxdb — TSDB.
- hashicorp/consul, hashicorp/nomad.
- kubedge-io/kubeedge, k3s-io/k3s — edge k8s.
- dapr/dapr — sidecar для микросервисов.
- temporalio/temporal, temporalio/sdk-go — workflow engine.
Российские проекты:
- YDB-Platform/ydb-go-sdk — SDK для YDB.
- VictoriaMetrics/VictoriaMetrics — TSDB, активно ищет contributors.
- avito-tech/normalize и другие OSS от Авито.
- ozontech/file.d — log forwarder.
16. Ресурсы для обучения уровня Middle 3
Заголовок раздела «16. Ресурсы для обучения уровня Middle 3»Книги (must-read)
Заголовок раздела «Книги (must-read)»Distributed Systems:
- Designing Data-Intensive Applications (DDIA) — Martin Kleppmann. Second Edition в 2026 (с AI/vector data). Главная книга.
- Database Internals — Alex Petrov.
- Designing Distributed Systems — Brendan Burns.
- Site Reliability Engineering + The SRE Workbook — Google. Бесплатно.
- Building Microservices — Sam Newman. Второе издание 2021.
Go:
- The Go Programming Language — Donovan & Kernighan. Классика.
- 100 Go Mistakes and How to Avoid Them — Teiva Harsanyi. Обязательно.
- Concurrency in Go — Katherine Cox-Buday.
- Domain-Driven Design with Golang — Matthew Boyle.
- Network Programming with Go — Adam Woodbeck.
- Cloud Native Go — Matthew Titmus.
- Let’s Go + Let’s Go Further — Alex Edwards (web apps на Go).
Architecture / Design:
- Domain-Driven Design — Eric Evans (Big Blue Book, фундаментальная).
- Implementing Domain-Driven Design — Vaughn Vernon (более practical).
- Patterns of Enterprise Application Architecture — Martin Fowler.
- Building Evolutionary Architectures — Neal Ford.
Performance / Production:
- Systems Performance — Brendan Gregg. Главная книга по performance.
- BPF Performance Tools — Brendan Gregg.
- MIT 6.824 Distributed Systems — Robert Morris. На YouTube, лекции + лабы на Go (свой Raft, KV store). Топовый курс.
- CMU 15-445 Database Systems — Andy Pavlo. Лучший курс по БД, бесплатно.
- CMU 15-721 Advanced Database Systems — для глубокого погружения.
- Stanford CS244B Distributed Systems — Diego Ongaro (автор Raft).
- Coursera: Cloud Computing Specialization — University of Illinois.
- edX: Reliable Distributed Systems — Cornell.
Российские курсы:
- Yandex Practicum: Go-разработчик — middle курс.
- Balun Courses (Олег Козырев): Микросервисы на Go, Алгоритмическое собеседование, Golang интервью.
- Курс «Микросервисы на Go» от olezhek28 (Sebastian, ex-Avito): https://olezhek28.courses/microservices
- HSE «Разработка микросервисов на Go».
Конференции (видео)
Заголовок раздела «Конференции (видео)»- GopherCon — главная Go-конференция. Talks на YouTube.
- dotGo — европейская Go-конференция.
- GoLab — Italian Go conference.
- KubeCon + CloudNativeCon — для cloud native.
- QCon — software architecture.
- SREcon — для SRE perspective.
- PGCon / PGConf.EU — для PostgreSQL.
- GoWayFest (РФ/СНГ, до 2022).
- Highload++ — российская hi-load конференция.
Блоги / Engineering
Заголовок раздела «Блоги / Engineering»Companies:
- Cloudflare blog — performance, networking.
- Uber engineering — большие Go-кейсы (Jaeger, M3DB, Cadence).
- Discord engineering — Go (раньше) → Rust.
- DropBox tech blog.
- Datadog engineering — много про Go.
- Reddit r/programming top monthly.
- Three Dots Labs — DDD/Clean Architecture на Go.
- Ardan Labs blog — Bill Kennedy.
- Dave Cheney’s blog.
- VictoriaMetrics blog — performance в Go.
Российские:
- Хабр Хабы: Go, Программирование, Системное администрирование, Базы данных.
- vc.ru — tech статьи.
- Авито Tech, Озон Tech, Yandex — engineering blogs.
- Антон Желтов, Олег Козырев, Никита Соболев — Telegram-каналы.
Подкасты
Заголовок раздела «Подкасты»- Go Time (Changelog) — еженедельный про Go.
- GoLab Podcast.
- The Cloudcast — cloud architecture.
- Software Engineering Daily.
- Software Engineering Radio.
- Talking Kotlin (даже для Go relevant — JVM ideas).
Российские:
- Подлодка — Andrey Boyar.
- Хекслет подкаст.
YouTube каналы
Заголовок раздела «YouTube каналы»- Rob Pike talks — основоположник Go.
- Russ Cox talks — current Go lead.
- GoSF — recorded meetups.
- Brendan Gregg — performance.
- Hussein Nasser — backend engineering.
- ByteByteGo — system design.
17. План перехода Middle 2 → Middle 3 (12 месяцев)
Заголовок раздела «17. План перехода Middle 2 → Middle 3 (12 месяцев)»Реалистичный план по неделям. Предполагается 10-15 часов в неделю на учёбу + текущая работа в качестве Middle 2.
Месяц 1: Фундамент Go (углубление)
Заголовок раздела «Месяц 1: Фундамент Go (углубление)»- Неделя 1-2: «100 Go Mistakes» — прочитать целиком, выписать неочевидное. Решить упражнения.
- Неделя 3: GMP scheduler deep dive. Прочитать GoTech blogs, source code
runtime/proc.go. Написать пост в блог/Habr. - Неделя 4: GC pacer math. Прочитать GC pacer proposal. Эксперименты с
GOGC,GOMEMLIMITлокально.
Месяц 2: Concurrency + Memory
Заголовок раздела «Месяц 2: Concurrency + Memory»- Неделя 5: Channel internals — прочитать
runtime/chan.go. Реализовать аналог канала с нуля. - Неделя 6: Memory model. Race detector. Atomic primitives. Реализовать lock-free MPSC.
- Неделя 7: sync.Mutex, sync.Map internals. Реализовать собственный RWMutex.
- Неделя 8: Profiling deep dive. pprof, flamegraphs, runtime/trace. Профилировать свой pet-проект.
Месяц 3: Базы данных
Заголовок раздела «Месяц 3: Базы данных»- Неделя 9: Postgres internals — MVCC, WAL, planner.
- Неделя 10: Индексы — B-tree, GIN, GiST, BRIN. Эксперименты с EXPLAIN.
- Неделя 11: HA — Patroni setup локально. PgBouncer modes.
- Неделя 12: ClickHouse, MergeTree. YDB или CockroachDB — что-то одно для эксперимента.
Месяц 4: Distributed Systems основы
Заголовок раздела «Месяц 4: Distributed Systems основы»- Неделя 13: DDIA главы 5-7 (Replication, Partitioning, Transactions).
- Неделя 14: DDIA главы 8-9 (Trouble, Consistency, Consensus). Прочитать Raft paper.
- Неделя 15: Lab MIT 6.824 — Raft на Go. Это большая инвестиция времени, но крайне ценная.
- Неделя 16: Прочитать про Kafka в DDIA + Confluent docs. Sagas.
Месяц 5: Микросервисы и архитектура
Заголовок раздела «Месяц 5: Микросервисы и архитектура»- Неделя 17: Sam Newman «Building Microservices». DDD strategic.
- Неделя 18: Pattern catalog — Saga, Outbox, Inbox, Circuit Breaker, Bulkhead, Retry. Реализовать в pet-проекте.
- Неделя 19: gRPC deep dive. Streaming, interceptors. Schema evolution.
- Неделя 20: Kafka deep dive — exactly-once, transactions. Реализовать на franz-go.
Месяц 6: System Design Practice
Заголовок раздела «Месяц 6: System Design Practice»- Неделя 21-22: ByteByteGo / Alex Xu System Design Vol 1 — прорешать все 15 задач письменно.
- Неделя 23: System Design Vol 2 — ML, search, etc.
- Неделя 24: Mock system design интервью (с другом / на YouTube).
Месяц 7: Kubernetes / Cloud Native
Заголовок раздела «Месяц 7: Kubernetes / Cloud Native»- Неделя 25: Kubernetes basics — если уже знаешь, пропустить. Иначе KodeKloud / Kelsey Hightower «Kubernetes the Hard Way».
- Неделя 26: Operators — Kubebuilder tutorial. Написать простой operator.
- Неделя 27: Service Mesh basics — Istio или Linkerd hands-on.
- Неделя 28: Helm, Kustomize, ArgoCD.
Месяц 8: Observability + Production Skills
Заголовок раздела «Месяц 8: Observability + Production Skills»- Неделя 29: OpenTelemetry — instrument свой pet-проект fully (traces + metrics + logs).
- Неделя 30: Prometheus, Grafana — set up dashboards, alerts.
- Неделя 31: SRE Workbook — implement SLOs для pet-проекта.
- Неделя 32: Chaos Engineering — Chaos Mesh на k8s, эксперименты.
Месяц 9: Security + Performance
Заголовок раздела «Месяц 9: Security + Performance»- Неделя 33: mTLS, SPIFFE/SPIRE basics.
- Неделя 34: Vault — secrets management. SBOM generation, Sigstore.
- Неделя 35: PGO в действии. Optimize hot paths в реальном коде.
- Неделя 36: Brendan Gregg «Systems Performance» — главы 1-5.
Месяц 10: Algorithms + Coding
Заголовок раздела «Месяц 10: Algorithms + Coding»- Неделя 37-39: Top 100 LeetCode questions for Go (см. NeetCode 150). По 5-10 в день, фокус на патернах.
- Неделя 40: Конкурентные задачи — Worker Pool, Rate Limiter, LRU, etc.
Месяц 11: Mock interviews + Portfolio
Заголовок раздела «Месяц 11: Mock interviews + Portfolio»- Неделя 41: Прокачать GitHub профиль — README, pinned projects.
- Неделя 42: Написать 2-3 технических статьи в Habr / Medium про что узнал.
- Неделя 43: Mock system design + Mock coding (interviewing.io, pramp).
- Неделя 44: Доработать pet-проект — добавить observability, тесты, README.
Месяц 12: Active job search
Заголовок раздела «Месяц 12: Active job search»- Неделя 45-48: Apply в Яндекс / Авито / Озон / Тинькофф / Сбер. Параллельно — мок собесы.
После каждого собеседования (даже неудачного): записать вопросы, разобрать пробелы.
18. Что отличает Middle 3 от Senior
Заголовок раздела «18. Что отличает Middle 3 от Senior»| Аспект | Middle 3 / Middle+ | Senior |
|---|---|---|
| Объём знаний | Глубоко знает Go, БД, k8s, концепции distributed systems | Кругозор шире: ОС, networking, security, multiple languages |
| Самостоятельность | Делает фичи end-to-end, но в рамках уже спроектированной системы | Проектирует системы с нуля, decompose требования в технические задачи |
| Архитектура | Понимает trade-offs, предлагает корректные решения для проблем | Драйвит архитектурные решения уровня системы, влияет на roadmap |
| Code review | Делает качественные ревью на уровне модуля | Делает кросс-командные ревью, видит system-level проблемы |
| Менторинг | Менторит джунов | Менторит middles, формирует engineering culture |
| Кросс-команда | Работает в основном внутри команды | Работает с другими командами, делает технические переговоры |
| Tech debt | Видит и фиксит | Принимает решения о приоритетах tech debt vs features |
| Хаос | Эффективно работает с понятными требованиями | Эффективно работает с ambiguity, выдумывает направление |
| Влияние | На команду | На org / company-wide |
| Постмортемы | Участвует, предлагает action items | Лидирует расследование, обеспечивает follow-through |
| Tech radar | Знает текущий стек глубоко | Постоянно сканирует индустрию, оценивает новые tech для adoption |
| Hiring | Участвует в технических секциях | Принимает решения о найме, прокачивает интервью-процесс |
| Зона ответственности | Service / модуль | Platform / domain |
Что нужно делать на Middle 3, чтобы расти в Senior
Заголовок раздела «Что нужно делать на Middle 3, чтобы расти в Senior»- Брать неопределённые задачи — где нет чёткого ТЗ, надо самому декомпозировать.
- Писать ADR / RFC регулярно, даже для своих решений.
- Менторить — это ускоряет твой рост.
- Участвовать в hiring — научишься оценивать.
- Лидировать инцидент — это меняет уровень понимания production.
- Влиять за пределами команды — talks внутри компании, OSS contributions.
- Углубиться в один домен — стать “the” эксперт по чему-то (например, distributed systems / db internals / observability).
- Развивать коммуникацию — Senior 50% времени общается / пишет, а не кодит.
Заключение и точки внимания
Заголовок раздела «Заключение и точки внимания»Минимум, который нужно знать на Middle 3 интервью
Заголовок раздела «Минимум, который нужно знать на Middle 3 интервью»- Внутренности Go: GMP, GC, escape analysis, map/slice/channel internals, sync primitives — на уровне «могу нарисовать на доске».
- Concurrency: реализовать worker pool, fan-in/out, rate limiter, LRU cache с нуля без подсказок. Понимать context, errgroup, singleflight.
- БД: PostgreSQL deep (MVCC, индексы, EXPLAIN), pgbouncer modes, isolation levels, ClickHouse basics.
- Очереди: Kafka deep (exactly-once, transactions, consumer groups). NATS JetStream basics.
- Distributed Systems: CAP, Raft, Saga, Outbox, Idempotency, distributed locks (с осторожностью).
- Архитектура: DDD bounded contexts, микросервисные паттерны, trade-off мышление.
- System Design: уверенно проектировать 10-15 классических систем.
- Production skills: pprof, OpenTelemetry, SLO/SLI, postmortems, debugging.
- Kubernetes: пользователь-плюс. Operators — бонус.
- Soft skills: code review, ADR, менторство джунов.
Чего ждут конкретные компании (наблюдения)
Заголовок раздела «Чего ждут конкретные компании (наблюдения)»- Яндекс: внутренности Go, алгоритмы (на уровне medium-hard LeetCode), system design, продуктовое мышление. Несколько секций.
- Авито: ОЧЕНЬ много concurrency (worker pool with graceful shutdown — классика). Архитектура. Practical Go patterns.
- Озон / Ozon Tech: алгоритмы, БД, system design. Знание Kafka — must.
- Тинькофф / Т-Банк: глубокий Go, БД, надёжность (платёжная вертикаль). Архитектурная секция для middle+.
- ВК: Tarantool, in-memory, performance. Свои нюансы legacy.
- Сбер: enterprise-style — больше про процессы, security, integrations.
Источники, которые упоминались (для углубления)
Заголовок раздела «Источники, которые упоминались (для углубления)»- Go Blog: PGO
- Go Blog: Swiss Tables
- Datadog: Save 14% CPU with PGO
- Datadog: Go Swiss Tables in production
- Uber: PGO in production (InfoQ)
- Ardan Labs: Kubernetes Memory Limits and Go
- Three Dots Labs blog
- Martin Kleppmann: Distributed Locking
- Google SRE Workbook
- Confluent: Exactly-Once Semantics
- GoAvengers go-interview (GitHub)
- Habr: Go-разработчик уровня middle/senior
- Habr: Реальные задачи с собеседований Яндекс/VK/Ozon/Сбер
- Habr: 100 вопросов/заданий с собеседований
- 100 Go Mistakes (book + site)
- Go Optimization Guide
- VictoriaMetrics blog
- Encore: Advanced Go Concurrency
- Gabor Koos: Go Channels Runtime Deep Dive
- Go Scheduler 2025 (Melatoni)
- MIT 6.824 Distributed Systems
- SPIFFE / SPIRE docs
- Debezium Outbox Pattern
- LitmusChaos
- Chaos Mesh
- ENIGMA AI: Go Salary Comparison 2026
- Balun Courses
- Olezhek28 Microservices on Go
- Habr: Go-разработка в 2026 (вебинар)
Удачи на собеседованиях!
Если есть отклик — допиши свой опыт пройденных собесов: какие вопросы задавали, какие мест были unexpectedly сложными. Это поможет docs обновлять под реальный рынок.