Понимание медленной производительности Django
Мой веб-сервер масштабируется, и я использую Sentry Performance, чтобы попытаться лучше понять, где все происходит медленно. Одна вещь, которую я не совсем понимаю, это то, откуда может исходить медлительность, когда общее время выполнения запроса значительно отличается от времени, которое требуется для получения ответа
Например, одной из моих конечных точек требуется 40 секунд, чтобы получить ответ от пользователя. Вы увидите, что общее время ответа заняло невероятные 44 000 мс, хотя вся работа была выполнена примерно за 1 с (что все равно медленно, но не 44 с).
Редактирование: в качестве общего замечания, все мои конечные точки делают это - особенность заключается в этих пунктирных точках в конце временной шкалы, где начинаются любые фактические удары Django / базы данных. Он просто сидит пустой в течение целой минуты, прежде чем Django начинает что-то делать. Это потенциальная ошибка конфигурации guincorn или Uvicorn?
Дополнительная информация:
- Запуск гуникорна с невикорном:
poetry run gunicorn -w 17 myApp.asgi:application -k myApp.uvicorn.AppUvicornWorker --log-level=debug - Я получаю около сотни запросов в секунду, с которыми сервер должен быть более чем способен справиться - у него 32гб оперативной памяти и 8 ядер процессора.
AppUvicornWorker:
class AppUvicornWorker(UvicornWorker):
CONFIG_KWARGS = {"loop": "uvloop", "http": "httptools", "lifespan": "off"}
- Views - это просто базовые, совершенно стандартные для Django Rest Framework ListViewSets, которые запрашиваются:
class UserSerializer(serializer.ModelSerializer):
class Meta:
model = User
fields = ["id", "username", "name"]
class CommentSerializer(serializer.ModelSerializer):
user = UserSerializer()
class Meta:
model = Comment
fields = ["id", "text", "user"]
class CommentsViewSet(viewsets.ViewSet):
def list(self, request):
queryset = Comments.objects.all()
serializer = CommentSerializer(queryset, many=True)
return Response(serializer.data)
One of the reasons that this is slow is because for each Comment, it has to make a separate query to fetch the User data. You can boost efficiency with .select_related(…) [Django-doc]:
class CommentsViewSet(viewsets.ViewSet):
def list(self, request):
queryset = Comments.objects.select_related('user')
serializer = CommentSerializer(queryset, many=True)
return Response(serializer.data)
Это позволит получить данные из user в том же запросе, и таким образом предотвратить проблему запросов N+1.
Примечание: обычно модели Django присваивается сингулярное имя, поэтому
Commentвместо.Comments
