Seite wählen

NETWAYS Blog

Über Physik, Erdnuss-Snacks und Schlangenöl aka Datenbanken

Achtung ein Hinweis in eigener Sache, dieser Artike kann Spuren von Polemik und rant enthalten!

Neal Stephenson hat in seinem wunderbaren Roman Cryptonomicon eine kleine Randgeschichte über eine Bandsäge eingebaut. Der für mich schönste Satz darin ist:

Anecdotes about accidents involving the bandsaw were told in hushed voices and not usually commingled with other industrial-accident anecdotes.

An diesen Satz muss ich immer denken, wenn es auf PostgreSQL-Konferenzen in den abendlichen War-Story-Runden zu Geschichten über MySQL oder MariaDB kommt, zugegeben hauptsächlichen deren Migration zu PostgreSQL.
Bei Entity–Attribute–Value (EAV) Schemas, nicht getesteten Backups, Prozeduren, die nicht maskierte Benutzereingaben als Tabellennamen für dynamisches SQL hernehmen etc. kann man sagen sie hätten es wissen können bzw. müssen. (Halt die üblichen Katastrophen, die man sich in gemütlicher Runde so erzählt, Datenbanker sind halt schon ein komischer Haufen.)

Das ist bei MySQL wie auch diversen anderen Datenbanken irgendwie anders, und ich frage mich immer wieder, warum ist das so?

Es hat evtl. etwas mit einer grundsätzlichen Bereitschaft zu tun, über physikalische Gegebenheiten nachzudenken.

Wenn jemand eine PostgreSQL-Mailingliste anschreibt und erklärt, dass Oracle eine Anfrage in 0,009 ms beantwortet, für die PostgreSQL über zwei Minuten benötigt, dann ist diese Frage erst einmal legitim.

Wenn dann aber nach und nach herauskommt, dass es um eine Tabelle mit 9.649.110 Zeilen und rund 3,5GB geht, die mittels SELECT * FROM table1; komplett gelesen wird, müsste einem doch sofort klar sein, das Ersteres nicht sein kann? Das brandneue DDR5-RAM schafft gerade mal 5,2 GT/s (Megatransfer), und da ist noch keine Netzwerkverbindung im Spiel. In 0,000009 Sekunden schafft selbst Licht „nur“ rund 2,7km.

Wie können solche offensichtlichen Mess- oder Denkfehler nicht sofort auffallen? Die 2,7 km muss man ja nicht parat haben, aber dass 0,000009 Sekunden ein sehr kurzer Zeitraum sind, um 3,5GB Daten zu übertragen, liegt doch eigentlich für ITler nah?

Was mich zum Thema MM (Multi-Master-Replication) oder politisch korrekt Multi-Primary, Write-Anywhere etc. bringt…

PostgreSQL-Umsteiger von MySQL, MariaD, CockroachDB, Oracle,… fragen immer wieder (z.B. im Telegram-/Slack-Channel, den Mailinglisten, Seminaren), wie man denn einen MM-Cluster aufbaut.

Der Dialog läuft üblicherweise so ab:
Q: „Ich komme von und habe dort einen Multimaster-Cluster. Wie baue ich dasselbe mit PostgreSQL auf?“
A: „Gar nicht. Wahrscheinlich willst du das aber auch gar nicht.“
Q: „Doch, doch. Ich brauche die Hochverfügbarkeit und die Performance (ein Knoten allein schafft meine Schreiblast nicht)!“
A: „MM kostet Performance und verbessert deine Verfügbarkeit nicht wirklich. Benutze einfach eine klassische Replikation, ggfs. mit Lese-Lastverteilung.“

