Warum dauert die MariaDB Rücksicherung so lange

OP #7703405
Lesenswert?

Hallo Leute,

Auf meinem NAS (DS220+ 12GB RAM) habe ich MariaDB 10.3.37 installiert. Ein Update der Version dürfen wir aufgrund einer Inkompatiblität mit einem anderen Programm nicht machen.

Das Arbeiten ist flott und auch eine Sicherung ist schnell erstellt.

AAABER: Will man die DB zurücksichern, dauert es gefühlt ewig. (DB Sicherungsdatei ungefähr 45 MB, Dauer ungefähr 1 Stunde)

Zurückgespielt wird mit folgendem Script:

1
BACKUPS=`find /volume1/Backups/CAO/Revert -name "MariaDBDump_*.gz"`
2
if ["$BACKUPS" -eq ""]
3
then echo "Keine Datei gefunden"; 
4
exit 1
5
fi
6
date "+Uhrzeit Beginn:%H:%M:%S"
7
gunzip < $BACKUPS | /volume1/@appstore/MariaDB10/usr/local/mariadb10/bin/mysql -uroot -p'KurzPfurtz017OPk!'
8
rm $BACKUPS
9
date "+Uhrzeit Ende:%H:%M:%S"
10
exit 0

Im Anhang die my.cnf vom NAS. (In den anderen ist nichts ausser dem Port drinnen)

Was läuft da falsch?

Angehängte Dateien:
#7703411
Lesenswert?

Ate E. schrieb:

Will man die DB zurücksichern, dauert es gefühlt ewig. (DB Sicherungsdatei ungefähr 45 MB, Dauer ungefähr 1 Stunde)

Das kann auch 3 Tage dauern, wenn die DB etwas grösser ist, trotz SSDs als Platz für die Tablespaces. Und bei HDDs ist es naturgemäss weitaus langsamer als bei SSDs.

Dieser Backup ist allerdings ein SQL Dump, weshalb der Inhalt als SQL Kommandos eingelesen wird. Das ist der besste Weg, um Inkonsistenzen aus dem Weg zu gehen, aber mitnichten der schnellste Weg, Backups einzulesen.

#7703413
Lesenswert?

Mit SSD als Ziel. SQL auszuführen braucht halt Zeit und wenn du nur SQL als Backup hast, wirds nicht schneller.

Wenn du diese Situation vermeiden willst, solltest du eine Form des Backups verwenden, die nicht auf mysqldump basiert, sondern die Tablespaces kopiert. Das ist allerdings etwas von der Version abhängig, und ob MySQL oder MariaDB.

(Firma: egal) #7703414
Lesenswert?

Lu schrieb:

wenn man jeden Datensatz einzeln bearbeiten muß.

Das ist hier genau die Frage, wie sehen deine gesicherten Daten aus? Jedes SQL-Kommando einzeln und nicht im Blockmodus? Wird ein etwaiger index zuvor ausgeschaltet und erst wenn alle Daten vollständig sind neu erzeugt? Von wievielten Datensätzen wir hier überhaupt geredet?

Ich kenn es eher von mysqldump, da gibt es zig Optionen, die zum Teil erhebliche Auswirkung auf die Dauer haben können:

#7703750
Lesenswert?

aus deiner my.cnf:

1
innodb_buffer_pool_size = 16M
2
innodb_log_file_size = 2M
3
innodb_log_buffer_size = 1024M

das ist ja wohl vollkommen für den Arsch. Welcher Hirntote hat das konfiguriert?

Der InnoDB Buffer Pool ist der in-Memory Buffer für jegliche InnoDB Tabellen. Immer wenn etwas von einer InnoDB Tabelle gelesen wird, wird die entsprechende Page von der Platte in diesen Buffer gelesen und bleibt dort bis der Platz für eine andere Page gebraucht wird. Dito beim Schreiben: die Page wird von der Festplatte in den Buffer geladen und dort modifiziert. Dann bleibt sie solange wie möglich im Buffer, damit nicht ein Update von ein paar Bytes die ganze Page (16KB!) wegschreiben muß (das Phänomen nennt sich write-amplification). In deinen InnoDB Buffer Pool passen gerade mal 1000 Pages. Das ist lächerlich wenig wenn du 12G RAM hast.

