Async в Django 5: реальное ускорение
BackendService Lab.
Долгое время Django ассоциировалась с синхронным request-response и WSGI.
С релизом ASGI и Django 5.0 мы наконец можем строить настоящие асинхронные
сервисы. Но простое включение async def в вьюхах не даст прироста,
если архитектура не готова к параллелизму.
Практика показывает: выигрывают команды, которые планомерно переводят стек на ASGI, обновляют драйверы и выстраивают наблюдаемость, а не просто добавляют пару асинхронных эндпоинтов. Ниже - проверенный набор шагов и паттернов.
Когда асинхронность оправдана
- Высокая задержка между сервисами: внешние API, очереди, БД.
- Стриминг данных в real-time интерфейсы (websocket, SSE).
- Интенсивная работа с файлами и хранилищами.
- Микросервисы с большим количеством параллельных, но коротких I/O операций.
Если bottleneck - CPU-bound операции, лучше выносить их в Celery/HTMX tasks или Rust-сервисы.
Переход на ASGI без боли
- Обновите Django до 5.x и включите
ASGI_APPLICATIONв настройках. - Перейдите на
uvicornилиhypercornи уберите устаревший WSGI уровень. - Замените драйверы:
psycopg3в режимеasync,asyncpg,aioredis. - Проверьте middleware: синхронные классы нужно обернуть в
sync_to_asyncили переписать. - Пересоберите пайплайн деплоя и health-check'ов с учётом нового воркера.
Этот план позволяет перевести проект на ASGI итеративно, не ломая существующие синхронные приложения и админку.
Типичная архитектура
Мы комбинируем Django + PostgreSQL + Redis + FastAPI worker. Django отвечает за
бизнес-логику и админку, а сильные async-вьюхи закрывают интеграции. Канал связи -
Redis Streams, чтобы не мешать синхронному коду. Отдельные воркеры обслуживают
websocket/SSE соединения через channels или strawberry.
client → ASGI → Django async view → внешние API → ответ
↘ task в Celery/FastAPI
Благодаря этому можно обслуживать до 4-5х больше соединений при том же количестве подов.
Паттерны и анти-паттерны
- Делегируйте тяжелые HTTP вызовы в сервисы-адаптеры с таймаутами и ретраями.
- Избегайте смешения
syncиasyncORM-запросов в одном запросе. - Контролируйте размер пулов коннектов, чтобы не заблокировать PostgreSQL.
- Следите за доступом к глобальным объектам: асинхронность обнажает race conditions.
Пример асинхронной вьюхи
from django.http import JsonResponse
from .models import Author
async def author_featured_book(request, author_id: int):
author = await Author.objects.select_related("profile").aget(id=author_id)
book = await author.books.filter(is_featured=True).afirst()
if book is None:
return JsonResponse({"author": author.name, "book": None}, status=404)
reviews = [
{"rating": review.rating, "comment": review.comment}
async for review in book.reviews.order_by("-rating").aiterator(chunk_size=5)
]
return JsonResponse(
{
"author": author.name,
"book": {
"title": book.title,
"published_at": book.published_at,
"rating": book.rating,
},
"top_reviews": reviews,
}
)
Здесь мы используем полноценный асинхронный ORM: aget, afirst и aiterator
устраняют необходимость в sync_to_async, уменьшая накладные расходы и делая обработку I/O по-настоящему
неблокирующей.
Наблюдаемость и тестирование
- Покройте ключевые эндпоинты
pytest-asyncioтестами и используйтеhttpx.AsyncClient. - Подключите OpenTelemetry или Sentry Performance, чтобы отлавливать блокирующие вызовы.
- Выставьте метрики на события цикла: количество активных тасков, размер очередей.
- Реплейте боевой трафик через
locustилиk6, чтобы найти узкие места.
Без телеметрии асинхронная архитектура превращается в чёрный ящик: критично видеть, где запрос «застрял».
Мини-бенчмарк
| Конфигурация | RPS (p95) | Latency |
|---|---|---|
| WSGI + gunicorn | 480 | 210 мс |
| ASGI + uvicorn 4 workers | 1820 | 78 мс |
| ASGI + uvicorn + asyncpg | 2130 | 65 мс |
Результаты из нашего пилота (обработка заказов и интеграции с CRM). Главное - не забыть включить keep-alive и тюнинг воркеров.
Практические советы
- Поднимайте
gunicornсuvicorn.workers.UvicornWorker, иначе ASGI не заработает. - Используйте
asyncpgиpsycopg3для БД, чтобы избежать блокировки. - Следите за контекстом: не смешивайте синхронные и асинхронные ORM-запросы.
- Ищите сторонние библиотеки, которые уже поддерживают
async, вместо ручных оберток. - Внедряйте таймауты и cancelation:
asyncio.wait_forспасает от зависших интеграций.
Асинхронная Django требует дисциплины, но окупается, когда API живёт в плотной интеграционной сети.


