Загрузка…
Загрузка…
backend / senior / tech_deep
Формат
online
Стадия
tech_deep
Когда
within_quarter
Длительность
—
01
System design
Куда сохраняются данные в вашей системе при нагрузке около тысячи RPS на запись?
Вопрос по опыту кандидата (инвестиционная система хранения поручений)
02
System design
Как работает ваш собственный алгоритм шардирования — как он определяет, в какой шард положить поручение?
Кандидат описал шардирование по весам вместо consistent hashing
03
System design
Данные у вас просто сохраняются или с ними что-то ещё делается (модифицируются, отправляются)?
Пример: слияние двух аккаунтов пользователя и обновление идентификаторов
04
System design
Если вы шардируете на основе загрузки шардов, как происходит поиск по данным и насколько эффективно это работает? Как решали проблему полного поиска по всем шардам?
Заметки
Собеседование на позицию senior (синьор) Java/Kotlin разработчика в компанию-вендора, разрабатывающую системы ДБО и АБС для банка «Банк Санкт-Петербург». Интервьюеры — Дмитрий и Алексей. Стек: Kotlin (основной), Java 11/17 (остаточно), JetBrains-стек Ktor, PostgreSQL (шардированный, собственный алгоритм шардирования по весам), Kafka и RabbitMQ для межсервисного взаимодействия, Docker + Kubernetes, более 100 микросервисов. Таск-трекер — YouTrack (Kaiten/Kaiten-подобный), недельные спринты. Кандидат — 5+ лет в банковских системах (СМС-центр, карточный платёжный шлюз-фасад над эквайерами, текущий проект — единая система хранения инвестиционных поручений ~1-1.5к RPS на запись). Это только техническая часть; отдельно была финальная секция по soft skills. По итогу — оффер на 435 000 рублей.
Подготовка
Часто встречающиеся темы: архитектура и микросервисы, шардирование PostgreSQL, работа с Kafka, отказоустойчивость и стратегии при деградации БД, rate limiting/backpressure для защиты сервиса. По Java Core: float/double и BigDecimal, контракт equals/hashCode, внутреннее устройство HashMap (ресайз, бакеты, дерево после 8), Set/TreeMap (красно-чёрное дерево, Comparable/Comparator, NavigableMap), Stream API (ленивость, parallelStream, IntStream.sum, переиспользование стрима, переполнение int). По SQL: поведение агрегатных функций с NULL, трёхзначная логика (NULL != NULL), задача на вторую по величине зарплату без window functions/LIMIT.
Стиль интервьюера
Двое интервьюеров (Дмитрий ведёт, Алексей задаёт уточняющие вопросы). Стиль доброжелательный, но с настойчивыми follow-up'ами и постепенным усложнением: от вопроса по реальному опыту кандидата уходят в абстрактные «а что если…» сценарии (деградация шарда, защита core-сервиса). Любят, когда кандидат рассуждает вслух и приходит к ответу сам, мягко направляют подсказками («давайте перечислим, что может вернуть остаток на 2»). На код-вопросах сначала спрашивают «что выведет и почему», затем углубляются во внутреннее устройство. Отмечена шуточная реакция на «превышено количество вопросов».
Решение: ретрансляция поручений в отдельный топик Kafka, потребители хранят свой снимок
05
System design
Вы сами выбирали, что хранилищем будет PostgreSQL? Можно ли было выбрать Cassandra, которая решает эти проблемы из коробки?
06
Поведенческий
Принимаете ли вы активное участие в проработке архитектуры и принятии решений, или вам приходит готовое целевое решение от архитектора?
07
System design
Расскажите про сам проект — это монолит или микросервисная архитектура, из чего он состоит?
Регистратор, сервисы за шардами, оркестратор для чтения
08
System design
Какой алгоритм балансировки нагрузки между инстансами вы используете?
Round-robin + распределение по партициям Kafka
09
System design
Если координатор определил нужный шард, но сервис или шард недоступен — как вы обрабатываете такой случай?
Ретраи с задержкой, публикация ошибки в топик, ответственность поставщика за переотправку
10
System design
Координатор отправляет запрос в сервис шарда синхронно или асинхронно?
11
System design
Сервисы шардов масштабируются? Как именно?
12
Кейс
Представьте, что шард начинает тормозить — база отвечает медленно. Вы предусматривали такой момент? К чему это может привести?
Мониторинг свободного пространства, алерты при 60-80%, добавление шардов/мощностей
13
Кейс
Сколько по времени занимает добавление нового шарда или увеличение мощности сервера?
14
Кейс
Если шард начинает тормозить и через минуту упадёт — какая стратегия экстренного реагирования?
Динамические веса, выставление веса в ноль при загрузке >95%
15
Кейс
Как защитить core-сервис, в который пишут разные неизвестные поставщики, от перегрузки запросами, не привлекая людей, чисто техническим решением?
Буфер/очередь перед сервисом (Kafka), rate limit на поставщика
16
Теория
Что выведет данный код сложения чисел с плавающей точкой (например, ожидается 3.3)? Почему?
Про ограниченную разрядную сетку и двоичное представление
17
Теория
Что использовать в Java, если нужно посчитать точно? Почему именно BigDecimal позволяет достичь этой точности и как он хранит числа внутри?
Follow-up: как хранить числа, превосходящие long (массив long)
18
Теория
Что выведет данный код с коллекцией Set (добавление дублирующейся четвёрки)? Сколько будет элементов и какая реализация под капотом?
Особенность: не HashSet под капотом, immutable/Set.of
19
Теория
Что выведет код с Map, где ключи — объекты new Object(): результат сравнения hashCode, размер мапы и результат get?
20
Теория
Что такое контракт equals и hashCode, зачем он нужен и как работает?
Равные объекты → равный hashCode, обратное не гарантируется (коллизии)
21
Теория
Почему при множественных добавлениях в HashMap производительность периодически проседает, а потом возвращается к норме? Как с этим связано внутреннее устройство?
Ресайз массива бакетов, дерево после 8 элементов
22
Теория
Как заранее задать размер HashMap, чтобы избежать ресайзов? (initial capacity, load factor)
23
Теория
Что произойдёт с TreeMap, если в неё положить ключи new Object()? Какое условие должно выполняться у типа ключа для использования TreeMap?
Ключ должен реализовывать Comparable либо нужен Comparator
24
Теория
В какой момент TreeMap выбросит исключение при некорректном ключе — при создании или при вставке? Почему именно тогда?
При вставке, т.к. нет объекта для сравнения до этого момента
25
Теория
Какой специфичный интерфейс реализует TreeMap (NavigableMap, SortedMap) и что он позволяет делать, для каких целей использовать?
Методы lowerBound/higherBound, обход дерева, взятие интервалов
26
Теория
Вы работали со Stream API? В чём плюс стримов, зачем они были созданы? Какие основные особенности (промежуточные и терминальные операции)?
27
Теория
Как называется свойство, при котором операция выполняется только после вызова терминальной операции? (ленивость / lazy evaluation)
28
Теория
Использовали ли вы parallelStream? В чём его особенность и в чём минусы? Можно ли задать другой пул вместо общего ForkJoinPool?
Минусы: гонки данных, блокировка общего пула толстыми задачами
29
Код
Напишите с помощью Stream API метод, который находит сумму квадратов нечётных чисел из списка.
filter по нечётности, map в квадрат, IntStream.sum / reduce
30
Теория
Почему у обычного Stream нет метода sum, а у IntStream есть?
Непонятно, как суммировать произвольные объекты
31
Код
Как корректно проверить число на нечётность в Java, учитывая, что остаток от деления на 2 может вернуть -1, 0 или 1?
Особенность реализации остатка в Java для отрицательных чисел
32
Кейс
Какие тест-кейсы вы бы проверили для этого метода?
Пустой список, все чётные/нечётные, отрицательные, null, null-элементы
33
Теория
Какая проблема есть у этого метода на больших числах? (переполнение int при возведении в квадрат, нужен long)
mapToInt не вместит квадрат, нужен mapToLong
34
Теория
Что произойдёт, если дважды вызвать строку с созданием/использованием стрима, или если бы метод принимал Stream вместо List?
Стрим нельзя переиспользовать
35
Теория
Дана таблица T с колонками col1 и col2 (есть NULL). Что выведут SUM(col1), AVG(col1), COUNT(*), COUNT(col1)? Как агрегатные функции работают с NULL?
Агрегатные функции игнорируют NULL
36
Теория
Что вернёт SELECT с условием col1 = col1, где есть строки с NULL? Почему?
NULL не равен NULL — строки с NULL не попадут в результат
37
Код
Напишите SQL-запрос, чтобы получить вторую по величине зарплату (только значение salary), без использования window functions, LIMIT и OFFSET.
SELECT MAX(salary) FROM T WHERE salary < (SELECT MAX(salary) FROM T)Решение через подзапрос: MAX(salary) WHERE salary < (SELECT MAX(salary))