Das InnoDB Logfile (redo Log, write ahead log) wird bei jedem Page-Update geschrieben. Allerdings ohne write-amplification. Durch die begrenzte Größe wird aber irgendwann (mit deiner Konfiguration nach 2x 2MB an Schreibzugriffen) die älteste Transaktion im Log überschrieben. Und spätestens dann muß die Page, auf der diese Transaktion stattgefunden hat, auf die Platte geschrieben worden sein. Durch die lächerlich kleine Log-Größe zwingst du InnoDB dazu laufend Pages rauszuschreiben.

Schließlich der Log Buffer. Der puffert Schreibzugriffe ins Log. Bei innodb_flush_log_at_trx_commit = 1 erzwingt jedoch jedes COMMIT (und bei auto-commit sogar jedes schreibende SQL-Statement) daß das Log geflushed wird. Den Log Buffer größer zu machen als das Log selber ist jedoch in jedem Fall absoluter Unsinn.

Vorschlag:

1
innodb_buffer_pool_size = 1G
2
innodb_log_file_size = 256M
3
innodb_log_buffer_size = 8M

Das ist zwar immer noch lächerlich wenig. Aber auch deine Datenbank ist mit gerade mal 45M (für den SQL-Dump!) lächerlich klein.

Die 45MB Dump sollten dann in wenigen 10s restored sein.

Ate E. schrieb:

Und wie kann ich den MySQL Dump am schnellsten wieder zurücklesen?

Indem du ihn nicht mit mysqldump erzeugst, sondern z.B. mit mydumper. Das erzeugt mehrere parallele Streams die dann parallel restored werden können (mit myloader). Brauchst du aber bei deiner winzigen Datenbank nicht.

#7703753
Lesenswert?

(prx) A. K. schrieb:

SQL auszuführen braucht halt Zeit und wenn du nur SQL als Backup hast, wirds nicht schneller.

45MB an SQL-Statements sind nicht die Welt. Das sollte auch ein schwächlicher Server in höchstens einer Minute schaffen.

Irgend W. schrieb:

Das ist hier genau die Frage, wie sehen deine gesicherten Daten aus? Jedes SQL-Kommando einzeln und nicht im Blockmodus? Wird ein etwaiger index zuvor ausgeschaltet und erst wenn alle Daten vollständig sind neu erzeugt?

mysqldump (sowohl von MariaDB als auch von MySQL) erzeugt standardmäßig multi-row INSERTs und die Indizes werden erst erzeugt, wenn die Daten gelesen sind. Ich weiß aber nicht, ob der Dump von mysqldump erzeugt wird und nicht etwa von phpMyAdmin.

OP #7703806
Lesenswert?

Axel S. schrieb:

innodb_buffer_pool_size = 1G innodb_log_file_size = 256M innodb_log_buffer_size = 8M

Werde ich probieren!

Die meisten Tabellen sind aber MyISAM! (Siehe Anhang)

Hier nochmals das Script für das Backup:

1
#!/bin/bash
2
KEEP=56
3
BACKUPS=`find /volume1/Backups/hour -name "MariaDBDump_*.gz" | wc -l | sed 's/\ //g'`
4
while [ $BACKUPS -ge $KEEP ]
5
do
6
ls -tr1 /volume1/Backups/hour/MariaDBDump_*.gz | head -n 1 | xargs rm -f 
7
BACKUPS=`expr $BACKUPS - 1` 
8
done
9
DATE=`date +%Y_%m_%d__%H_%M`
10
rm -f /volume1/Backups/hour/.MariaDBDump_${DATE}.gz_INPROGRESS
11
/volume1/@appstore/MariaDB10/usr/local/mariadb10/bin/mysqldump --opt -uroot -p'KurzPfurtz017OPk!' --all-databases | gzip -c -9 > /volume1/Backups/hour/.MariaDBDump_${DATE}.gz_INPROGRESS
12
mv -f /volume1/Backups/hour/.MariaDBDump_${DATE}.gz_INPROGRESS /volume1/Backups/hour/MariaDBDump_${DATE}.gz
13
exit 0

Axel S. schrieb:

Indem du ihn nicht mit mysqldump erzeugst, sondern z.B. mit mydumper. Das erzeugt mehrere parallele Streams die dann parallel restored werden können (mit myloader). Brauchst du aber bei deiner winzigen Datenbank nicht.

Sehe ich mir näher an.

Angehängte Dateien:
OP #7703845
Lesenswert?

Alexander schrieb:

Wer hat das geschrieben? das PW im Klartext soll im Skript stehen?

Das Script läuft auf meinem NAS!

Axel S. schrieb:

