Performance

Hallo zusammen,

ich versuche mehrere einfache UPDATE-Queries durchzuführen. Dies erfolgt über Java/Hibernate Transaktionen (ohne Webserver/Container o.Ä.). HQL-Queries sehen wie folgt aus:

select X, Y, Z from mytable where K=?
update mytable set X=?, Y=?, Z=? where K=?

Der Query-Aufbau ist an sich einfach, es gibt aber mehrere Hunderttausende solcher Queries. Meine Frage ist, welche Optimierungsziele bei dieser einfachen Anwendung und konkretem System überhaupt möglich sind.

System: Quad-Core ca. 3 GHz, 16 GB RAM.
Software: Debian Squeeze, Java 7, PostgreSQL 9.1.6.

Irgendwo habe ich gesehen, dass pro CPU-Core max. 2 nebenläufige Queries sinnvoll sind. Heisst es, macht es keinen Sinn mehr als 8 Threads einzusetzen?

Was ist Euere Meinung wieviele Queries wie angegeben pro Sekunde maximal möglich sind?

Nach meinem Verständnis, stehen folgende Tuning-Bereiche zur Verfügung:

  • PostgreSQL Konfiguration
  • JVM Speicher
  • Hibernate Konfiguration, u.a. auch ConnectionPool-Einstellungen (c3p0)

Wo fange ich an und gibt es Best Practices? Was ist der beste Weg, die Performance in diesem Fall zu messen?

Wozu das Select? Ist das jeweils dieselbe Tabelle select und update?

Der Query-Aufbau ist an sich einfach, es gibt aber mehrere Hunderttausende solcher Queries. Meine Frage ist, welche Optimierungsziele bei dieser einfachen Anwendung und konkretem System überhaupt möglich sind.

Wird da eine Tabelle mit den Daten einer anderen via UPDATE verändert? Wenn ja, dann ist dieser Weg so quatsch.

System: Quad-Core ca. 3 GHz, 16 GB RAM.
Software: Debian Squeeze, Java 7, PostgreSQL 9.1.6.

Irgendwo habe ich gesehen, dass pro CPU-Core max. 2 nebenläufige Queries sinnvoll sind. Heisst es, macht es keinen Sinn mehr als 8 Threads einzusetzen?

Was ist Euere Meinung wieviele Queries wie angegeben pro Sekunde maximal möglich sind?

Hängt sehr stark von Deinem Plattensystem ab.

Nach meinem Verständnis, stehen folgende Tuning-Bereiche zur Verfügung:

  • PostgreSQL Konfiguration
  • JVM Speicher
  • Hibernate Konfiguration, u.a. auch ConnectionPool-Einstellungen (c3p0)

Wo fange ich an und gibt es Best Practices? Was ist der beste Weg, die Performance in diesem Fall zu messen?

Mir ist noch nicht ganz klar, was das wird. Ein Performance-Test oder eine reale Anwendung? Hast die postgresql.conf schon überarbeitet? Läuft (aus Sicht von PG) alles in einer TX ab? Das würde u.U. einiges bringen, dann aber kannst das nicht alles über N Connections rausballern.


Andreas

Hi Andreas,

danke für die Antwort.

Also,

  • die Anwendung ist real sofern ich hobby-mäßig etwas rumbasteln möchte. SELECT und UPDATE werden auf der selben Tabelle ausgeführt. Jede Query ist in einer TX, ich möchte eine nebenläufige Anwendung bauen und schauen wie sie skalieren kann. Daher auch N connections. Es ist ein statistisches Wörterbuch - wir schauen ob ein Wort schon da ist (SELECT) und wenn nicht, machen wir einen INSERT und sonst UPDATE. Am Anfang gibt es sehr viele INSERTS die dann von UPDATES mehr und mehr überholt werden. Ich überlege mir, alles im RAM zu machen und dann nur per INSERT rausschreiben - wenn man hierbei etwas gewinnen würde.

  • ich habe in der postgresql.conf alle relevanten Einstellungen einem Tutorial folgend etwas erhöht, dies scheint aber nicht viel Unterschied zu machen. Wir sollten von daher von der default-Konfiguration ausgehen.

  • Die Eckdaten zum Plattensystem sind: 6 Gb/s HDD 7200rpm, Software-RAID 1

Ich denke bevor ich etwas optimiere, soll ich mich für den sinnvollen Einstiegsgrad der Nebenläufigkeit entscheiden (4 cores - 8 Java-Threads?) und nach der Messung evaluieren, ob das System “viel” oder “wenig” leistet. Dafür aber benötige ich einen groben Vergleichswert, ob es 100, 1000 oder mehr tx/s werden können.

Mein Eindruck ist bisher dass die Anwendung bzw. Hibernate schnell eine große TX-Warteschlange aufbaut und es zu einem “Stau” kommt, d.h. TX-Queue wird schneller erzeugt als sie abgearbeitet werden kann (dies trotz erhöhter Speicher-Einstellungen in der postgresql.conf).

viele Grüße
pgnoob

Ich denke, der Schwachpunkt ist die IO-Last. Jedes Insert bzw. Update und das Commit danach erzwingt ein fsync, erst dann ist die TX fertig. Mit Software-RAID kommst da schnell an die Grenzen dessen, was machbar ist. Man kann das, wenn man die Parameter der Platten kennt, auch berechnen, google mal nach “harddisk iops” oder so.

Wenn Du das in schnell haben willst:

  • WAL auf separate Spindel legen
  • echtes RAID, RAID10 z.B., mit guten Controllern und Cache (write-cache mit BBU)
  • SAS-Platten, 15k oder SSD

Aus dem Bauch heraus denke ich, nicht mehr als das 1.5fache an Cores als Maximum für Threads.

Andreas

Hi,

ja I/O ist auf jeden Fall der Bottleneck hier.

Ich habe leider keine Möglichkeit, an dem HW-System rumzuschrauben. Was meinst Du, mit wievielen TX/s kann ich bei dem gegebenen System realistisch rechnen? (Grobschätzung)

Probier es aus und messe :wink:

select * from depesz; » Blog Archive » how many transactions per second?


Um mal eine grobe Peilung zu geben: mehr als ca. 120 werden es kaum werden, es sei denn, Deine Platten lügen.

Um mal Bruce M. zu zitieren:

{quote}
Have you ever run benchmarks that topped out at 250 Transactions per Second (tps)? What about 120 or 90? If so, you might have been stumped about why you consistently hit these numbers and could never go higher.

These numbers are common rotational latency numbers for hard disks. Specifically, 250, 120, and 90 represent rotational latencies for 15k, 7.2k, and 5.4k rpm drives, respectively.
{/quote}

Bruce Momjian: Postgres Blog


Dein Software-RAID wird dies noch verringern, vermute ich. Du kannst natürlich mehr Records pro Sekunde Inserten oder Updaten, aber dann mehr davon in einzelne TX zusammenfassen.

Ach ja: wenn Du an Deinem HW-System nicht schrauben kannst, auch kein Problem: wir haben bessere Maschinen, wirst halt Kunde bei uns :wink:



Andreas