Django Request langsam

Django, Flask, Bottle, WSGI, CGI…
xerion21
User
Beiträge: 19
Registriert: Freitag 13. März 2015, 16:31

Hallo zusammen,

ich arbeite seit einiger Zeit nun mit Python und wollte nun eine Webapp mit Django schreiben. Leider habe ich das Problem, dass der Request (mit Django-Toolbar ausgewertet) sehr lange dauert (bis zu 10 Sekunden). Dies tritt aber nicht bei allen Seiten auf.

Ich weiß leider nicht woran das liegt :/

Kann mir hier jemand helfen?
Bzw. was für Infos braucht ihr?


Danke :)

P.S. Django läuft bei mir auf einem RPI. Daten sind schon in der Datenbank und werden auch sehr schnell ausgelesen, daran kann es nicht liegen.
BlackJack

@xerion21: Worin unterscheiden sich denn die Seiten bei denen es auftritt von denen wo es nicht auftritt?

Man könnte in die beteiligten Funktionen ja mal ein bisschen logging mit Zeitstempeln einbauen um zu sehen wo so viel Zeit verbraucht wird.
xerion21
User
Beiträge: 19
Registriert: Freitag 13. März 2015, 16:31

BlackJack hat geschrieben:Worin unterscheiden sich denn die Seiten bei denen es auftritt von denen wo es nicht auftritt?
Es sind verschiedene Seiten. Die eine Seite z.B. zeigt sämtliche User in einer Tabelle an. Dabei wird immer das template "user_table" aufgerufen und pro User dann "user_table_item".
Die andere Seite ist eine Seite zum Anlegen eines neuen Users. Hierbei wird über crispy_forms ein formular erzeugt. Bei diesem Formular werden allerdings auch sämtliche Adressen aus der Datenbank geladen (Dauer: 10 ms). Das sind nur ca 100.

Ich denke, dass es so langsam ist, weil die templates zum Aufbauen so lange brauchen. Aber ich kann das leider noch nicht beweisen...
BlackJack hat geschrieben:Man könnte in die beteiligten Funktionen ja mal ein bisschen logging mit Zeitstempeln einbauen um zu sehen wo so viel Zeit verbraucht wird.
Logging werde ich heute abend mal einbauen.

Was noch interessant ist, wenn ich dies lokal auf meinem Rechner ausführe mit "python manage.py runserver", dann habe ich nicht die langsamen requests. Diese entstehen nur, wenn auf meinen RPI zugreife.
Ich werde dies auch noch mal auf meiner VM testen, ob dies da auch so langsam ist

***** UPDATE *****
Auf meiner VM braucht der gleiche Aufruf auf diese Seite nur 0.5 Sekunden...
Kann es wirklich an meinem RPI liegen? Dieser hat an sich wirklich keine große Auslastung
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

xerion21 hat geschrieben: Die andere Seite ist eine Seite zum Anlegen eines neuen Users. Hierbei wird über crispy_forms ein formular erzeugt. Bei diesem Formular werden allerdings auch sämtliche Adressen aus der Datenbank geladen (Dauer: 10 ms). Das sind nur ca 100.
Ein "select * from table" skaliert niemals, lass dir was anderes einfallen.
Ich denke, dass es so langsam ist, weil die templates zum Aufbauen so lange brauchen. Aber ich kann das leider noch nicht beweisen...
Ja, Templates sind nicht die schnellsten, aber im Normalfall auch nicht so ein Problem wenn man normale Datenmengen hat.
***** UPDATE *****
Auf meiner VM braucht der gleiche Aufruf auf diese Seite nur 0.5 Sekunden...
Kann es wirklich an meinem RPI liegen? Dieser hat an sich wirklich keine große Auslastung
Ja, der RPI ist definitiv nicht schnell. Abgesehen davon verlangsamt die debug-toolbar auch die Ausführung der Seiten. IO ist auf dem RPI im Normalfall sehr lahm, schau also dass du nicht viele Daten brauchst und diese schnell zu lesen sind.
BlackJack

@apollo13: Das erklärt aber alles nicht bis zu 10 Sekunden Seitenaufbau vs. 10 ms wenn man den `SELECT * …` direkt absetzt. Das ist schon ein ziemlich krasser Zeitunterschied.
xerion21
User
Beiträge: 19
Registriert: Freitag 13. März 2015, 16:31

Ja der Select der Daten aus der Datenbank benötigt 10 Sekunden.

Der Aufbau der Seite, also der Templates dauert allerdings so lange (insgesamt 10 Sekunden). Ich frage mich warum.
Vor allem haben die beiden Seiten, welche ich oben beschrieben habe, eigentlich nichts gemeinsam...

Bei dem einen wird auf viele verschiedene Templates zugegriffen, auf dem anderen habe ich 1 Template und benutze Crispy_Forms.

