Какие способы выдерживания большой нагрузки на систему существуют
Что проверяют
Умеете ли вы искать узкое место, прежде чем масштабировать, и понимаете ли, как на это влияет устройство Python. Следом обычно спрашивают, что будет с базой, если просто поднять вдвое больше воркеров.
Как отвечать
Стройте ответ от измерения к мерам. Сначала нагрузочный тест (Locust, k6) и профилирование (py-spy, APM), чтобы понять, куда уходит время: CPU, ожидание базы или внешние вызовы. Дальше по слоям:
- процессы вместо потоков: из-за GIL один процесс CPython исполняет Python-код на одном ядре, поэтому приложение запускают несколькими воркерами, например Gunicorn с воркерами Uvicorn, обычно по числу ядер;
- асинхронность для I/O:
asyncio, FastAPI, асинхронные драйверы. Один процесс держит тысячи ожидающих соединений, но любой блокирующий вызов внутри корутины останавливает весь цикл событий; - фоновые задачи: тяжёлое и необязательное для ответа уходит в очередь (Celery, RQ, arq), пользователь получает ответ сразу;
- кэш: Redis для общих данных, HTTP-кэш и CDN для статики и публичных страниц,
functools.lru_cacheдля дорогих вычислений внутри процесса; - база: индексы, устранение N+1 (
select_relatedиprefetch_relatedв Django,selectinloadв SQLAlchemy), пул соединений и PgBouncer, реплики на чтение; - горизонтальное масштабирование: приложение без состояния, сессии в Redis, балансировщик вроде nginx, автоскейлинг в Kubernetes;
- защита от перегрузки: rate limiting, таймауты на все внешние вызовы, ограничение длины очередей, circuit breaker. Система, которая отвечает части клиентов быстрым отказом, лучше той, что падает целиком.
Где спотыкаются
Первым пунктом называют микросервисы. Они решают организационные задачи, а к нагрузке добавляют сетевые вызовы и новые точки отказа.
Предлагают потоки для CPU-bound кода на Python. Из-за GIL выигрыша не будет, нужны процессы, очередь или вынос вычислений в нативный код.
Масштабируют приложение и забывают про базу. У каждого воркера свой пул, и двадцать подов по двадцать соединений упираются в max_connections PostgreSQL раньше, чем в CPU.