Indem du ihn nicht mit mysqldump erzeugst, sondern z.B. mit mydumper. Das erzeugt mehrere parallele Streams die dann parallel restored werden können (mit myloader). Brauchst du aber bei deiner winzigen Datenbank nicht.

mydumper ist leider für meinen NAS nicht verfügbar.

Gast #7703862
Lesenswert?

Ate E. schrieb:

Und wie kann ich den MySQL Dump am schnellsten wieder zurücklesen?

Am schnellsten wäre, die Binärdateien im data Verzeichnis zu sichern und zurück zu spielen. Das dauert nur wenige Sekunden.

Aber du riskiert damit inkonsistente Daten, wenn die DB während dieser Zeit auf die Dateien zugreift. Unter Umständen lassen sie diese Inkonsistenzen nicht reparieren.

Außerdem musst du damit rechnen, dass solche binären Backups nicht auf Rechner mit anderer Architektur übertragbar sind - selbst wenn die Versionsnummer von MySQL dort die gleiche ist.

Falls du das trotzdem machen willst, stoppe den DB server Dienst vor dem backup/restore.

#7703959
Lesenswert?

Ate E. schrieb:

Axel S. schrieb:

innodb_buffer_pool_size = 1G innodb_log_file_size = 256M innodb_log_buffer_size = 8M

Werde ich probieren!

Die meisten Tabellen sind aber MyISAM!

Dann mußt du die key_buffer_size hochdrehen. Die ist mit 1M auch arg knapp bemessen. Ist ok für eine InnoDB-mostly Instanz, da sind nur die Privilege-Tabellen MyISAM. Ich würde mittelfristig aber eine Migration zu InnoDB empfehlen. Das hat besseres Caching (eben den Buffer Pool) und nicht wie MyISAM nur für Indizes (Key Buffer).

Summiere die Größe aller MYI Files. Dann hast du einen Anhaltspunkt wie groß du den Key Buffer machen solltest.

Wenn du (fast) keine InnoDB Tabellen hast, dann laß die Einstellungen auf den Defaults.

#7703972
Lesenswert?

Ate E. schrieb:

(prx) A. K. schrieb:

MariaDB wiederum hat "mariabackup".

Kannst mir eine Quelle für den Synology DS220+ nennen?

Google...

Was dir dann verrät, das es mariabackup als docker container gibt, wie man einen beliebigen Container von docker hub auf der Synology installiert, und wie man dann das alle konfigurieren muss.

Google ist schon ein wirklich tolles Tool. Das solltest du wirklich mal ausprobieren.

Oliver

#7703977
Lesenswert?

Nachtrag:

ich habe mir deine my.cnf nochmal genauer angesehen und da sind mehrere Dinge fraglich:

table_open_cache = 2000 table_definition_cache = 2000

Hast du wirklich derartig viele Tabellen? Eigentlich braucht man das nicht anzufassen, sondern kann sich auf die Automatik (abhängig von max_connections) verlassen.

max_allowed_packet = 100M

Das ist sehr viel. Und es fällt pro Connection an. Gibt es da einen Grund dafür?

read_buffer_size = 256K read_rnd_buffer_size = 256K

Muß man eingentlich nie setzten.

net_buffer_length = 100K

Dito. Und sowieso setzt man das besser auf Systemebene (net.core.rmem_max, net.core.wmem_max, mit sysctl). Ist aber nicht kriegsentscheidend.

thread_stack = 240K

Von dieser Einstellung läßt man immer die Finger.

tmp_table_size = 1G max_heap_table_size = 1G

Das ist ebenfallst sehr viel wenn man bedenkt, daß das Synology nur 12G RAM hat. Denn das Limit gilt pro Tabelle. Und für die Anzahl der Tabellen gibt es kein Limit.

performance_schema=ON

Wenn du das nicht nutzt, schalte es aus.

Schlußfolgerung: ich würde das alles auf Default lassen. Mit folgenden Ausnahmen:

(innodb_buffer_pool_size) key_buffer_size tmp_table_size max_heap_table_size

und die an den tatsächlichen Bedarf anpassen.

(Firma: Q3) #7706619
Lesenswert?

Beim Einlesen werden alle notwendigen Kommandos nacheinander ausgeführt, wie "create table ..." und dann fleißig "insert into ...".

Wenn die Datenbank Indices enthielt (werden gleich nach dem Ausführen von "create table" mit "create index ..." wieder angelegt), wird nach jedem "insert" eines Datensatzes der Index ergänzt. Index schreiben dauert immer lange ...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren