Вопрос с собеседования · System design

Внешний платёжный провайдер начал отвечать за 30 секунд вместо 200 миллисекунд. Через минуту сервис перестал отвечать вообще, включая страницы, не связанные с оплатой. Что произошло?

MiddleНадёжность и идемпотентность
Ещё спрашивают так:
  • Что такое каскадный отказ?
  • Как медленная зависимость роняет весь сервис?
Коротко

Медленная зависимость выедает общий пул потоков и соединений: каждый запрос держит поток в 150 раз дольше, и сервис перестаёт обслуживать даже страницы без оплаты.

  • Таймаут на внешний вызов по наблюдаемому верхнему перцентилю
  • Bulkhead — отдельный пул для каждой внешней зависимости
  • Circuit breaker — перестать звать упавшую зависимость

А ещё Закон Литтла: время ×150 при том же потоке — потоков нужно ×150

Подробно

Это классическое начало каскадного отказа. Пока провайдер отвечал за двести миллисекунд, каждый поток освобождался быстро и пула хватало; при тридцати секундах каждый запрос удерживает поток в полтораста раз дольше, поэтому пул исчерпывается за считанные секунды. Дальше запросы, не имеющие к оплате никакого отношения, встают в очередь за свободным потоком — и сервис выглядит полностью недоступным. Правильный набор мер известен: таймаут на каждый внешний вызов, выставленный по наблюдаемому верхнему перцентилю с запасом, а не в тридцать секунд; изоляция ресурсов, то есть отдельный пул или ограничение числа одновременных вызовов именно к этой зависимости, чтобы её деградация не касалась остального; предохранитель, который после порога ошибок начинает отклонять вызовы мгновенно и даёт провайдеру восстановиться; и продуманная деградация — принять заказ и подтвердить оплату позже вместо ожидания. Ответ про нехватку памяти неверен, а тезис «сервис не может быть быстрее зависимости» верен лишь для операций, которые эту зависимость используют, — и именно чтобы он не распространялся на всё остальное, применяют изоляцию.

Что хотят услышать

  • Механизм исчерпания общего пула.
  • Таймаут, изоляция ресурсов, предохранитель.
  • Почему страдают несвязанные запросы.

Частые ошибки

  • Ставить один общий пул на все внешние вызовы.
  • Задавать таймаут «с запасом» в десятки секунд, что равносильно его отсутствию.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗Провайдер начал возвращать ошибки, и сервис перегрузился их обработкой и повторами
  • ✗Не хватило памяти под ответы провайдера — нужно увеличить heap
  • ✓Общий пул потоков и соединений забит ожиданием провайдера; нужны таймаут, отдельный пул и предохранитель
  • ✗Так и должно быть: сервис не быстрее самой медленной зависимости

Что спросят дальше

  • Как выбрать значение таймаута для конкретной зависимости?
  • Чем ограничение конкурентности лучше выделенного пула потоков?

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования