Конкурентность

Дефицит ресурсов

Как управлять ограниченными ресурсами в ООП проектировании

⚖️ Дефицит ресурсов (Scarcity) касается управления ограниченными ресурсами, когда спрос превышает предложение. У вас есть конечное число соединений с базой данных, ограниченная память для буферов или дорогие ресурсы, которые нужно создавать только один раз. Ограничение заключается не в корректности, а в том, что ресурсов просто не хватает на всех, кто хочет их получить.

Проблема

Рассмотрим пул соединений, который управляет подключениями к базе данных. Каждому запросу к базе данных нужно соединение, а соединения дороги, потому что они потребляют память на сервере базы данных, удерживают файловые дескрипторы и требуют времени на установку. Поэтому при запуске мы создаем пул из 5 соединений и переиспользуем их между запросами.

Вот что должно происходить, когда запросу нужна база данных, при этом каждый запрос получает подключение из пула и выполняет запрос:

Пул соединений

Пять запросов могут выполняться одновременно, каждый использует одно соединение. Однако шестому запросу придется подождать, пока кто-нибудь вернет соединение, прежде чем он сможет продолжить.

Но что произойдет, если запрос возьмет соединение и никогда его не вернет? Это может случиться из-за ошибки в коде или из-за медленного запроса, выполнение которого занимает много времени. В любом случае это заблокирует пул соединений и не даст другим запросам получить соединения. Они будут ждать бесконечно, а сервис зависнет.

Пул соединений заблокирован

С базой данных все в порядке. Она без проблем обрабатывает пять запросов. Но ваш сервис не работает. Каждый новый запрос бесконечно блокируется в ожидании соединения, которое уже не вернется. Пользователи видят таймауты. Мониторинг показывает ноль ошибок, потому что ничего не упало. Запросы просто застряли в ожидании.

Это проблема дефицита ресурсов. Что происходит, когда ресурсов не хватает на всех? В отличие от проблем корректности, где опасность заключается в повреждении данных, здесь проблема в ограниченной емкости. У вас есть 5 соединений и 100 одновременных запросов. Большинству этих запросов придется ждать. Вопрос в том, как управлять этим ожиданием, чтобы система могла продолжать функционировать.

В этой статье мы рассмотрим два решения проблем дефицита ресурсов:

  • Семафоры ограничивают, сколько потоков могут одновременно удерживать ресурс.
  • Пулы ресурсов выдают реальные объекты ресурсов, а не просто разрешение.

Затем мы разберем четыре паттерна, в которых дефицит ресурсов чаще всего появляется на интервью, и покажем, как применять эти решения:

  • Ограничение конкурентных операций, например, для менеджеров загрузок и ограничителей запросов API.
  • Ограничение совокупного потребления, например, для ограничения пропускной способности или использования памяти.
  • Переиспользование дорогих объектов, например, для пулов соединений или планировщиков GPU.
  • Максимизация утилизации, например, для кражи работы (work stealing), пакетирования (batching) или адаптивного изменения размера пула.

Решения

Любая проблема дефицита ресурсов сводится к обеспечению соблюдения предела емкости и принятию решения о том, что происходит, когда вы его достигаете. Нужно отслеживать, сколько ресурсов используется, блокировать новые запросы, когда предел достигнут, и пробуждать ожидающие потоки, когда ресурсы снова становятся доступными.

Перейдите на Premium, чтобы продолжить

Разблокируйте доступ к этой статье и всем остальным материалам с NowInterview Premium

Перейти на Premium