Verdeutlichen wir uns kurz, was es für eine Datenbank bedeutet, auf mehr als einem Clusterknoten schreibenden Zugriff zu erlauben:

  • Sequenzen (für Primärschlüssel bzw. „auto-increment/identity“ Spalten) müssen synchronisiert werden, damit keine IDs doppelt vergeben werden
  • es muss sichergestellt werden, dass bei z.B. DELETE-Statements die referentielle Integrität erhalten bleibt; es muss also die Möglichkeit geben,
    clusterweit Datensätze oder sogar ganze Tabellen zu LOCKen
  • wenn auf mehreren Knoten derselbe Datensatz verändert wird, muss eine Konfliktbehandlung erfolgen. Wenn die nicht dem Zufall, sprich dem Replikations-Lag überlassen werden soll, werden clusterweite Transaktions-IDs benötigt
  • und zum Thema Schreiblast: Ziel ist es ja weiterhin, einen einheitlichen und konsistenten Datenbestand zu haben, die Schreiblast pro Knoten bleibt also unverändert!

Je mehr Knoten beteiligt sind, desto mehr Koordination ist erforderlich. Und jede dieser Aktivitäten benötigt Zeit, mindestens 1-2 Netzwerk-Roundtrips.

Je weiter meine Knoten voneinander entfernt sind, desto mehr Zeit und damit Performance geht allein schon durch pure Physik verloren!

Für PostgreSQL gibt bzw. gab es einige FOSS-Varianten, die MM beherrschen (Postgres-XC, Postgres-XL, BDR). Und 2ndQuadrant, deren derzeitiger Maintainer, sagt sinngemäß:

Die Einschränkungen und zusätzlichen Maßnahmen, die MM mit sich bringt bzw. erfordert, sind so eklatant, dass MM wahrscheinlich nie Einzug in den PostgreSQL-Core kommen wird. Und so ein Cluster ist explizit nicht für Hochverfügbarkeit gedacht, sondern um z.B. logisch weitgehend voneinander getrennte Datenbestände, z.B. Verkäufe und Lagerbestände in verschiedenen Ländern, in den jeweils anderen Standorten verfügbar zu machen.

Der Aufwand ist also durchaus erheblich, und mit ein klein wenig Nachdenken sollten sich die Zusammenhänge und Gründe auch jedem Interessenten erschließen.

Oder man macht sich einfach keine Gedanken und setzt bidirektionale Replikation auf, „was soll schon passieren“ und „war ganz einfach, mit diesem Tutorial aus dem Netz“…

Multimaster-Clustering ist ein wenig wie im Dunkeln, bei Regen, mit 250 km/h über die Autobahn zu fahren. Als Beifahrer…

  1. Man wünscht sich auf jeden Fall, dass die Person am Steuer nicht nachtblind (sprich: „has RTFM“) ist
  2. das Auto und seine Grenzen sehr genau kennt (pun intended!)
  3. ein oder besser mehrere Fahrsicherheitstrainings hinter sich hat.

Und trotzdem ist man letztlich Faktoren überlassen, auf die man keinen Einfluss hat. Meist geht es ja auch gut…

Hier schließt sich der Kreis zur Bandsäge von oben, denn gewisse DBMS (Datenbank Management Systeme) stehen ja schon ohne bidirektionale Replikation nicht unbedingt im Ruf, Datenintegrität besonders hoch zu bewerten (https://bugs.mysql.com/bug.php?id=11472).

Zur Performance:

Ich erinnere mich, dass Oracle seinerzeit für ihr RAC angegeben hat, dass jeder neue Knoten 90% der Leistung des vorherigen Knotens bringt*. Was ein sensationell guter Wert wäre, aber eben alles andere als lineare Skalierung (linear steigt lediglich der Preis…):


WITH perf AS (
SELECT nodes, 0.9^(nodes-1) AS nextnodes_performance
FROM generate_series(1,8) AS nodes
)
SELECT *
,avg(nextnodes_performance) OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS average_performance
,nodes * avg(nextnodes_performance) OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS overall_performance
FROM perf;
┌───────┬───────────────────────┬────────────────────────┬────────────────────────┐
│ nodes │ nextnodes_performance │ average_performance │ overall_performance │
├───────┼───────────────────────┼────────────────────────┼────────────────────────┤
│ 1 │ 1.0000000000000000 │ 1.00000000000000000000 │ 1.00000000000000000000 │
│ 2 │ 0.9000000000000000 │ 0.95000000000000000000 │ 1.90000000000000000000 │
│ 3 │ 0.8100000000000000 │ 0.90333333333333333333 │ 2.70999999999999999999 │
│ 4 │ 0.7290000000000000 │ 0.85975000000000000000 │ 3.43900000000000000000 │
│ 5 │ 0.6561000000000000 │ 0.81902000000000000000 │ 4.09510000000000000000 │
│ 6 │ 0.5904900000000000 │ 0.78093166666666666667 │ 4.68559000000000000002 │
│ 7 │ 0.5314410000000000 │ 0.74529014285714285714 │ 5.21703099999999999998 │
│ 8 │ 0.4782969000000000 │ 0.71191598750000000000 │ 5.69532790000000000000 │
└───────┴───────────────────────┴────────────────────────┴────────────────────────┘

* vielleich waren es auch 80% oder 95% oder die Aussage war einfach kompletter Humbug?

Zur Verfügbarkeit:

Ein anderes gerne vorgebrachtes Argument, z.B. auf galeracluster.com ist „Transparent to Applications: Required no or minimal changes to the application“.

Ich habe mich immer gefragt, wie Oracle beim RAC das TCP-Protokoll aushebelt, eine Netzwerkverbindung bricht nun einmal ab, wenn der Host offline geht. Bis mir mal jemand gesteckt hat, dass man auf ein RAC mit einer anderen Client-Bibliothek zugreift. Mit anderen Worten: der Verbindungsabbruch wird nicht an das Programm durchgereicht, sondern das Statement (bzw. die Transaktion?) wird auf einer neuen Verbindung wiederholt. Ich unterstelle einfach mal, dass Galera etc. ähnlich arbeiten.

Können das die modernen Connection-Pools, ORMs etc. nicht auch alle schon mehr oder weniger selbsttätig oder mit „minimal changes“? Eine Applikation sollte es auf jeden Fall können. Aber gut, es sollte auch keine Applikationen mehr geben, die mehr als ein Statement außerhalb einer Transaktion durchführen…!

Auf jeden Fall rücken solche Aussagen die entsprechenden Produkte m. E. in die Nähe eines Worts, das im Titel dieses Beitrags steht…

Der klassische Ansatz:

Der Vollständigkeit halber sei noch kurz umrissen, wie eine hochverfügbare Cluster-Lösung mit PostgreSQL oder auch anderen DBMS aussehen kann.

  • ein Knoten („Primary“ oder non-PC „master“, P) erlaubt lesende und schreibende Zugriffe (R/W)
  • n andere Knoten („Secondaries“ oder „slaves“, S1,…,Sn) erhalten die Änderungen von P und erlauben lesende Zugriffe (RO)
  • zusätzlich landen alle Änderungen in einem Archiv, aus dem jeder beliebige Zeitpunkt wieder hergestellt werden kann (PITR)
  • Sn können synchron oder asynchron replizieren (bei synchroner Replikation sollte n > 1 sein!)

Der Zugriff auf den Knoten P kann auf verschiedene Arten erfolgen:

  • Clients erhalten die IPs aller Knoten und können selbst festlegen, ob sie Schreib-Lesezugriff benötigen
  • P hat eine zusätzliche virtuelle IP-Adresse, unter der er angesprochen wird (gerne zusammen mit P in einer Resource-Group der eingesetzten HA-Lösung)
  • ein vorgeschaltetes Tool, z.B. HAProxy weiß, welcher Knoten gerade P ist

Zusätzlich können Clients entscheiden, ob ihre jeweilige Aktivität nur lesend oder schreibend ist und sich entsprechend mit P oder einem Sn unterhalten, um die Gesamt-Performance zu verbessern.

Manche Pooler, z.B. PGPool-II können diese Unterscheidung sogar selber mehr oder weniger gut treffen. Vorsicht aber mit z.B. schreibenden Triggern!

Dass eine Client-Software eine halbwegs funktionale Fehlerbehandlung haben sollte, vielleicht sogar mit ein wenig Wartezeit vor’m retry, versteht sich von selbst.

Multi-Master-Datenbankcluster bringen einige Aspekte mit, die zu wenig oder zumindest selten beachtet werden. Manche sind ausgesprochen gefährlich!

Eine klassische Replikationslösung bietet annähernd dieselbe Verfügbarkeit, i.A. deutlich bessere Performance und bereitet auf Dauer wesentlich weniger Kopfschmerzen.

Wie man ein solches Cluster aufbaut, lernt man in unserem Kurs PostgreSQL Fundamentals.

Gunnar „Nick“ Bluth hat seine Liebe zu relationalen Datenbanken Ende des letzten Jahrtausends entdeckt. Über MS Access und MySQL 3.x landete er sehr schnell bei PostgreSQL und hat nie zurückgeschaut, zumindest nie ohne Schmerzen. Er verdient seine Brötchen seit beinahe 20 Jahren mit FOSS (Administration, Schulungen, Linux, PostgreSQL). Gelegentlich taucht er auch tiefer in die Programmierung ein, so als SQL-Programmierer bei der Commerzbank oder in App-Nebenprojekten.

Galera Clustering

Viele von Euch kennen es bestimmt schon, das Project Galera. Dieses vereint die wsrep API mit MySQL bzw. dessen Fork MariaDB. Zum aktuellen Zeitpunkt werden schon InnoDB und die XtraDB – Storage Engine unterstützt. Letzteres ist eine InnoDB-Erweiterung und wird von Percona entwickelt .

Galera-Cluster-logo-1024x195

Der Galera Cluster bringt folgende Features/Benefits mit:

  • Multi-Master schon von Haus aus
  • Synchrone Replication kein Datenverlust mehr auch keine Slave-Lags mehr (Boa wie mich das immer wieder nervt)
  • Eng gekoppelt Alle Knoten haben grundsätzlich denselben Status, keine Daten mehr die auseinander laufen
  • Multi-threaded Slave für bessere Performance der Nutzlast
  • Keine Master-Slave Failover Operationen nötig oder die Notwendigkeit eine virtuelle IP binden zu müssen
  • Hot Standby keine Downtimes während des Failover (denn es gibt keinen Failover mehr)
  • Automatic Node Provisioning kein manuelles Eingreifen mehr um Knoten in den Cluster zu bringen, die Daten werden automatisch auf den neuen Knoten repliziert
  • Supports InnoDB bald auch MyISAM (ist noch experimentell)
  • Transparent zur Application benötigt in Kombination mit GLB (oder HAproxy) keine Änderungen an der Applikation
  • Kein Aufspalten von Read und Write Operationen nötig (einfach Feuer auf das Ding 😉 ).

Galera ist somit die Lösung für Unternehmungen die ein hohes Aufkommen an Schreib- und Lese -Operationen in ihren Datenbanken erwarten. Die Main „Use Cases“ für den Betrieb des Galera Cluster sind eben kurz und gut, Skalierung der Schreib-Operationen, entkoppeln von Latenz Killern (wie zB. lange laufende Queries).
Die Entwickler des Forks MariaDB haben diese vielfältigen Möglichkeiten erkannt und bieten auf ihren Seiten Anleitungen zum Betrieb so eines Basic Setups an. Ebenfalls werden dort fertige Pakete für die Installation auf alle Major Linux Distributionen angeboten, somit fällt auch schon mal das Kompilieren weg.
Für das Setup können zwei Loadbalancing-Produkte zum Einsatz kommen: Zum einen der schon etwas in die Jahre gekommene (aber immer noch sehr beliebte) HAproxy und zum anderen GLB (Galera LoadBalancer), der eigens für Galera, aber außerhalb des Projekts entstanden ist. Wir bevorzugen für unsere Setups meist den GLB da dieser auch während der Laufzeit (wenn nötig auch automatisiert durch Skripte) konfiguriert bzw. gesteuert werden kann. Änderungen können somit im laufenden Betrieb und auch unter Last problemlos vorgenommen werden. Wenn es dann doch mal knapp wird, kann man im Betrieb ganz einfach einen weiteren Knoten hinzufügen 🙂

ZFS Replikation mit zrep

Das Dateisystem ZFS wurde ursprünglich von der Firma „Sun Microsystems“ entwickelt, die dann später bekanntermaßen von Oracle gekauft wurde. Das sind jetzt keine wirklichen Neuigkeiten und ZFS ist auch nicht neu, aber immer noch in seinen Bereichen das Maß der Dinge. Auf Linux muss man allerdings wegen Lizenzschwierigkeiten von Haus aus darauf verzichten und sich mit dem FUSE Modul oder dem zfsonlinux Kernel Modul Abhilfe schaffen. Für Linux steht ja schon seit langem BTRFS in den Startlöchern, was aber bis heute noch nicht als stable markiert ist.
ZFS ist ein Copy on Write Filesystem, das durch ein reiches Feature Set glänzen kann. Unter anderem unterstützt es Snapshots und kann diese Snapshots inkrementell versenden, um einen Datenzustand als Backup oder für höhere Verfügbarkeit auf einen weiteren Server vorhalten zu können. Das ganze ist denkbar einfach:
zfs snapshot tank/myzfs@1hourago
zfs snapshot tank/myzfs@now
zfs send -I tank/myzfs@1hourago tank/myzfs@now | ssh server2.domain zfs receive tank/myzfsbackup
Die drei Befehle erzeugen zwei Snapshots die dann dann mit „zfs send“ inkrementell von „1hourago“ bis „now“ an den „server2“ gesendet und dort empfangen werden. Die Schwierigkeit besteht jetzt darin, Snapshots auch wieder zu löschen und dafür zu sorgen, dass die Snapshots aufeinander aufbauen.
Hierfür gibt es ein KSH Script mit dem Namen zrep. Zrep sorgt sich genau darum und kann noch viel mehr. Neben dem initialen synchronisieren und dem Handling der Snapshots kann mit zrep auch auf den zweiten Server im Fehlerfall geschwenkt werden. Während des Schwenks werden die Filesysteme auf beiden Seiten readonly gesetzt, der letzte Zustand gesynced und anschließend läuft die Replikation in die andere Richtung weiter.
Mehr Informationen zu zrep findet man auf der Website zu dem Projekt.

Sebastian Saemann
Sebastian Saemann
CEO Managed Services

Sebastian kam von einem großen deutschen Hostingprovider zu NETWAYS, weil ihm dort zu langweilig war. Bei uns kann er sich nun besser verwirklichen, denn er leitet das Managed Services Team. Wenn er nicht gerade Cloud-Komponenten patched, versucht er mit seinem Motorrad einen neuen Rundenrekord aufzustellen.

MySQL Cheat-Sheet

Da ich euch nicht mit Dingen wie SELECT, INSERT oder UPDATE nerven möchte, aber es auch immer wieder Dinge gibt die ich regelmäßig nachschlagen muss, hier mein persönliches MySQL-Cheat-Sheet in der Hoffnung das es euch auch helfen möge 😉
Mitschneiden der MySQL-Session, z. B. für Doku’s:
[user@host ~]$ mysql -u root -p --tee=/tmp/what_i_have_done.log
Logging to file '/tmp/what_i_have_done.log'
Enter password:

Anzeigen aller DB’s mit der jeweiligen Größe in MB:
SELECT table_schema "Data Base Name",
sum( data_length + index_length ) / 1024 /
1024 "Data Base Size in MB",
sum( data_free )/ 1024 / 1024 "Free Space in MB"
FROM information_schema.TABLES
GROUP BY table_schema ;

Auflisten aller Benutzer und deren Datenbankberechtigungen:
SELECT grantee, table_schema, privilege_type FROM information_schema.schema_privileges;

Klonen von Tablellen (keys und index werden nicht automatisch übernommen!):
CREATE TABLE AS SELECT * FROM ;

Erstellen / Wiederherstellen einer Replikation:
STOP SLAVE;
RESET SLAVE;
CHANGE MASTER TO MASTER_HOST='myotherdbms', MASTER_USER='replication_user', MASTER_PASSWORD='nsa_will_never_guess', MASTER_LOG_FILE='mysql-bin.00000', MASTER_LOG_POS=414138;
START SLAVE;

Bei Fehlern in der Replikation auch gerne gesehen… Ignoriere eine Anzahl N an Fehlern:
SET GLOBAL sql_slave_skip_counter = N;

Sollte ich noch mehr coole Sachen finden, werde ich diese Liste selbstverständlich erweitern 🙂

Tobias Redel
Tobias Redel
Head of Professional Services

Tobias hat nach seiner Ausbildung als Fachinformatiker bei der Deutschen Telekom bei T-Systems gearbeitet. Seit August 2008 ist er bei NETWAYS, wo er in der Consulting-Truppe unsere Kunden in Sachen Open Source, Monitoring und Systems Management unterstützt. Insgeheim führt er jedoch ein Doppelleben als Travel-Hacker und renoviert, baut und bastelt als Heimwerker an allem was er finden kann.

Weekly Snap: Load balancing with Cluster IP, PHP memory tracking with Memtrack, new ACKP SensorProbe & Pgpool 2

26 – 30 September bid summer farewell with load balancing and PHP tips, the arrival of a new AKCP sensor probe, and developments in the MySQL – PostgreSQL realm.
Bernd bemoaned recent news from Oracle of new extensions for MySQL Enterprise. As announced in the Oracle blog, a new Enterprise Scalability Extension will join the ranks of the Enterprise High Availability and Enterprise Security modules. This follows the trend to offer much needed extensions for large environments only to commercial users, which can alienate the MySQL user community into the arms of competitor software such as PostgreSQL.
Sebastian continued on this thread to look at PostgreSQL replication with Pgpool-II. A third party middleware between PGSQL client and server, Pgpool complements PostgreSQL’s streaming replication (as of version 9) by managing the failover between master and slave. Features include connection pooling, replication, load balancing, limit exceeding connections and parallel queries. More information can be found in both Pgpool 2 and PostgreSQL’s documentation.
Lennart then looked at load balancing on Linux minus the load balancer. With Cluster IP of Netfilter, extensive clusters with multiple nodes can be built by using a common IP address on all nodes. This way, all nodes can respond to the same address. To avoid confusion in ARP querying, Cluster IP uses a Multicast MAC for the cluster IP addresses, so that incoming packets are received by participating nodes. It also uses a hash to distinguish between source IPs or ports etc, ensuring that nodes only answer queries relevant to them.
Following on, Marius shared his tip for monitoring memory capacity in PHP. The PECL extension Memtrack, tracks PHP memory usage and assists in troubleshooting, by enabling deviations in the logs to be detected.
Last but not least, hardware man Martin announced the arrival of AKCP Sensor Probe 4 to our online store. The much awaited device comes with 4 sensor ports in an AKCP Sensor Probe 8-like casing, making it perfect for a 19 inch rack. The AKCP Sensor Probe 4 features Cat 5 sensor connection for many different sensors, simple installation and configuration, Icinga and Nagios plugins, SNMP Trap messaging, 100Mbit network connection and a web interface to send email alerts.