Hat jemand eine Idee, wie ich das Problem weiter identifizieren kann? Oder vielleicht sogar eine komplette Lösung? ;)
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

Mir fällt dazu als erstes folgendes ein:

Wärend der Ausführung des Scripts mit `top` schauen ob der PI anfängt zu swappen oder hauptsächlich auf IO wartet oder halt doch CPU.

1. SWAP ist bei Top die Zeile die mit `KiB Swap` beginnt
2. bei der Zeile `%Cpu(s) sollte der wert vor `wa` nicht die meiste Zeit sehr groß sein. Dann wartet die CPU nur auf Daten vom Dateisystem

Das sagt dir zwar nicht wo im Code die Zeit vergeht, aber es zeigt dir relativ schnell wo der Flaschenhals liegt.
xerion21
User
Beiträge: 19
Registriert: Freitag 13. März 2015, 16:31

Sr4l hat geschrieben: 1. SWAP ist bei Top die Zeile die mit `KiB Swap` beginnt
2. bei der Zeile `%Cpu(s) sollte der wert vor `wa` nicht die meiste Zeit sehr groß sein. Dann wartet die CPU nur auf Daten vom Dateisystem
Danke erstmal für die schnelle Antwort!
Ich habe mal eben mit top geschaut, was so auf meine RPI passiert.

Unter Normalbetrieb (ohne Seitenaufruf) habe ich überall normale Werte drin stehen:
KiB Swap: 28 used
KiB Mem: 428428 used, 17312 free
%CPU: 18,8 us, 0,0 wa

Wenn ich den Seitenaufruf mache habe ich folgende Werte:
KIB Swap: 28 used
KiB Mem: 428428 used, 17312 free
%CPU 95,9 us, 0,0 wa


Ach ja noch als Info. Momentan habe ich das Django Projekt über "runserver" laufen, aber selbst das stellt bei meinen anderen Systemen keine Probleme da...
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

BlackJack hat geschrieben:@apollo13: Das erklärt aber alles nicht bis zu 10 Sekunden Seitenaufbau vs. 10 ms wenn man den `SELECT * …` direkt absetzt. Das ist schon ein ziemlich krasser Zeitunterschied.
Ka, dafür hab ich zu wenig Infos -- aber alleine die Tatsache dass die debug toolbar zum messen dieser Zeit verwendet wird macht das ganze nicht mehr aussagekräftig. Ich habe hier auch Seiten die sofort laden und mit der debug toolbar gar nimmer fertig werden…
xerion21
User
Beiträge: 19
Registriert: Freitag 13. März 2015, 16:31

apollo13 hat geschrieben:
BlackJack hat geschrieben:@apollo13: Das erklärt aber alles nicht bis zu 10 Sekunden Seitenaufbau vs. 10 ms wenn man den `SELECT * …` direkt absetzt. Das ist schon ein ziemlich krasser Zeitunterschied.
Ka, dafür hab ich zu wenig Infos -- aber alleine die Tatsache dass die debug toolbar zum messen dieser Zeit verwendet wird macht das ganze nicht mehr aussagekräftig. Ich habe hier auch Seiten die sofort laden und mit der debug toolbar gar nimmer fertig werden…
selbst mit anderen Zeiterfassungsmöglichkeiten dauert der Request immer noch 10 Sekunden...
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

poste doch mal den Code vom View und vom Template.

Gruß, noisefloor
xerion21
User
Beiträge: 19
Registriert: Freitag 13. März 2015, 16:31

noisefloor hat geschrieben:Hallo,

poste doch mal den Code vom View und vom Template.

Gruß, noisefloor

Code: Alles auswählen

@login_required
def player_list(request):
    players = Player.objects.all()
    context = {'players' : players}
    return render(request, 'Spielerdatenbank/player_list.html', context)

Code: Alles auswählen

{% extends "base.html" %}

{% block title %}Spielerliste{% endblock %}

{% block heading %}
<h2>Spielerliste</h2>
{% endblock %}

{% block content %}
{% if user.is_authenticated %}
<p><a class="btn btn-default" href="{% url "Spielerdatenbank_player_create" %}"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Neuer Spieler</a></p>
{% endif %}
<ul class="list-unstyled">
{% for player in players %}
    <li class="well">{% include "Spielerdatenbank/player_list_item.html" %}</li>
{% empty %}
    <li>Keine Spieler</li>
{% endfor %}
</ul>
{% endblock %}
}

Code: Alles auswählen

<a class="lead" href="/player/show/{{ player.id }}">{{ player.lastname }}, {{ player.firstname }}</a>
{% if player.birthday %}
    <br><b>Geburtstag: </b>{{player.birthday|date:"d.m.Y"|linebreaksbr }}
{% endif %}
<br><b>Erstellt vor: </b>{{ player.date_created|timesince }}
Ein Beispiel View, bei dem es länger dauert.
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

xerion21 hat geschrieben: Wenn ich den Seitenaufruf mache habe ich folgende Werte:
KIB Swap: 28 used
KiB Mem: 428428 used, 17312 free
%CPU 95,9 us, 0,0 wa
Ach ja noch als Info. Momentan habe ich das Django Projekt über "runserver" laufen, aber selbst das stellt bei meinen anderen Systemen keine Probleme da...
Mein Einschätzung wäre dazu das sich alle relevanten Daten bereits im Cache befinden und es ein eine reines Rechenproblem ist. Da der Raspberry PI kein rechen Monster ist würde ich darauf tippen das SELECT auf große Datenbanken einfach ihre Ressourcen benötigen.

Über welche Größenordnung sprechen wir bei `players = Player.objects.all()`? 10? 100? 1000 Einträge?
Mal die Zeit genommen vor und nach Player.objects.all()?
xerion21
User
Beiträge: 19
Registriert: Freitag 13. März 2015, 16:31

Sr4l hat geschrieben: Über welche Größenordnung sprechen wir bei `players = Player.objects.all()`? 10? 100? 1000 Einträge?
Mal die Zeit genommen vor und nach Player.objects.all()?
Momentan befinden sich ca 100 Einträge in dieser Tabelle.
Diese liegen momentan noch in einer sqlite-Datenbankdatei.

Ich glaube irgenwie nicht, dass es die DB-Abfrage ist, die langsam ist, denn die Debug-Toolbar zeigt an, dass diese Anfrage 50 ms benötigt.


Zu der Rechenleistung: Wenn ich mir einen Server miete, besitze ich auch gegen 512 MB Rechenleistung. Normal sollte dies kein Problem darstellen.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

die Langsamkeit ist aber nicht dadurch bedingt, dass das bootstrap.css zu langsam ausgeliefert wird, oder? Normalerweise ist das zwar kein Problem (zumindest nicht bei meinen Django-Projekten), aber wenn wir gerade noch beim rumraten sind, sollten wir das nicht ausschließen ;-)

Zweiter Tipp zum Debugging:
Modifiziert den View mal so, dass die DB-Abfrage ausfällt und du dem Template direkt eine fertige Liste mitgibst. Wenn das dann immer noch lange dauert, kannst du DB-Abfrage als Quelle der Langsamkeit ausschließen.

Gruß, noisefloor
BlackJack

Passiert sonst noch irgend etwas, zum Beispiel schreibende Zugriffe auf die Datenbank? Wie ist der Raspi ans Netz angebunden? WiFi oder Netzwerkkabel?
xerion21
User
Beiträge: 19
Registriert: Freitag 13. März 2015, 16:31

noisefloor hat geschrieben:Hallo,

die Langsamkeit ist aber nicht dadurch bedingt, dass das bootstrap.css zu langsam ausgeliefert wird, oder? Normalerweise ist das zwar kein Problem (zumindest nicht bei meinen Django-Projekten), aber wenn wir gerade noch beim rumraten sind, sollten wir das nicht ausschließen ;-)

Zweiter Tipp zum Debugging:
Modifiziert den View mal so, dass die DB-Abfrage ausfällt und du dem Template direkt eine fertige Liste mitgibst. Wenn das dann immer noch lange dauert, kannst du DB-Abfrage als Quelle der Langsamkeit ausschließen.

Gruß, noisefloor
Ich habe das Laden des bootstrap.css mal ausgeschaltet. Es hat sich nichts geändert.

Wie soll ich dem View einer fertige Liste mitgeben? Dazu müsste ich 95 Daten fest reincoden?
BlackJack

@xerion21: Die kannst Du ja erstellen. Vielleicht auch einen Eintrag 95 mal an eine Liste anhängen.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
xerion21 hat geschrieben:Wie soll ich dem View einer fertige Liste mitgeben? Dazu müsste ich 95 Daten fest reincoden?
Du kannst den Query auch in der Shell ausführen, das Ergebnis per `print` ausgeben lassen und dann per Copy&Paste in den Code hardcoded einfügen.

Oder halt wie BlackJack sagt einen (Fantasie-) Datensatz von Hand tippen und dann eine Liste mit 95x dem gleichen Eintrag hardocden.

Gruß, noisefloor
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

xerion21 hat geschrieben:

Code: Alles auswählen

{% for player in players %}
    <li class="well">{% include "Spielerdatenbank/player_list_item.html" %}</li>
{% empty %}
Inklude in der Schleife ist möglicherweise ein Template-Resolve pro Spieler. Aktivier mal den cached Templateloader, oder tu testweise den Inhalt von player_list_item.html direkt hinein.
Antworten