Загрузка…
Загрузка…
backend / middle / tech_deep
Формат
online
Стадия
tech_deep
Когда
within_quarter
Длительность
90 мин
01
Поведенческий
Расскажи кратко о себе и о своём последнем проекте: что интересного сделал, чего добился (5–10 минут).
Вступительная часть, поток найма без привязки к команде
02
Поведенческий
Расскажи про какой-нибудь интересный фейл, на котором чему-то научился.
Кандидат рассказал про падающие тесты (добавили запуск тестов в CI) и про бесконечно рестартящийся под в Kubernetes из-за медленных селектов в базу
03
Поведенческий
У тебя в резюме указана нагрузка 4–5k RPS — это нагрузка на конкретную ручку или общая? Что под этим подразумевается?
Проверка цифр из резюме, копание в детали проекта
04
Поведенческий
Какая вычислительная мощность нужна, чтобы держать нагрузку 5k RPS? Сколько инстансов приложения её держит?
Заметки
Транскрипт видео с записью реального технического собеседования в Магнит (потоковый найм, без привязки к конкретной команде) на Go-разработчика. Интервью проходило в декабре. Структура: рассказ о себе (~5-10 мин) → лайвкодинг на Go (~40 мин, рефакторинг последовательного кода в конкурентный) → теория Go (sync, GC, память) → PostgreSQL (транзакции, ACID, индексы, блокировки) → Kafka → устная задачка на Redis. Кандидат — Go-разработчик с ~5 годами опыта из проп-трейдинговой компании. Фидбэк положительный, позвали на следующий этап (system design), но кандидат отказался, так как уже принял оффер в другом месте.
Стиль интервьюера
Интервьюер ведёт на «ты», активно даёт наводящие вопросы и подсказки, на лету меняет условия задачи (ломает входные данные, меняет тайминги), чтобы проверить понимание, копает «под капот» (внутреннее устройство WaitGroup, RWMutex, atomic, GC), дотошно сверяет цифры из резюме (RPS, инстансы, шарды/реплики) с реальной архитектурой, следит за таймингом и сам объясняет правильные ответы, если кандидат не знает.
Интервьюер сопоставлял заявленные 5k RPS с ответом БД в секунды и тремя инстансами приложения
05
Поведенческий
Как устроена ваша база данных: шарды или реплики? Сколько шардов, сколько реплик у каждого, сколько машин подключается к базе?
06
Поведенческий
У вас архитектура синхронная или асинхронная? Работаете через Kafka или RabbitMQ? Открытие позиции — это синхронная запись в базу или асинхронная?
07
Поведенческий
Как обеспечиваете надёжность записи в базу под нагрузкой? Как следите за replication lag — на уровне приложения или через мониторинг, в какой момент проверяете, что запись дошла до реплики?
Кандидат ответил, что видел это только через мониторинг (Grafana/alert manager)
08
Код
Прочитай код: расскажи, что происходит в функции main и в функции getFiles, какие команды выполняются, что и как проверяется (ты — компилятор).
Лайвкодинг-секция, чтение кода с последовательным получением файлов по списку имён
09
Теория
За какое примерно время выполнится данный код (ответ с погрешностью ±20%)?
Внутри getFile тикер раз в секунду, 5 файлов → минимум 5 секунд
10
Код
Можем ли выполнить функцию main быстрее? Перепиши getFiles так, чтобы getFile вызывался конкурентно в горутинах, сохранив поведение: при первой ошибке прекращаем обработку и возвращаем ошибку.
Основная задача лайвкодинга, ~40 минут с серией follow-up'ов; интервьюер по ходу менял условия и ломал код
11
Теория
Зачем вызывать wg.Wait() в отдельной горутине? Нужно ли это здесь?
Follow-up по ходу лайвкодинга
12
Теория
Какие два аргумента возвращает функция context.WithCancel?
Follow-up по ходу лайвкодинга
13
Теория
Зачем нам на каждом шаге (итерации цикла) создавать новый контекст? Где правильно его объявить?
Follow-up по ходу лайвкодинга
14
Теория
Почему нужен mutex при записи в мапу из нескольких горутин? Как это сделать?
Кандидат сам обозначил проблему конкурентного доступа к мапе, интервьюер уточнил реализацию
15
Теория
Может ли горутина (анонимная функция) вернуть значение через return?
Follow-up при обработке ошибок в горутинах
16
Теория
Как в Go принято обрабатывать ошибки? Почему все бесятся, когда переходят с классических языков на обработку ошибок в Go?
Нет try/catch, ошибки возвращаются из функций и проверяются на nil сразу после вызова
17
Код
Я изменил условие (передал пустые строки в список имён) — какая из ошибок вернётся и почему? Где ты её возвращаешь?
Интервьюер на лету менял входные данные; getFile возвращает ошибку invalid name на пустую строку
18
Теория
Почему передавать родительский контекст вместо созданного дочернего — реальная ошибка? Что произойдёт при вызове cancel?
Возникло из ошибки компиляции declared and not used: сигнал отмены не дойдёт до горутин, т.к. передан родительский контекст
19
Теория
Как в Go делается аналог публичных и приватных методов?
Заглавная/строчная буква в имени идентификатора
20
Теория
Какой самый правильный, нативный способ работы с многопоточностью в Go — как нужно синхронизировать горутины?
Подвод к рефакторингу решения на каналы вместо разделяемой переменной с мьютексом
21
Теория
Зачем читать из канала в отдельной горутине? Как мы вернём ошибку, если не блокируемся и работаем в горутине?
22
Код
Где лучше закрыть канал? Я изменил условие — почему мы поймали deadlock?
Канал не закрылся, т.к. ветка с ошибкой не выполнилась — range по каналу завис навечно
23
Теория
Как сделать так, чтобы закрытие канала было неблокирующим, но при этом дожидалось окончания работы всех горутин?
Решение: wg.Wait() + close(ch) в отдельной горутине
24
Теория
Какая особенность у range по каналу при его закрытии? Что вернётся из закрытого канала и каким будет второй аргумент при чтении?
При закрытии канала чтение возвращает zero value и ok=false; обсудили, как обойти проверкой на nil
25
Теория
Какой принцип Go нарушается, когда канал закрывается не той горутиной, которая его создала, и есть перспектива записи в закрытый канал?
Принцип: кто создал канал, тот в него пишет и тот его закрывает
26
Теория
Что такое sync.WaitGroup, как она работает и что у неё под капотом?
Счётчик на атомиках: Add увеличивает, Wait ждёт сброса в ноль
27
Теория
Что такое Mutex и как он работает?
28
Теория
Какие ещё виды мьютексов есть в Go? Как работает RWMutex, сколько у него методов и что под капотом? Зачем там эти сущности?
Под капотом два списка ожидающих горутин: на чтение и на запись
29
Теория
Что будет, если вместо RWMutex (RLock/RUnlock) использовать обычный Mutex с Lock/Unlock — скомпилируется ли код, будет ли работать, будет ли медленнее и почему?
30
Теория
Что ещё есть в пакете sync, кроме WaitGroup и Mutex?
Кандидат вспомнил sync.Once, sync.Pool, sync.Map
31
Теория
Что такое sync.Once и на чём он построен под капотом?
32
Теория
Что такое атомики? Почему мы говорим «атомарные», что значит «неделимо на уровне процессора» и за счёт чего это достигается?
Атомарные инструкции процессора, сишники называют их барьерами
33
Теория
Что такое sync.Pool и зачем он нужен?
34
Теория
Что такое сборщик мусора в Go, зачем он нужен и как работает?
Обсудили трёхцветный алгоритм (белый/серый/чёрный)
35
Теория
Что такое Stop the World и в какие моменты работы GC он происходит? Нужно ли останавливать мир в момент sweep?
Sweep работает в фоновом режиме, STW — в начале (определение корней) и при финальной проверке
36
Теория
Следишь ли за новостями Go? Что вышло в версии 1.25, в частности касательно GC?
Интервьюер рассказал про новый алгоритм GC Green Tea, оптимизации под конвейеры процессора (как и swiss map в 1.24)
37
Теория
Всю ли память нужно очищать сборщиком мусора? Какие типы памяти доступны программисту? Запускается ли GC для стека?
38
Теория
var i = new(int) — какой тип у переменной и где она выделится: на стеке или в куче?
var i = new(int)Указатель на стеке, место под значение зарезервировано в куче
39
Теория
В каком месте в Go могут быть утечки памяти — докуда не добирается сборщик мусора?
40
Кейс
Кейс: сервис рассылок раз в 10 секунд выгребает из БД 10 самых старых сообщений и отправляет. Нужно отправить 10 млн сообщений, подняли 10 инстансов — пользователи получили по 10 одинаковых писем. Как избежать дублирования при нескольких инстансах над одной таблицей?
Разобрали варианты: партиционирование, шардирование, блокировка на уровне строк SELECT ... FOR UPDATE
41
Теория
SELECT ... FOR UPDATE: второй инстанс натыкается на блокировку и ждёт — по времени не выиграли. Что ещё надо добавить в запрос?
Ответ: SKIP LOCKED
42
Теория
Почему есть правило, что транзакции должны быть как можно короче и нельзя держать долгие транзакции?
43
Теория
Расшифруй буквы ACID и объясни каждое свойство: что такое атомарность, консистентность, изолированность, долговечность — и как это обеспечивается?
По каждой букве уточняющий вопрос «что это такое и как мы это делаем»
44
Теория
Какие есть уровни изоляции транзакций? За счёт чего они организованы в PostgreSQL, например read committed?
Кандидат отметил, что read uncommitted в Postgres недостижим из-за мультиверсионности
45
Теория
Какие индексы есть в PostgreSQL? Какими пользовался, кроме B-tree?
46
Теория
Что означает буква B в названии индекса B-tree?
Balanced — сбалансированное дерево
47
Кейс
Запрос раньше выполнялся 10 мс, теперь 300 мс — что будешь делать? Как анализировать (EXPLAIN ANALYZE) и почему нежелательно делать это на проде?
Обсудили дамп прода / препрод с реальным объёмом данных, виды сканирования (seq scan, index scan, index only scan, bitmap scan)
48
Теория
Что значит full index scan?
49
Теория
Как работают составные индексы? Какие есть подводные камни их использования?
Работает до первого неравенства включительно; подводный камень — порядок колонок
50
Теория
Чем PostgreSQL 18 круче 17-го? Что нового ввели относительно составных индексов?
Кандидат не читал; интервьюер намекнул на новую фичу про порядок колонок в составных индексах