Оптимизация медленного Python-сервиса
Backend-сервис на Python стал медленным под нагрузкой. Как бы ты локализовал bottleneck и понял, что именно оптимизировать?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Сначала фиксируем симптом и SLO, затем смотрим метрики/логи/traces, локализуем слой: API, serialization, DB, queue, network или CPU. После этого воспроизводим локально и проверяем гипотезу измерением.
Подробный разбор
Хороший ответ начинается не с "переписать на Go", а с вопроса: какой именно SLO нарушен и где это видно. Нужно посмотреть latency, error rate, throughput, saturation, очереди, пул соединений и ресурсы процесса. Дальше раскладываем путь запроса: API handler, serialization, внешние сервисы, база, очередь, CPU-bound код.
Если подозрение на базу, надо смотреть slow query log, EXPLAIN/EXPLAIN ANALYZE, индексы, selectivity, connection pool и объем результата. Если CPU-bound код, пригодятся профилировщик и проверка горячих функций. Если проблема в долгой фоновой задаче, можно выделить producer/consumer, batch size, backpressure и шардирование работы.
Важно закрывать цикл измерением: было N секунд, стало M секунд, не сломали correctness и не ухудшили другие метрики.
Типичные ошибки
- Оптимизировать без SLO и baseline.
- Сразу винить Python runtime, не проверив базу и внешние зависимости.
- Не воспроизводить проблему и не проверять эффект изменения.
Как сказать на собеседовании
- Назови observability, EXPLAIN ANALYZE, profiling и connection pool.
- Раздели CPU-bound, IO-bound и database-bound сценарии.
Code review как ownership и onboarding
Как организовать code review в backend-команде, чтобы сохранять качество и одновременно растить знание кодовой базы у команды?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
На review стоит назначать минимум эксперта по домену и человека, который погружается в проект. Первый отвечает за correctness, второй расширяет bus factor.
Подробный разбор
Практичная схема: каждый MR смотрит maintainer или domain owner, который понимает бизнес-логику и архитектурные границы сервиса. Второй reviewer может быть разработчиком, которого нужно погрузить в эту часть кодовой базы. Так review становится не только gatekeeping, но и системным onboarding.
На review нужно проверять не только style. Важнее семантика изменения, границы слоев, тесты, миграции, обратная совместимость API, observability и влияние на performance. Мелкие style-вопросы лучше автоматизировать formatter/linter-ом, чтобы люди тратили внимание на design и correctness.
Хорошая политика также ограничивает количество итераций: понятные checklist-и, маленькие MR, owners по подсистемам и быстрый feedback loop.
Типичные ошибки
- Сводить review к naming и форматированию.
- Назначать случайных reviewers без ownership.
- Не использовать review как способ погружения в проект.
Как сказать на собеседовании
- Скажи про domain owner плюс onboarding reviewer.
- Отдели автоматизируемый style от ручной проверки design/correctness.
Backend-тесты не только на status 200
На review ты видишь тест, который проверяет только HTTP 200. Что с ним не так и как сделать проверку полезной?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Status 200 проверяет только оболочку. Полезный тест должен проверять бизнес-эффект: запись в БД, вызов зависимости, side effects, ошибки, права и важные edge cases.
Подробный разбор
Тест "endpoint вернул 200" часто почти ничего не доказывает. Нужно понять контракт фичи: что должно измениться в системе и какие инварианты должны сохраниться. Для create/update endpoint это может быть запись в БД, корректные поля, транзакционность, публикация события, idempotency и обработка невалидного input.
В backend обычно нужна пирамида: unit-тесты для чистой логики, integration-тесты с БД/очередью для важных сценариев, contract-тесты для внешних API и producer/consumer схем. Регресс должен ловиться до ручной передачи QA.
На review стоит просить тесты, которые падают при реальной поломке бизнес-сценария, а не просто выполняют happy path без assert-ов.
Типичные ошибки
- Проверять только status code.
- Не проверять состояние базы и side effects.
- Игнорировать negative cases и permissions.
Как сказать на собеседовании
- Приведи пример: не только 200, но и созданный объект в БД.
- Упомяни unit/integration/contract уровни.
Контракты между сервисами
В микросервисной системе сервисы общаются через API и события. Как документировать и проверять контракты, чтобы релизы не ломали consumers?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Нужно явно описывать API/event schemas, версионировать изменения и гонять contract tests между producer и consumer версиями. Breaking changes должны идти через migration window.
Подробный разбор
Для HTTP API контракт можно фиксировать через OpenAPI/JSON Schema/gRPC proto, для событий - через schema registry или явно версионированные event schemas. Важно не давать сервисам читать чужие таблицы напрямую: публичный контракт должен быть API или событием.
Проверка - consumer-driven contract tests или совместимость producer/consumer схем. Перед релизом надо убедиться, что старая версия producer работает с новой версией consumer и наоборот, если такой режим возможен во время rolling deploy. Для событий полезны правила backward compatibility: добавление optional поля обычно безопаснее, переименование или удаление поля - breaking change.
Документация контракта должна жить рядом с кодом или в registry, а не только в устной договоренности. Для миграций нужен план: dual-write, dual-read, deprecation period и мониторинг ошибок парсинга.
Типичные ошибки
- Документировать контракт только в Confluence и не проверять его в CI.
- Менять event schema без backward compatibility.
- Давать сервисам ходить напрямую в общую БД.
Как сказать на собеседовании
- Назови OpenAPI/schema registry/consumer-driven contract tests.
- Скажи про rolling deploy и backward compatibility.
Throughput OCR-сервиса по CPU и RAM
OCR API обрабатывает один документ за 2 секунды, на время обработки занимает 1 CPU core и 3.5-4 GB RAM. На сервере 20 cores и 64 GB RAM. Как посчитать safe throughput?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
CPU дает максимум 20 одновременных документов, RAM в worst case дает floor(64 / 4) = 16. Safe concurrency равна 16, throughput = 16 / 2 = 8 документов в секунду.
Подробный разбор
Сначала надо разделить concurrency и throughput. Один документ держит один CPU core и до 4 GB RAM на все время обработки. CPU разрешает держать одновременно 20 документов, но память разрешает только floor(64 / 4) = 16 документов в worst case.
Значит, реальный safe bottleneck - RAM. При concurrency 16 и времени обработки 2 секунды throughput равен 16 / 2 = 8 документов в секунду.
Если брать optimistic estimate 3.5 GB на документ, память дала бы floor(64 / 3.5) = 18 документов и 9 документов в секунду. Но для safe ответа на собеседовании лучше брать worst-case потребление 4 GB.
Типичные ошибки
- Считать только CPU и отвечать 10 документов в секунду.
- Умножать CPU на RAM или смешивать GB и секунды в одной формуле.
- Брать optimistic memory estimate, когда интервьюер просит safe throughput.
Как сказать на собеседовании
- Сначала назови два bottleneck: CPU и RAM.
- Покажи оба лимита и явно выбери minimum.
Kafka partitions и время обработки consumer group
В Kafka topic 10 partitions и 100 задач: 90 задач по 90 ms и 10 задач по 1 s. Задачи равномерно лежат по partitions, внутри partition порядок последовательный. Как оценить best/worst completion time для 1, 10 и 20 consumers?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Для 1 consumer вся работа последовательна: 90 * 0.09 + 10 * 1 = 18.1 s. Для 10 consumers best case 1.81 s, если долгие задачи распределены по одной на partition; worst case 10 s, если все долгие задачи попали в одну partition. Для 20 consumers так же, потому что partitions всего 10.
Подробный разбор
Сначала считаем суммарную работу: 90 быстрых задач по 0.09 секунды дают 8.1 секунды, 10 долгих задач по 1 секунде дают 10 секунд. Всего 18.1 секунды последовательной работы.
При 1 consumer все partitions фактически обрабатываются одним worker-ом, поэтому best и worst одинаковые: 18.1 секунды.
При 10 consumers каждая partition может получить своего consumer-а. Best case: долгие задачи распределены равномерно, по одной на partition. Тогда каждая partition занимает 1 + 9 * 0.09 = 1.81 секунды, и вся группа заканчивает за 1.81 секунды. Worst case: все 10 долгих задач попали в одну partition; эта partition становится bottleneck и занимает 10 секунд.
При 20 consumers результат не улучшается: одна partition назначается максимум одному consumer-у, поэтому полезный параллелизм ограничен 10 partitions.
Типичные ошибки
- Думать, что 20 consumers ускорят topic с 10 partitions.
- Делить суммарную работу на consumers, игнорируя sequential order внутри partition.
- Не различать best и worst distribution долгих задач по partitions.
Как сказать на собеседовании
- Сначала проговори ограничение one partition -> one consumer within group.
- Best/worst объясняй через makespan самой медленной partition.