MBL
Go / avito / Финал / Финал: технический разговор с тимлидом
Go сложный

Финал: технический разговор с тимлидом

avitointerviewfinalarchitecturesessionproxy

Если чего-то не было в проекте — говорить "не сталкивался, но вот как искал бы", не выдумывать.

Питч SessionProxy

Reverse proxy для временного доступа гостя без раскрытия логина/пароля/куки.

  • Data/control plane разделены — прокси на httputil.ReverseProxy (AES-256-GCM, вырезание Set-Cookie) отдельно от REST/gRPC-управления.
  • Redis + Postgres — лимиты гостя в Redis на каждый запрос, Postgres — источник истины для восстановления после рестарта Redis.
  • HA Postgres — Patroni (primary+standby) + etcd + HAProxy. Failover проверен: остановка primary → ~15 сек → standby стал primary без ручного вмешательства.
  • Graceful shutdown — через signal.NotifyContext, запросы не обрываются при остановке.

Грабли — честно

Реальный случай: миграция 00009_grant_app_role.sql. В HA-профиле миграции идут от postgres, таблицы создаются с его владением. Роль sessionproxy (от которой работает само приложение) автоматически прав не получает — нужен явный GRANT. Без миграции первый запрос на чистом кластере падал с permission denied. Юнит-тестами такое не ловится — воспроизводится только на чистом окружении.

Граница гарантий: вырезание Set-Cookie — надёжно, это код. Утечка токена в теле ответа (HTML/JSON от целевого сайта) — не перехватывается, это осознанно не решено на уровне прокси.

Про гонки/утечки горутин: конкретного зафиксированного инцидента не было. Где искал бы: параллельная запись в общее состояние — go run -race на интеграционных тестах; горутина без гарантированного выхода — явный context с отменой на каждый сетевой вызов.

Системный траблшутинг

p99 > 2с под нагрузкой — порядок действий: 1. Метрики — RPS, latency по хендлерам, локальный рост или общий. 2. Логи — корреляция с деплоем/трафиком/внешним инцидентом. 3. БД — активные соединения, долгие запросы (pg_stat_activity), блокировки. 4. Пулы соединений — не исчерпан ли пул к БД/Redis. 5. pprof — только если первые четыре шага не дали ответа.

Канал vs мьютекс: передаётся владение значением между горутинами — канал. Несколько горутин читают/пишут один объект in-place — мьютекс.

Тесты: unit на бизнес-логике (table-driven, без Docker), integration через testcontainers-go (реальный Postgres/Redis, не моки — мок не проверяет SQL). Repository-слой не мокается — тест пройдёт даже при неверном SQL.

Чек-лист перед созвоном

  • Питч ≤ 2 минуты, с цифрой (failover ~15 сек).
  • Готов сказать "не сталкивался с этим конкретно".
  • p99: метрики раньше pprof.
Самопроверка 0 / 3
Питч SessionProxy — 2 минуты, с цифрой
Честно называю границу того, что реально проверено
Шаги диагностики p99 — от дешёвого к дорогому
Как усвоено?