MariaDB

Bemerkung

Ein Server mit MariaDB 10.6+ (egal ob dediziert oder zusammen mit einer Applikation) sollte heute mit mindestens 4 GB RAM betrieben werden.

MariaDB ist ein multi-user, multi-threaded, binärkompatibler Fork der relationalen Datenbank MySQL. Da Oracle inzwischen die Markenrechte an MySQL hält, musste ein neuer Name gefunden werden - „MariaDB“ und die zugrundeliegende Storage-Engine namens „Aria“ gehen auf den Namen der jüngeren Tochter des ehemaligen MySQL-Hauptentwicklers zurück, der auch den Fork initiiert hat.

In Fedora ist MySQL Ende 2012 durch MariaDB ersetzt worden, in Folge dadurch auch in und seit RHEL 7. Das Wikipedia-Projekt hat sich unter der Haube im April 2013 von MySQL verabschiedet.

Bis MariaDB 5.5 heisst der Service noch mysql, danach mariadb. Wird ein MariaDB 5 auf MariaDB 10 aktualisiert, bleibt es aber bis einschliesslich 10.3 beim Service-Namen mysql.

Seit MariaDB 10.5 werden die Begriffe master und slave durch primary und replica ersetzt.

Abkürzungen
  • AI = Auto-Increment

  • BIN = Binary

  • G = Generated Always As ()

  • NN = NOT NULL

  • PK = Primary Key

  • UN = Unsigned

  • UQ = Unique

  • ZF = Zerofill

Es gibt inzwischen jede Menge Detail-Unterschiede zwischen MySQL und MariaDB. Eine winzige Auswahl aus dem Betrieb:

  • Die Unterschiede in den Default-Einstellungen (my.cnf, SHOW VARIABLES) sind gigantisch.

  • MariaDB 10 ist restriktiver.

  • String-Längenbeschränkungen: in v5 wurden längere Strings beim INSERT in die Tabelle einfach abgeschnitten, in v10 ergibt das einen Fehler.

  • Integer: in v5 war es möglich, leere Strings in ein Integer-Feld zu schreiben; in v10 führt das zu einem Fehler.

Installation & Konfiguration

Wir empfehlen die Installation direkt aus dem Hersteller-Repo und nicht aus den RHEL-Repos.

Repository Configuration Tool: https://downloads.mariadb.org/mariadb/repositories

VER=11.4

curl --silent --show-error --location --output mariadb_repo_setup https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
chmod +x mariadb_repo_setup
./mariadb_repo_setup --mariadb-server-version="mariadb-$VER"

dnf -y install MariaDB-server

systemctl enable --now mariadb

# optional
dnf -y install MariaDB-client MariaDB-backup
dnf -y install maxscale

Egal welche $VER für das Repo herangezogen wird: jede baseurl liefert neben $VER immer auch die aktuellste Version, die damit standardmässig installiert wird.

Tipp

Wer eine spezifische Version wie z.B. v 5.5 einsetzen muss, lässt sich mit dnf list MariaDB-server --show-duplicates zunächst anzeigen, welche Minor-Versionen verfügbar sind. Die Installation erfolgt dann per dnf -y install MariaDB-server-5.5.66.

WICHTIG: da hier eine spezifische, tiefere Version installiert wird, würde diese beim nächsten dnf update aktualisiert werden. Um das zu verhindern, muss die installierte Version per dnf -y install dnf-plugin-versionlock; dnf versionlock mariadb* gelockt werden.

Anschliessend kann man dem MariaDB-Standardbenutzer „root“ ein komplexes Passwort zuteilen sowie den Gast-Zugang und die zusätzlich installierte Datenbank „test“ löschen:

mariadb-secure-installation

Es erhöht die Sicherheit, die root-Benutzer nach der Installation umzubenennen - es sind bis zu vier, je nach dem, ob die Maschine über einen voll-qualifizierten Hostnamen verfügt oder nicht:

  • einen für den Zugang von ::1 (root@‘::1‘)

  • einen für den Zugang von 127.0.0.1 (root@‘127.0.0.1‘)

  • einen für den Zugang von hostname (root@‘hostname‘)

  • einen für den Zugang von hostname.fqdn (root@‘hostname.fqdn‘)

mariadb --user=root --password

Zugriff dann per

mariadb --user=root

root-Benutzer umbenennen - bis 10.3:

update mysql.user set user = 'mariadb-admin' where user = 'root';
flush privileges;
quit

Ab 10.4 ist mysql.user neu eine View, und das Verfahren hat sich geändert. Hier gilt:

rename user 'root'@'localhost' to 'mariadb-admin'@'localhost';

Wer möchte, dass man sich von jedem Rechner aus (Adresse: „%“, dem Wildcard in SQL) mit MariaDB und root-Rechten verbinden darf, fügt einen Benutzer (hier per GRANT-Statement) hinzu:

grant all privileges
    on *.*
    to 'mariadb-admin'@'%'
    identified by 'password'
    with grant option;
flush privileges;
quit

Wer selektiver vorgeht und beispielsweise nur Zugriffe aus dem 10.26.6er-Netz zulassen möchte, verwendet create user 'mariadb-admin'@'10.26.6.%' ....

Bemerkung

Wer auf einer Maschine den Kommandozeilen-Client mysql benötigt, installiert ihn mit dnf -y install mariadb (damit wird nicht der MariaDB-Server installiert). Der Client landet immer auf der Maschine, sobald man den MariaDB-Server installiert.

Konfigurationsdateien unterhalb von /etc/my.cnf.d werden erwartungsgemäss alphabetisch ausgewertet. Einstellungen in der /etc/my.cnf.d/mysettings.cnf werden also durch eine /etc/my.cnf.d/z_mysettings.cnf bei Bedarf überschrieben.

Passwort ändern - man beachte, dass „flush“ zuerst ausgeführt werden muss:

flush privileges;
alter user 'root'@'localhost' identified by 'myn3wp4ssw0rd';

Migration MariaDB > MariaDB

Umzug einer MariaDB-Installation von VMalt nach VMneu, ohne langwierigen SQL-Ex- und Import der Datenbanken, sondern durch Kopie der Datenverzeichnisse. Die Ziel-Maschine kann dabei auch eine neuere MariaDB-Version fahren (ein bereits installiertes MariaDB ist Voraussetzung); ein Downgrade dagegen funktioniert nicht.

Wo

Was

VMalt

dnf -y install rsync

VMalt

systemctl stop mariadb

VMneu

dnf -y install rsync

VMneu

systemctl stop mariadb

VMneu

mv /var/lib/mysql /var/lib/mysql.orig

VMneu

rsync --archive --progress --human-readable --rsync-path='sudo rsync' vmalt:/var/lib/mysql/ /var/lib/mysql/

VMneu

chown -R mysql:mysql /var/lib/mysql; restorecon -Fvr /var/lib/mysql; systemctl start mariadb (evtl. auftretende Fehler wegen nächstem Schritt zunächst ignorieren)

VMneu

mysql_upgrade --user=mariadb-admin --password (Passwort von VMalt verwenden)

VMneu

Meldungen wie error    : Table rebuild required fixen

VMneu

systemctl restart mariadb

Tipp

Wenn die importierte Datenbank keinen mariadb-admin-User hat, und das root-Passwort unbekannt ist, lässt sich der MariaDB-Server ohne User-Schicht wie folgt starten: sudo -u mysql mariadbd --skip-grant-tables&.

Migration MySQL > MariaDB

MariaDB 10.11 lässt sich ein originales /var/lib/mysql von MySQL 8 nicht unterschieben, MariaDB rennt dann in den Fehler InnoDB: Plugin initialization aborted with error Generic error. Hier kommt man also um einen logischen Dump z.B. per mydumper auf MySQL und anschliessendem Import in MariaDB nicht herum.

Wichtig: MySQL 8+ verwendet als Default-Collation utf8mb4_unicode_520_ci, die MariaDB unbekannt ist (Fehler: Connection 21 - ERROR 1273: Unknown collation: 'utf8mb4_0900_ai_ci'). Für MariaDB 10.10+ kann diese Collation vor dem Import durch uca1400_as_ci ersetzt werden:

sed -i "s/utf8mb4_0900_ai_ci/uca1400_as_ci/g" /backup/mysql-dump/*.sql

Upgrading

Ein Upgrade von beispielsweise MariaDB 10.2 direkt auf MariaDB 10.6 ist möglich. Das Upgrade-Prozedere wird hier anhand der aus den MariaDB-Repos installierten Datenbank beschrieben.

  • Backups aller Datenbanken anlegen.

  • Evtl. Konfiguration in /etc/my.cnf.d an die zukünftige Version anpassen.

  • Passwort des DBA bereithalten.

  • Auf die DB-bezogene Cronjobs deaktivieren.

  • MariaDB stoppen: systemctl stop mariadb

  • MariaDB deinstallieren: dnf remove MariaDB-server. Das Verzeichnis /var/lib/mysql bleibt dabei erhalten.

  • Die bisher verwendeten /etc/yum.repos.d/mariadb.repo-Dateien deaktivieren.

  • Repository-Datei unter /etc/yum.repos.d auf die neue Version anpassen.

  • dnf clean all

  • Aktuellere Version installieren: dnf install MariaDB-server

  • /etc/my.cnf bzw. /etc/my.cnf.d/* anpassen. Beispielsweise sollten alle Einstellungen entfernt werden, die nicht mehr unterstützt werden. Siehe dazu auch die Tabelle am Ende dieses Dokuments.

  • MariaDB starten: systemctl enable mariadb; systemctl start mariadb

  • Upgrade-Skript ausführen (sonst erhält man Fehler der Art Couldn't execute '...': Column count of mysql... is wrong. Expected 21, found 20. The table is probably corrupted (1805)): mysql_upgrade --user=mariadb-admin --password - es passt System-Tabellen so an, dass sie mit der neuen Version kompatibel sind, prüft darüber hinaus alle Tabellen auf Konsistenz und markiert sie als mit der neuen Version kompatibel.

  • MariaDB restarten: systemctl restart mariadb

Clients

Tipp

Verbinden über einen SSH-Tunnel: ssh -L 13306:localhost:3306 mariadb-host, Zugriff dann auf localhost:13306.

MySQL Workbench

Für die Administration von MySQL-Datenbanken eignet sich MySQL Workbench auf einer Admin-Workstation. Für MariaDB eignet sich das Tool Stand 2021-04 noch, jedoch nicht mehr in allen Bereichen, beispielsweise in der Benutzer-Administration. Die RPM-Pakete für die Yum-Repositories des Herstellers finden sich auf http://dev.mysql.com/downloads/repo/yum/.

Am Beispiel von Fedora Workstation:

VER=8.0.36-1.fc38
dnf -y install https://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-$VER.x86_64.rpm

Konfiguration liegt unter ~/.mysql/workbench.

Welche Berechtigungen stecken hinter den „Administrative Roles“?

  • MaintenanceAdmin: Event, Reload, Show_db, Shutdown, Super

  • ProcessAdmin: Reload, Super

  • UserAdmin: Create_user, Reload

  • SecurityAdmin: Grant, Create_user, Reload, Show_db, User_manage_attr

  • MonitorAdmin: Process

  • DBManager: Create, Drop, Grant, Event, Alter, Delete, Index, Insert, Select, Update, Create_tmp_table, Lock_tables, Trigger, Create_view, Show_view, Create_routine, Alter_routine, Show_db

  • DBDesigner: Create, Alter, Index, Trigger, Create_view, Show_view, Create_routine, Alter_routine, Show_db, Routine_manage_attr

  • ReplicationAdmin: Repl_client, Repl_slave, Super

  • BackupAdmin: Event, Select, Lock_tables, Show_db

Backup und Restore

Physische Backups

Im Prinzip Sicherung des Datenverzeichnisses /var/lib/mysql. In der Regel schnell, aber nur auf der gleichen MariaDB-Version verwendbar.

Logische Backups

Es werden universelle SQL-Dateien (ASCII) geschrieben, die auch auf anderer Hardware, anderen MariaDB-Versionen oder (unter Umständen) auf anderen DB-Systemen zum Import verwendet werden können. Der Nachteil: das dauert, auch auf moderner Hardware.

mysql-Client

Der Dump - realistisch ungefähr 1 GB pro Minute. Wichtig zu wissen: die innodb_buffer_pool-Caches werden durch die beim Backup stattfindenden Full Table Scans zugemüllt, was folgende Statements verhindern:

# save the innodb_buffer_pool
$MYSQL --host=$HOST --user=$USER --password=$PASSWORD --execute='SET GLOBAL innodb_buffer_pool_dump_now = ON;'

# do the backup
# for example with mydumper or mysqldump

# restore the innodb_buffer_pool
$MYSQL --host=$HOST --user=$USER --password=$PASSWORD --execute='SET GLOBAL innodb_buffer_pool_load_now = ON;'

Tipp

Angaben im SQL-Dump der Form /*!40014 SET ... */; sind Conditional Comments. Im Beispiel wird SET ... nur auf einem MySQL 4.0.14 oder später ausgeführt.

Für globale Locks ist mindestens das RELOAD-Privileg nötig.

Der Restore mit dem Kommandozeilen-Client - realistisch ungefähr 200 MB pro Minute:

mariadb --user=root --password mydb < mydb.sql

Fortschrittsanzeige mit Hilfe des „pipe viewers“:

dnf -y install pv
pv mydb.sql | mariadb --user=root --password mydb

Import dauert ewig? Ein schnellerer Restore, der einige Checks abschaltet und damit um Faktoren beschleunigt abläuft, geschieht mittels:

SET autocommit=0;
SET unique_checks=0;
SET foreign_key_checks=0;

here comes the backup_file.sql

COMMIT;

Um SQL-Dumps im GB-Bereich zu bearbeiten, empfiehlt sich hexedit: mit Tab auf die rechte ASCII-Seite wechseln, mit Space den Anfang der Datei bis zu den ersten SQL-Anweisungen überschreiben, und anschliessend obige Statements einfügen. F2 speichert den Dump.

mydumper und myloader

Siehe https://github.com/mydumper/mydumper.

Geht durch Threading etwas schneller zu Werke als mysqldump. Von uns empfohlen.

mydumper kann die User-Credentials aus der ~/.my.cnf, einer cnf-Datei aus /etc/my.cnf.d, Sektion [client], oder einer beliebigen Datei, die per --defaults-files=/path/to/file referenziert wird, verwenden:

[client]
user=mydumper_user
password=mydumper_s3cr3t_pass
mydumper

Installation

VER=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/mydumper/mydumper/releases/latest | cut -d'/' -f8)

# RHEL 9:
dnf -y install https://github.com/mydumper/mydumper/releases/download/v$VER/mydumper-$VER.el9.x86_64.rpm

# RHEL 8:
dnf -y install compat-openssl10
dnf -y install https://github.com/mydumper/mydumper/releases/download/v$VER/mydumper-$VER.el8.x86_64.rpm

Full-Backup / Full-Dump:

HOST=localhost
USERNAME=root
PASSWORD=linuxfabrik
BACKUP_DIR=/backup
THREADS=0

# most used variant, all databases:
mydumper --host=$HOST --user=$USER --password=$PASSWORD \
    --compress \
    --outputdir=$BACKUP_DIR

# with more options:
mydumper --host=$HOST --user=$USER --password=$PASSWORD \
    --build-empty-files \
    --events \
    --logfile=$BACKUP_DIR/mydumper.log \
    --outputdir=$BACKUP_DIR \
    --routines \
    --threads=$THREADS \
    --triggers \
    --verbose=3
  • Wird --database weggelassen, werden alle Datenbanken gedumpt.

  • --logfile $BACKUP_DIR/mydumper.log wird bei jedem Run überschrieben.

  • --outputdir $BACKUP_DIR verhindert das Erzeugen von Verzeichnissen der Art export-20201027-145722.

  • --database wählt bei Bedarf die zu exportierende Datenbank aus.

  • --threads=0 wählt die Anzahl der Threads automatisch (erzeugt pro Core einen Thread, mindestens aber zwei). „0“ wird erst in neueren mydumper-Versionen unterstützt, und erzeugt sonst eine „floating point exception“. Default ist „4“.

Tipp

Ein Dump-Benutzer benötigt die Rechte event, execute, lock_tables, process, reload, select, show databases, show view, super, trigger. Werden beispielsweise Views oder Trigger nicht exportiert, sollten die Berechtigungen des Dump-Users überprüft werden. execute braucht es für gewisse Tabellen in der sys-DB.

myloader

Restore: Full-Backup wiederherstellen (bereits existierende und nicht im Backup enthaltene Datenbanken bleiben dabei natürlich unangetastet):

HOST=localhost
USERNAME=root
BACKUP_DIR=/backup
THREADS=0

myloader --host=$HOST --user=$USER --ask-password \
    --directory=$BACKUP_DIR \
    --overwrite-tables \
    --threads=$THREADS \
    --verbose=3

Einzelne Datenbank(en) wiederherstellen (und dabei neu benennen):

HOST=localhost
USERNAME=root
BACKUP_DIR=/backup
NEW_NAME_OF_DB=restored-nextcloud
DB_TO_RESTORE=nextcloud
THREADS=0

myloader --host=$HOST --user=$USER --ask-password \
    --directory=$BACKUP_DIR \
    --database=$NEW_NAME_OF_DB \
    --overwrite-tables \
    --queries-per-transaction=1000 \
    --source-db=$DB_TO_RESTORE \
    --threads=$THREADS \
    --verbose=3
  • --enable-binlog steht standardmässig auf False.

  • --overwrite-tables = DROP TABLE IF EXISTS, im Standard abgeschaltet. Backup-User benötigt sonst DROP-Rechte.

Der Restore muss mit einem Benutzer durchgeführt werden, der ausreichend Rechte zum Anlegen von Tabellen etc. besitzt. Falls in eine neue Datenbank wiederhergestellt werden soll, muss diese bereits angelegt sein. Falls der Restore Meldungen der Form ** (myloader:4191): CRITICAL **: 11:42:06.213: Error restoring db.table from file db.table-schema-view.sql.gz: Table 'db.other_table' doesn't exist bringt, einfach den Import erneut laufen lassen (da dann die vermissten Tabellen mit ziemlicher Sicherheit vorhanden sind).

Der Restore einzelner Tabellen gestaltet sich simpel, da diese als SQL-Datei vorliegen.

mysqldump, mariadb-dump

mysqldump erzeugt logische Dumps.

Full-Backup / Full-Dump:

   mysqldump --host=$HOST --port=3306 --user=$USER --password=$PASSWORD \
       --create-options \
       --default-character-set=utf8 \
       --events \
       --routines \
       --single-transaction=TRUE \
       --skip-dump-date \
       --skip-extended-insert \
       --triggers \
       --all-databases > /path/to/backup.sql

Um einen Dump von Server A auf Server B zu bekommen, dieses auf Server B ausführen:
mysqldump --host=server_a --user=root --password --single-transaction --flush-logs --hex-blob --source-data=2 --routines --all-databases | mysql
# --source-data causes the binary log position and filename to be appended to the output.
# If equal to 1, will print it as a CHANGE MASTER command.
# If equal to 2, that command will be prefixed with a comment symbol.

Ein DB-für-DB Backup-Script auf Basis von mysqldump:

echo Starting the logical backup...

if command -v zstd &>/dev/null
then
    PACKER=zstd
    EXTENSION=zst
else
    PACKER='gzip --fast'
    EXTENSION=gz
fi

# We do NOT lock the database by "BACKUP STAGE START; BACKUP STAGE BLOCK_COMMIT; DO SLEEP(very_long);"
# or similar, because it is too dangerous to run into a deadlock situation
# (client writes to a locked DB, and both client and the backup are blocked until the end of the sleep,
# and the backup is still not consistent after the end of the sleep).
# Instead, we use --single-transaction again. So, use the logical backup with care and don't expect
# it to be consistent (foreign keys etc.).

\rm -rf $BACKUP_DIR_LOGICAL
mkdir -p $BACKUP_DIR_LOGICAL

# go through all databases
echo Dumping...
for DB in $DBS
do
    if [ "$DB" == 'performance_schema' ]
    then
        continue
    fi

    CHARSET=$($MYSQL --host=$HOST --user=$USER --password=$PASSWORD \
            $DB --execute='SELECT @@character_set_database;' | \
            $AWK '{ print $1}' | $GREP -v '^@@character_set_database')

    # go through all tables in database
    TABLES=$($MYSQL --host=$HOST --user=$USER --password=$PASSWORD \
        --execute='show tables;' $DB | \
        $AWK '{ print $1}' | $GREP -v '^Tables' )
    for TABLE in $TABLES
    do
        if [ "$DB" == 'mysql' ]
        then
            if [ $TABLE == 'general_log' ]
            then
                continue
            fi
            if [ $TABLE == 'slow_log' ]
            then
                continue
            fi
            if [ $TABLE == 'transaction_registry' ]
            then
                continue
            fi
        fi

        $MYSQLDUMP --host=$HOST --user=$USER --password=$PASSWORD \
            --create-options \
            --default-character-set=$CHARSET \
            --routines \
            --single-transaction \
            --skip-dump-date \
            --skip-extended-insert \
            --triggers \
            $DB $TABLE | $PACKER > $BACKUP_DIR_LOGICAL/$DB.$TABLE.sql.$EXTENSION
        if [ $? -ne 0 ]
        then
            echo "Error dumping $DB.$TABLE" >&2
        else
            echo "$DB.$TABLE dumped"
        fi
    done
done

echo Done.

Mariabackup

Ab Version 10.1.23 kann das ursprünglich von Percona XtraBackup 2.3.8 geforkte Mariabackup verwendet werden, um InnoDB und XtraDB zu sichern. Unter InnoDB sind „hot online“-Backups möglich.

Wem es auf Performance ankommt: Unserer Erfahrung nach ist das Tool für ein erstmaliges Full Backup (und damit auch für die Einrichtung einer Replikation) nicht schneller als mysqldump oder mariadbdump, im Gegenteil - es ist nochmal langsamer, da es sich unter anderem ausgiebig mit den InnoDB redo logs beschäftigt, siehe Output weiter unten.

Full Backup erzeugen:

Siehe https://mariadb.com/kb/en/full-backup-and-restore-with-mariabackup/

rm -rf /backup/mariadb-dump/*
mariabackup --host=$HOST --user=$USER --password=$PASSWORD \
    --backup \
    --target-dir=/backup/mariadb-dump/full

Der Output:

[00] 2020-10-19 15:20:37 Connecting to MySQL server host: localhost, user: mariadb-admin, password: set, port: not set, socket: not set
[00] 2020-10-19 15:20:37 Using server version 10.5.6-MariaDB-log
mariabackup based on MariaDB server 10.5.6-MariaDB Linux (x86_64)
[00] 2020-10-19 15:20:37 uses posix_fadvise().
[00] 2020-10-19 15:20:37 cd to /var/lib/mysql/
[00] 2020-10-19 15:20:37 open files limit requested 0, set to 1024
[00] 2020-10-19 15:20:37 mariabackup: using the following InnoDB configuration:
[00] 2020-10-19 15:20:37 innodb_data_home_dir =
[00] 2020-10-19 15:20:37 innodb_data_file_path = ibdata1:12M:autoextend
[00] 2020-10-19 15:20:37 innodb_log_group_home_dir = ./
[00] 2020-10-19 15:20:37 InnoDB: Using Linux native AIO
2020-10-19 15:20:37 0 [Note] InnoDB: Number of pools: 1
[00] 2020-10-19 15:20:37 mariabackup: Generating a list of tablespaces
2020-10-19 15:20:37 0 [Warning] InnoDB: Allocated tablespace ID 2727 for mysql/innodb_table_stats, old maximum was 0
[00] 2020-10-19 15:20:40 >> log scanned up to (31993329429)
[01] 2020-10-19 15:20:40 Copying ibdata1 to /backup/mariadb-dump/ibdata1
[00] 2020-10-19 15:20:41 >> log scanned up to (31993329705)
[00] 2020-10-19 15:20:42 >> log scanned up to (31993329722)
...
[00] 2020-10-19 15:20:50 >> log scanned up to (31993330151)
[00] 2020-10-19 15:20:51 >> log scanned up to (31993330151)
2020-10-19 15:20:52 0 [Note] InnoDB: Read redo log up to LSN=31993330688
[00] 2020-10-19 15:20:52 >> log scanned up to (31993330444)
[00] 2020-10-19 15:20:53 >> log scanned up to (31993330444)
...
[00] 2020-10-19 15:20:59 >> log scanned up to (31993330865)
[00] 2020-10-19 15:21:00 >> log scanned up to (31993330929)
[01] 2020-10-19 15:21:01         ...done
[01] 2020-10-19 15:21:01 Copying ./mysql/innodb_table_stats.ibd to /backup/mariadb-dump/mysql/innodb_table_stats.ibd
[01] 2020-10-19 15:21:01         ...done
...

Full Backup wiederherstellen:

mkdir /backup/mariadb-dump/temp
cd /backup/mariadb-dump/temp
tar --use-compress-program zstd -xvf ../full/server.tar.zst

# make the full backup to be point-in-time consistent:
mariabackup --prepare --target-dir=/backup/mariadb-dump/temp

systemctl stop mariadb
rm -rf /var/lib/mysql/*
mariabackup --copy-back --target-dir=/backup/mariadb-dump/full
chown -R mysql:mysql /var/lib/mysql/
restorecon -Fvr /var/lib/mysql/
systemctl start mariadb

Einzelne DB aus einem Full Backup wiederherstellen:

Siehe https://mariadb.com/resources/blog/how-to-restore-a-single-database-from-mariadb-backup/

mkdir /backup/mariadb-dump/temp
cd /backup/mariadb-dump/temp
tar --use-compress-program zstd -xvf ../full/server.tar.zst
mariabackup --prepare --export --target-dir=/backup/mariadb-dump/temp --databases $DB
  • Optional Datenbank manuell erzeugen: CREATE DATABASE ...

  • Tabelle identisch zum Original manuell erzeugen, jedoch OHNE Constraints: CREATE TABLE ...

  • Tablespace löschen: ALTER TABLE ... DISCARD TABLESPACE;

  • Backup zurückkopieren:

    \cp /backup/mariadb-dump/temp/$DB/*.{ibd,cfg,frm} /var/lib/mysql/$DB/
    chown -R mysql:mysql /var/lib/mysql/
    restorecon -Fvr /var/lib/mysql/
    
  • Tablespace importieren: ALTER TABLE ... IMPORT TABLESPACE;

  • Constraints wiederherstellen: ALTER TABLE .... ADD CONSTRAINT ....

Partielle Backups (einzelne Datenbank sichern):

mariabackup --host=$HOST --user=$USER --password=$PASSWORD \
    --backup \
    --target-dir=$BACKUP_DIR_PARTIAL/datadir \
    --databases="$DB"

Eine einzelne Datenbank aus dem Full Backup wiederherstellen ist möglich, aber viel zu kompliziert. Wir setzen hier auf logische Backups.

Inkrementelle Backups:

columnstoreBackup

Aus dem MariaDB ColumnStore Tools Paket. Wird verwendet, um ColumnStore-Tabellen zu sichern.

Siehe https://mariadb.com/kb/en/backup-and-restore-for-mariadb-columnstore-110-onwards/

Umgang mit MariaDB

/var/lib/mysql initialisieren

systemctl stop mariadb
rm -rf /var/lib/mysql
mkdir -p /var/lib/mysql/mysql
chown -R mysql:mysql /var/lib/mysql
restorecon -r /var/lib/mysql

mysql_install_db --user=mysql \
     --basedir=/usr \
     --datadir=/var/lib/mysql
systemctl start mariadb
mysql_secure_installation

Benutzer

Der initiale DBA im System heisst root bzw. genauer root@localhost. Einen root@127.0.0.1 gibt es nicht.

Benutzer auflisten / list users / show users:

# MariaDB 10.5+
select * from mysql.global_priv;

# earlier versions:
select user, host, grant_priv from mysql.user;

Rechte eines Benutzers ermitteln:

show grants for 'user';

Benutzer erstellen und keinerlei brauchbare Rechte geben:

grant
    usage
    on *.*
    to 'user'@'host'
    identified by 'password';
flush privileges;

Benutzer mit SELECT-Rechten auf sämtliche Tabellen einer „accounting“-Datenbank anlegen:

grant
    select
    on accounting.*
    to 'user'@'host'
    identified by 'password';
flush privileges;

Benutzer mit minimalen Backup-Rechten auf eine DB anlegen, die auch Events, Triggers, Views etc. verwendet:

grant
    select, event, lock tables, process, reload, show view, super, trigger
    on *.*
    to 'user'@'host'
    identified by 'password';
flush privileges;

Benutzer mit minimalen Backup- UND Restore-Rechten anlegen (der Restore sollte nach Möglichkeit jedoch mit einem anderen, administrativen Account durchgeführt werden):

grant
    select, create view, drop, event, insert, lock tables, process, reload, show view, super, trigger
    on *.*
    to 'user'@'host'
    identified by 'password';
flush privileges;

Bemerkung

Werden zwei oder mehr Privilegien auf Datenbank und Tabellen angegeben, wird immer die spezifischere Regel angewendet. Beispiel:

database.table:ALTER
database.*:DELETE,SELECT

Damit darf der Benutzer DELETE und SELECT auf alle Tabellen in database ausführen, auf die Tabelle table allerdings nur ein ALTER. Soll der Benutzer auf table zusätzlich ALTER ausführen dürfen, müssen die Regeln wie folgt aussehen:

database.table:ALTER,DELETE,SELECT
database.*:DELETE,SELECT

Benutzer alle Berechtigungen entziehen:

revoke all privileges, grant option from 'user'@'host';

Passwort eines Benutzers ändern/zurücksetzen - man beachte, dass flush zuerst ausgeführt werden muss:

flush privileges;
set password for `user`@`host` = password('new-password');

Passwort des root-Benutzers zurücksetzen

Ab 10.4:

systemctl stop mariadb
cat > /etc/my.cnf.d/zzz-password-recovery.cnf << 'EOF'
[server]
skip_grant_tables = ON
skip_networking = 1
EOF
systemctl start mariadb

mariadb --user root
FLUSH PRIVILEGES;
SET PASSWORD FOR `mariadb-admin`@`%` = PASSWORD('new-password');
rm /etc/my.cnf.d/zzz-password-recovery.cnf
systemctl restart mariadb

Bash und MariaDB-Sessions

Einige SQL-Befehle verlangen, dass die Session für nachfolgende Befehle offen bleibt, z.B. FLUSH TABLES WITH READ LOCK - doch wie macht man das in einem Bash-Script? Der Trick ist, das Kommando auszuführen, genügend lange in SQL zu warten, das Konstrukt in den Hintergrund zu schicken, anschliessend seine Arbeit zu erledigen und am Ende den Hintergrundprozess zu killen:

echo Locking the database for max. 10 minutes by sleeping in background task...
$MYSQL --host=$HOST --user=$USER --password=$PASSWORD \
    --execute "BACKUP STAGE START; BACKUP STAGE BLOCK_COMMIT; DO SLEEP(600);" &
sleep 1

# do whatever you want to do

echo Finished, killing the previous background task to unlock.
kill $! 2>/dev/null
wait $! 2>/dev/null

Storage Engines

ColumnStore kann inzwischen ab Version 10.5.4 direkt als Storage Engine in MariaDB laufen, muss aber nach wie vor separat installiert werden.

ColumnStore

ColumnStore im Single-Node-Betrieb, ab Version 10.6+.

Siehe auch:

dnf -y install epel-release
dnf -y install jemalloc

curl --silent --show-error --location --output mariadb_repo_setup https://r.mariadb.com/downloads/mariadb_repo_setup
chmod +x mariadb_repo_setup
./mariadb_repo_setup --mariadb-server-version=11.4
/etc/sysctl.d/90-mariadb-columnstore.conf
# minimize swapping
vm.swappiness = 1

# Increase the TCP max buffer size
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# Increase the TCP buffer limits
# min, default, and max number of bytes to use
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# don't cache ssthresh from previous connection
net.ipv4.tcp_no_metrics_save = 1

# for 1 GigE, increase this to 2500
# for 10 GigE, increase this to 30000
net.core.netdev_max_backlog = 30000
sysctl --load=/etc/sysctl.d/90-mariadb-columnstore.conf

Character Encoding:

dnf -y install glibc-locale-source glibc-langpack-en
localedef --inputfile=en_US --charmap=UTF-8 en_US.UTF-8

MariaDB inklusive ColumnStore-Engine installieren:

dnf -y install MariaDB MariaDB-columnstore-engine MariaDB-columnstore-cmapi

Konfiguration:

/etc/my.cnf.d/z00-linuxfabrik.cnf
[server]
character_set_server = utf8
collation_server = utf8_general_ci
columnstore_use_import_for_batchinsert = ON
init_connect = 'SET NAMES utf8'
log_error = /var/log/mariadb/mariadb.log
max_allowed_packet = 4M
max_length_for_sort_data = 4M
systemctl enable --now mariadb
mariadb-secure-installation

Cross Engine Join-Benutzer in ColumnStore konfigurieren (falls Joins über ColumnStore und andere Datenbank-Engines benötigt werden):

mariadb \
    --user=$DBUSER \
    --password \
    --execute="CREATE USER 'cross_engine'@'127.0.0.1' IDENTIFIED BY 'linuxfabrik';"
mariadb \
    --user=$DBUSER \
    --password \
    --execute="CREATE USER 'cross_engine'@'localhost' IDENTIFIED BY 'linuxfabrik';"
mariadb \
    --user=$DBUSER \
    --password \
    --execute="GRANT SELECT, PROCESS ON *.* TO 'cross_engine'@'127.0.0.1';"
mariadb \
    --user=$DBUSER \
    --password \
    --execute="GRANT SELECT, PROCESS ON *.* TO 'cross_engine'@'localhost';"

mcsSetConfig CrossEngineSupport Host localhost
mcsSetConfig CrossEngineSupport Port 3306
mcsSetConfig CrossEngineSupport User cross_engine
mcsSetConfig CrossEngineSupport Password linuxfabrik

Neuen root-Benutzer anlegen, und alten root-Benutzer entfernen:

# new mariadb-admin
mariadb \
    --user=$DBUSER \
    --password \
    --execute="grant all privileges on *.* to 'mariadb-admin'@'localhost' identified by 'linuxfabrik' with grant option;"
mariadb \
    --user=$DBUSER \
    --password \
    --execute="grant all privileges on *.* to 'mariadb-admin'@'127.0.0.1' identified by 'linuxfabrik' with grant option;"
mariadb \
    --user=mariadb-admin \
    --password \
    --execute="drop user 'root'@'localhost' 'root'@'127.0.0.1';"

Settings:

/etc/columnstore/Columnstore.xml
<!-- better config -->
<VersionBuffer>
    <!-- VersionBufferFileSize must be a multiple of 8192.
    One version buffer file will be put on each DB root. -->
    <VersionBufferFileSize>4GB</VersionBufferFileSize>
</VersionBuffer>
<HashJoin>
    <AllowDiskBasedJoin>Y</AllowDiskBasedJoin>
</HashJoin>
systemctl unmask mariadb-columnstore.service
systemctl enable mariadb-columnstore
reboot

Ports für mcsimport:

  • 8616/tcp controllernode

  • 8630/tcp WriteEngineServ

  • 8800/tcp

Test:

 SHOW STATUS LIKE '%columnstore%';

 CREATE DATABASE IF NOT EXISTS lf_test;

 CREATE TABLE IF NOT EXISTS lf_test.contacts (
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    email VARCHAR(100)
 ) ENGINE=ColumnStore;

 INSERT INTO lf_test.contacts (first_name, last_name, email)
    VALUES
    ("Kai", "Devi", "kai.devi@example.com"),
    ("Lee", "Wang", "lee.wang@example.com");

SELECT * FROM lf_test.contacts;

# Test the Cross Engine Join

 CREATE TABLE lf_test.addresses (
    email VARCHAR(100),
    street_address VARCHAR(255),
    city VARCHAR(100),
    state_code VARCHAR(2)
 ) ENGINE = InnoDB;

 INSERT INTO lf_test.addresses (email, street_address, city, state_code)
    VALUES
    ("kai.devi@example.com", "1660 Amphibious Blvd.", "Redwood City", "CA"),
    ("lee.wang@example.com", "32620 Little Blvd", "Redwood City", "CA");

 SELECT name AS "Name", addr AS "Address"
 FROM (SELECT CONCAT(first_name, " ", last_name) AS name,
    email FROM lf_test.contacts) AS contacts
 INNER JOIN (SELECT CONCAT(street_address, ", ", city, ", ", state_code) AS addr,
    email FROM lf_test.addresses) AS addr
 WHERE  contacts.email = addr.email;

 DROP DATABASE lf_test;

Restart ColumnStore:

systemctl restart mariadb-columnstore.service

Tipp

ERROR 1815 (HY000) at line 1: Internal error: CAL0009: Truncate table failed:  MCS-2009: Unable to perform the cpimport operation because 4176 with PID -1 is currently holding the table lock for session .

viewtablelock
cleartablelock <LockID>

ColumnStore bis 1.2.5

Hier auf RHEL 7:

/etc/sysctl.d/90-mariadb-columnstore.conf
# minimize swapping
vm.swappiness = 1

# Increase the TCP max buffer size
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# Increase the TCP buffer limits
# min, default, and max number of bytes to use
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# don't cache ssthresh from previous connection
net.ipv4.tcp_no_metrics_save = 1

# for 1 GigE, increase this to 2500
# for 10 GigE, increase this to 30000
net.core.netdev_max_backlog = 30000
sysctl --load=/etc/sysctl.d/90-mariadb-columnstore.conf

Während der Installation SELinux auf Permissive setzen:

setenforce 0

Character Encoding:

localedef --inputfile=en_US --charmap=UTF-8 en_US.UTF-8

ColumnStore installieren:

dnf -y install boost
dnf -y install expect perl perl-DBI openssl zlib file sudo libaio rsync snappy net-tools numactl-libs nmap
wget https://downloads.mariadb.com/ColumnStore/1.2.5/centos/x86_64/7/mariadb-columnstore-1.2.5-1-centos7.x86_64.rpm.tar.gz
tar xvzf mariadb-columnstore-*-centos7.x86_64.rpm.tar.gz
dnf -y install mariadb-columnstore-*.rpm

/usr/local/mariadb/columnstore/bin/quick_installer_single_server.sh

source /etc/profile.d/columnstoreAlias.sh
/etc/logrotate.d/columnstore
#
# MariaDB ColumnStore Log Rotate file that gets installed in /etc/logrotate.d
# as part of the package installation
#

/var/log/mariadb/columnstore/*.log {
    missingok
    rotate 7
    daily
    dateext
    copytruncate
    olddir /var/log/mariadb/columnstore/archive
    su root root
}
#/usr/local/mariadb/columnstore/etc/Columnstore.xml {
#    daily
#    dateext
#   copy
#    olddir /usr/local/mariadb/columnstore/etc/
#}
/usr/local/mariadb/columnstore/mysql/db/*.err {
    missingok
    rotate 7
    daily
    dateext
    copytruncate
    olddir /usr/local/mariadb/columnstore/mysql/db
    su root root
}

Settings finden sich in zwei Dateien (empfohlene Einstellungen):

/usr/local/mariadb/columnstore/etc/Columnstore.xml
<!-- better config -->
<VersionBuffer>
    <!-- VersionBufferFileSize must be a multiple of 8192.
    One version buffer file will be put on each DB root. -->
    <VersionBufferFileSize>4GB</VersionBufferFileSize>
</VersionBuffer>
<DBBC>
    <NumBlocksPct>25</NumBlocksPct>
</DBBC>
<HashJoin>
    <TotalUmMemory>50%</TotalPmUmMemory>
    <AllowDiskBasedJoin>Y</AllowDiskBasedJoin>
</HashJoin>
/usr/local/mariadb/columnstore/mysql/my.cnf
[client]
...
default-character-set=utf8

[mysqld]
...
character-set-server = utf8
collation-server = uca1400_as_ci
init-connect = 'SET NAMES utf8'
max_allowed_packet = 4M
max_length_for_sort_data = 4M
/usr/local/mariadb/columnstore/bin/setConfig SystemConfig SystemLang en_US.utf8
mcsadmin restartSystem y

SELinux konfigurieren und aktivieren:

dnf -y install policycoreutils-python

grep mysqld /var/log/audit/audit.log | audit2allow -M mariadb_local
semodule -i mariadb_local.pp

setenforce 1

Start:

systemctl enable --now columnstore

Aufräumen:

/usr/local/mariadb/columnstore/mysql/bin/mysql_secure_installation

Benutzer anlegen auf ColumnStore im Single-Node-Betrieb, z.B. in MySQL Workbench:

/usr/local/mariadb/columnstore/mysql/bin/mysql --user root --password
# new mariadb-admin
grant all privileges on *.* to 'mariadb-admin'@'localhost' identified by 'linuxfabrik' with grant option;

Test:

CREATE DATABASE inventory;
CREATE TABLE inventory.products (
   product_name varchar(11) NOT NULL DEFAULT '',
   supplier varchar(128) NOT NULL DEFAULT '',
   quantity varchar(128) NOT NULL DEFAULT '',
   unit_cost varchar(128) NOT NULL DEFAULT ''
) ENGINE=Columnstore DEFAULT CHARSET=utf8;
DROP DATABASE inventory;

Siehe auch https://mariadb.com/docs/deploy/community-single-columnstore/.

Benutzer in ColumnStore anlegen:

mcsmysql -u root
# or in MySQL Workbench, for example
grant select on newuser.* to `newuser`@`localhost` identified by 'password';
grant create temporary tables on infinidb_vtable.* to `newuser`@`localhost`;
flush privileges;

SQL

Typen von SQL-Statements:

  • Data Manipulation Language (DML): SELECT, INSERT, UPDATE, DELETE, MERGE

  • Data Definition Language (DDL): CREATE, ALTER, DROP, RENAME, TRUNCATE, COMMENT

  • Data Control Language (DCL): GRANT, REVOKE

  • Transaction Control: COMMIT, ROLLBACK, SAVEPOINT

Test-Datenbanken

Die hier genannten Beispiel-Datenbanken werden teilweise auch für MySQL-Zertifizierungen und Schulungen verwendet.

Datenbank „employees“ (167 MB, inkl. gewünschter Inkonsistenzen):
git clone https://github.com/datacharmer/test_db.git
cd test_db/
mariadb --user=$DBUSER --password  < employees.sql

Datenbank-Tabelle „employees“ für Tests 4mal pro Sekunde laufend mit Daten füllen - ideal, um eine Ausgangsbasis für Backup- und Replikationstests zu haben:

for i in {1000000..2000000}; do
    echo $i
    mariadb --user=$DBUSER --password=$DBPASS \
        --execute="INSERT INTO \`employees\`.\`employees\` (\`emp_no\`, \`birth_date\`, \`first_name\`, \`last_name\`, \`gender\`, \`hire_date\`) VALUES ('$i', '2020-12-31', '$i', '$i', 'M', '2020-12-31');"
    sleep 0.25
done
Datenbank „world_x“
wget https://downloads.mysql.com/docs/world_x-db.tar.gz
tar xvzf world_x-db.tar.gz
mariadb --user=$DBUSER --password < world_x-db/world_x.sql
Datenbank „sakila“
wget https://downloads.mysql.com/docs/sakila-db.tar.gz
tar xvzf sakila-db.tar.gz
mariadb --user=$DBUSER --password < sakila-db/sakila-schema.sql
mariadb --user=$DBUSER --password < sakila-db/sakila-data.sql
Datenbank „menagerie“
  • Hilfe: nicht verfügbar

  • DB-Name: menagerie

wget https://downloads.mysql.com/docs/menagerie-db.tar.gz
tar xvzf menagerie-db.tar.gz
mariadb --user=$DBUSER --password --execute='create database menagerie;'
mariadb --user=$DBUSER --password menagerie < menagerie-db/cr_pet_tbl.sql
mysqlimport --user=$DBUSER --password --local menagerie menagerie-db/pet.txt
mariadb --user=$DBUSER --password menagerie < menagerie-db/ins_puff_rec.sql
mariadb --user=$DBUSER --password menagerie < menagerie-db/cr_event_tbl.sql
mysqlimport --user=$DBUSER --password --local menagerie menagerie-db/event.txt

Tabellen optimieren und reparieren

Achtung: das Kommando lockt die Tabellen, daher nur bei Bedarf und zu Randzeiten ausführen.

mysqlcheck --user=root --password=password --optimize --all-databases
mysqlcheck --user=root --password=password --repair   --all-databases

JSON in SQL

JSON-Text in Tabelle data beispielsweise {"email":{"value":"info@example.com"}}.

Passende SQL-Query:

select json_extract(data, '$.email.value') from ...

Cluster & Replikation

Das Standard-Replikationsszenario besteht aus einem Primary- und (mindestens) einem Replica-Server. Der MariaDB Galera Cluster ist ein Multi-Primary-Cluster.

Primary/Replica

Begriffe:

  • bis 10.4: Master und Slave

  • 10.5+: Primary und Replica

In diesem Standardszenario wird nur auf dem Primary geschrieben; Änderungen sind beinahe instant auf dem oder den Replica-Servern verfügbar. Die Replica können daher auch für reine Lese-Anforderungen eingesetzt werden. Die Replicas kommen (anders als früher) gut damit zurecht, wenn sie runtergefahren werden, auch wenn sich währenddessen auf dem Primary sowohl Schemata als auch Daten ändern.

Primary und Replica kommunizieren wenn nicht anders konfiguriert über Port 3306, also Firewall-Rules auf den beteiligten Hosts anpassen.

Achtung

Ein Replica übernimmt neben den Datenbanken auch die Benutzer-Accounts des Primary - also auch das Passwort für root, Backup-Benutzer und andere.

Siehe auch:

Auf dem Primary:

Binary Logging einschalten, das optimale Binary Logging Format (optional) und eine im Netz eindeutige Server-ID auf einen Wert zwischen 1 und 4294967295 setzen:

/etc/my.cnf.d/server.cnf
binlog_format = MIXED
log_bin = ON
server_id = 1

Jetzt einen Replikations-Benutzer mit Passwort und REPLICATION SLAVE-Berechtigung anlegen:

GRANT REPLICATION SLAVE ON *.* TO 'mariadb-replica'@'replica-host' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;

MariaDB-Server neu starten.

Auf dem Replica:

Im Netz eindeutige Server-ID vergeben:

/etc/my.cnf.d/server.cnf
server_id = 2

Replica-Server neu starten.

Tipp

Unsere Ansible-Rollen für den MariaDB-Server leisten die Installation bis zu obigem Punkt. Anschliessend ist Handarbeit angesagt.

Auf dem Primary:

Backup der Datenbanken beispielsweise mit mariadb-dump oder Mariabackup erzeugen und auf den Replica kopieren.

Um falsch ermittelten Binlog-Positionen und inkonsitenten Backups vorzubeugen, den Parameter --master-data verwenden. Dieser …

  • schaltet --lock-tables ab und --lock-all-tables an (solange --single-transaction nicht angegeben wird)

  • setzt also ein Read-Lock (FLUSH TABLES WITH READ LOCK)

  • ermittelt die aktuelle Position des Binary-Logs (sonst per SHOW MASTER STATUS; ermittelt) und schreibt diese in den Dump

  • gibt die DB nach dem Dump wieder frei (UNLOCK TABLES;)

# This sets a database read lock (due to --master-data)!
mysqldump --verbose --user=$DBUSER --password --master-data --opt --comments --hex-blob --dump-date --no-autocommit --flush-privileges --all-databases | gzip -1 > all-databases.sql.gz

scp all-databases.sql.gz ...
rm -f all-databases.sql.gz

Achtung

Wir hatten schon den Fall, dass mysqldump bei grossen Datenbanken (>= 100 GB) selbst mit --master-data keinen konsistenten/verwendbaren Dump erzeugen konnte, der als Import auf einem Replika funktioniert hätte. Stattdessen hat sich mariabackup --backup --user $USER --password $PASSWORD --target-dir /backup/mariadb-dump/physical/ bewährt.

Auf dem Replica:

Falls vorher schon mal importiert wurde, nicht vergessen, die Datenbanken auf dem Replika zu entfernen. Sonst einfach die Datenbanken importieren, zum Beispiel per

nice --adjustment 19 zcat all-databases.sql.gz | mariadb --user=$DBUSER --password
CHANGE MASTER TO
  MASTER_HOST='primary.domain.com',
  MASTER_USER='mariadb-replica',
  MASTER_PASSWORD='password',
  MASTER_PORT=3306,
  MASTER_CONNECT_RETRY=10,
  MASTER_USE_GTID = slave_pos;

Replica starten:

START SLAVE;

Replikation prüfen:

# prior to 10.5.1: SHOW SLAVE STATUS;
SHOW REPLICA STATUS;

Der Replica bzw. die Replikation funktioniert nur, wenn diese Werte zurückkommen:

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

Ein „Slave_SQL_Running=No“ heisst, dass die Replikation kaputt ist. Während Queueing master event to the relay log wird der Sync für die Replikation vorbereitet. Ein 'Waiting for master to send event' in der Spalte Slave_IO_State bedeutet lediglich, dass der Replica auf neue Inputs vom Primary wartet.

Auf dem Primary: tail -f /var/log/messages /var/lib/mysql/*.log

Auf dem Replica: tail -f /var/log/messages /var/lib/mysql/*.log

Falls auf dem Replica etwas falsch konfiguriert wurde, den Replica mit STOP SLAVE; stoppen (evtl. hilft noch ein RESET SLAVE;), mit CHANGE MASTER TO umkonfigurieren und per START SLAVE; wieder starten.

Binary-Logs aufräumen: Im Replika-Set werden auf dem Primary laufend die Binary-Logdateien in der Form /var/lib/mysql/ON.000001 usw. geschrieben. So räumt man diese auf, ohne die Replikation zu zerstören:

  • Auf dem Primary: SHOW BINARY LOGS;

  • Auf allen Replikas: SHOW REPLICA STATUS; (Inhalt der Spalte „Master_Log_File“ merken)

  • Das älteste von einem Replika verwendete Log-File muss erhalten bleiben, alle älteren davor können gelöscht werden.

  • alle Log-Dateien vor ‚ON.000063‘ löschen: PURGE BINARY LOGS TO 'ON.000063';

Galera

Galera ist ein „virtually synchronous multi-primary cluster supporting InnoDB storage engines“.

Begriffe:

  • IST: Incremental State Transfer

  • SST: State Snapshot Transfer

  • WSREP: Write Set Replication - eine Gruppe an zu schreibenden Änderungen

Firewall:

  • 3306: MySQL/MariaDB Standard Port und State-Snapshot-Übertragung mit mysqldump

  • 4567: Galera Replication Traffic (unicast). Falls Multicast-Replikation verwendet wird, wird sowohl TCP- als auch UDP-Transport auf diesem Port genutzt.

  • 4568: Galera Incremental State Transfer - IST. Wird nur bei Bedarf geöffnet.

  • 4444: State Snapshot Transfer - SST. Wird nur bei Bedarf geöffnet.

Installation auf dem ersten Node:

VER=11.4

curl --silent --show-error --location --output mariadb_repo_setup https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
chmod +x mariadb_repo_setup
./mariadb_repo_setup --mariadb-server-version="mariadb-$VER"

dnf -y install epel-release
dnf -y install MariaDB-server MariaDB-client galera-4 rsync

systemctl enable --now mariadb
mariadb-secure-installation

Konfiguration:

/etc/my.cnf.d/z00-linuxfabrik.cnf
[mariadb]
bind_address=0.0.0.0
binlog_format=ROW
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2  # ensure the InnoDB locking mode for generating auto-increment values is set to interleaved lock mode
innodb_doublewrite=1  # this is the default value, and should not be changed
innodb_flush_log_at_trx_commit=0  #  inconsistencies can always be fixed by recovering from another node

[galera]
wsrep_cluster_address="gcomm://<node1_IP>,<node2_IP>,<node3_IP>"  # DNS names work as well, IPs are preferred for performance
wsrep_cluster_name="my_galera_cluster"
wsrep_node_address=<my_IP>
wsrep_node_name=<my_hostname>
wsrep_on=ON  # enable wsrep replication
wsrep_provider=/usr/lib64/galera-4/libgalera_smm.so  # enable Plugin 'wsrep-provider'
wsrep_provider_options="gcache.size=300M; gcache.page_size=300M"
wsrep_slave_threads=4  # four slave threads can typically saturate a CPU core
wsrep_sst_method=rsync  # rsync SST method requires wsrep_cluster_address to be configured on startup

Nach der Installation und Konfiguration muss der erste Node bootstrapped werden:

galera_new_cluster

Cluster-Grösse prüfen (zu Beginn auf Node 1, später kann das auf jedem beliebigen Node ausgeführt werden):

mariadb --user=mariadb-admin --password --execute="SHOW STATUS LIKE 'wsrep_cluster_size';"

# wsrep_cluster_size | 1

Monitoring - Cluster-Zustand und -Werte überwachen:

mariadb --user=mariadb-admin --password --execute="SHOW GLOBAL STATUS LIKE 'wsrep_%';"

Weitere Nodes hinzufügen? Installation und Konfiguration auf jedem weiteren Node:

  • MariaDB installieren, starten und absichern

  • Konfigurationsdatei übernehmen und wsrep_node_address und wsrep_node_name anpassen

  • systemctl restart mariadb. Die neue Instanz wird versuchen, dem Cluster auf dem Ziel-Port 4567/tcp beizutreten, und wird selbst auf Port 4444/tcp per rsync einen SST anfordern. Der Sync kann dauern, daher Geduld und per journalctl -fu mariadb die Logs auf dem beitretenden Host beobachten.

  • Cluster-Grösse (auf irgendeinem der teilnehmenden Hosts) prüfen.

Bemerkung

Ein Node kann einfach ohne besondere Massnahmen jederzeit neu gestartet werden (inkl. Poweroff).

WSREP has not yet prepared node for application use: Tritt zum Beispiel auf, wenn sich n-1 von n Nodes nicht sauber aus dem Cluster abgemeldet haben (z.B. durch Poweroff). Praktisch ist dann der letzte verbliebene MariaDB-Node nutzlos und kann nicht mehr abgefragt werden. Besser als ein 3-Node-Setup ist daher ein 5-Node-Setup, aufgetrennt in zwei und drei Server pro Zone.

Cluster-Zustand prüfen:

mariadb --user=mariadb-admin --password --execute="SHOW STATUS LIKE 'wsrep%';"

#wsrep_cluster_size | should be 3
#wsrep_connected | should be ON
#wsrep_ready | should be ON

Zugriff auf den Cluster durch Clients:

  • Es spielt keine Rolle, auf welchen Node der Client zugreift - Schreibzugriffe werden nahezu in Echtzeit unter allen Nodes gesynct.

Cluster-Shutdown - geordnet:

  • Einen Node nach dem anderen herunterfahren. Den letzten Node merken - dieser muss später als erstes hochgefahren werden.

Cluster hochfahren - nach einem geordneten Shutdown:

  • Den zuletzt heruntergefahrenen Node zuerst starten und galera_new_cluster ausführen. Das (re-)startet auch ein (beim Startup failed) MariaDB. Clients können anschliessend mit diesem Node bereits produktiv arbeiten.

  • Die anderen Nodes (re-)starten. Diese treten automatisch dem Cluster bei.

Cluster hochfahren - aber MariaDB Startup failed? Cluster nach einem unerwarteten Ausfall hochfahren? Man weiss nicht mehr, welches der zuletzt aktive Node war? Die Nodes wurden in beliebiger Reihenfolge hochgefahren?

  • Der zuletzt aktive Node ist damit unbekannt, daher muss die „Global Transaction ID“ (GTID) auf jedem Node ermittelt und der Node mit der höchsten GTID / seqno zum Cluster-Manager promotet werden.

  • Ausserdem wird Galera höchstwahrscheinlich nicht starten, da es keinen Cluster formieren kann.

  • Daher auf jedem Node: cat /var/lib/mysql/grastate.dat

  • MariaDB auf dem Node mit safe_to_bootstrap: 1 per galera_new_cluster starten; die anderen Nodes mit systemctl restart mariadb aufnehmen.

  • Falls alle Nodes safe_to_bootstrap: 0 anzeigen, den mit der höchsten seqno wählen.

  • Falls alle Nodes seqno:   -1 anzeigen, irgendeinen wählen. In der Regel gab es dann einfach keine Schreiblast auf den einzelnen Nodes.

  • Auf dem ausgewählten Node: sed --in-place 's/safe_to_bootstrap: 0/safe_to_bootstrap: 1/' /var/lib/mysql/grastate.dat && galera_new_cluster; die anderen Nodes mit systemctl restart mariadb aufnehmen.

Load Balancing und Hochverfügbarkeit

Wie sollen Clients auf die Instanzen oder den Cluster zugreifen?

Möglichkeiten sind:

  • Round-Robin-DNS: Simpelster Ansatz, versagt aber bei Ausfall eines Datenbank-Nodes.

  • Keepalived: Nur Failover, ohne Load Balancing.

  • HAProxy: Simpel, bietet zunächst aber nur Failover. Load Balancing muss speziell implementiert werden, z.B. über Skripte, die bestimmte Parameter in MariaDB abfragen (und beispielsweise über einen Webserver laufen). HAProxy muss selbst aber redundant z.B. mit Hilfe von keepalived implementiert werden. Wer keine besonderen Anforderungen hat, ist damit gut bedient.

  • MaxScale: Read-/Write-Splitting, Query Rewrites etc. Direkt von MariaDB, kann aber aufgrund seiner Business Source License (BSL) nur in mehr als zwei Jahre alten Versionen frei in einem Community-Edition-Setup eingesetzt werden.

  • ProxySQL: Freie Alternative zu MaxScale, aber gewöhnungsbedürftig in der Konfiguration.

Security und Auditing

MariaDB Audit-Plugin

Grundsätzlich besteht der Zweck des MariaDB Audit Plugin darin, die Aktivitäten des Servers zu protokollieren. Für jede Client-Sitzung wird aufgezeichnet, wer sich mit dem Server verbunden hat (d.h. Benutzername und Host), welche Abfragen ausgeführt wurden, auf welche Tabellen zugegriffen wurde und welche Servervariablen geändert wurden. Diese Informationen werden in einer rotierenden Log-Datei gespeichert oder können an den lokalen syslogd gesendet werden.

Installation:

/etc/my.cnf.d/server.cnf
[mysqld]
plugin_load_add = server_audit

# Prohibiting Uninstallation:
server_audit = FORCE_PLUS_PERMANENT

server_audit_events = "CONNECT,QUERY,TABLE,QUERY_DDL,QUERY_DML,QUERY_DCL,QUERY_DML_NO_SELECT"
server_audit_excl_users =
server_audit_file_path = server_audit.log
server_audit_file_rotate_now = off
server_audit_file_rotate_size = 10M
server_audit_file_rotations = 9
server_audit_incl_users =
server_audit_logging = on
server_audit_output_type = file
server_audit_query_log_limit = 1024
server_audit_syslog_facility = LOG_USER
server_audit_syslog_ident = mysql-server_auditing
server_audit_syslog_info =
server_audit_syslog_priority = LOG_INFO

Anschliessend:

SHOW GLOBAL VARIABLES LIKE 'server_audit%';

Log-Datei findet sich mit obiger Konfiguration auf einem RHEL-basierten System unter /var/lib/mysql/server_audit.log. Beispiel für den Inhalt:

timestamp        ,server,username,host,ConnID,queryid,operation, database, object,             retcode
20211115 09:04:01,server,username,host,15,    35,     QUERY,     database, 'SET NAMES latin1', 0

Mehr Info hier: https://mariadb.com/kb/en/mariadb-audit-plugin/.

Tuning und Troubleshooting

Slow Query Log untersuchen

# summarize the output file and sort the output by rows affected or average rows affected
mariadb-dumpslow -s t log_file

mysqltuner

dnf -y install mysqltuner
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/basic_passwords.txt --output-document=basic_passwords.txt
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/vulnerabilities.csv --output-document=vulnerabilities.csv

mysqltuner --user mariadb-admin --pass mypass --passwordfile basic_passwords.txt --cvefile vulnerabilities.csv

MySQL sollte da schon 24h oder länger gelaufen sein.

Die Ausgaben bedeuten:

  • [--]: „Info Print“

  • [OK]: „Good Print“

  • [!!]: „Bad Print“

Beispielausgabe:

 >>  MySQLTuner 1.7.21 - Major Hayden <major@mhtx.net>
 >>  Bug reports, feature requests, and downloads at http://mysqltuner.pl/
 >>  Run with '--help' for additional options and output filtering

[--] Skipped version check for MySQLTuner script
[OK] Logged in using credentials passed on the command line
[OK] Currently running supported MySQL version 10.3.30-MariaDB
[OK] Operating on 64-bit architecture

-------- Log file Recommendations ------------------------------------------------------------------
[!!] Log file ./mariadb-error.log doesn't exist

-------- Storage Engine Statistics -----------------------------------------------------------------
[--] Status: +Aria +CSV +InnoDB +MEMORY +MRG_MyISAM +MyISAM +PERFORMANCE_SCHEMA +SEQUENCE
[--] Data in MyISAM tables: 10.5M (Tables: 4)
[--] Data in InnoDB tables: 1.5G (Tables: 906)
[!!] Total fragmented tables: 2

-------- Analysis Performance Metrics --------------------------------------------------------------
[--] innodb_stats_on_metadata: OFF
[OK] No stat updates during querying INFORMATION_SCHEMA.

-------- Security Recommendations ------------------------------------------------------------------
[OK] There are no anonymous accounts for any database users
[OK] All database users have passwords assigned
[!!] User ''root'@%' does not specify hostname restrictions.
[!!] There is no basic password file list!

-------- CVE Security Recommendations --------------------------------------------------------------
[--] Skipped due to --cvefile option undefined

-------- Performance Metrics -----------------------------------------------------------------------
[--] Up for: 1d 14h 48m 46s (48M q [343.594 qps], 192K conn, TX: 501G, RX: 7G)
[--] Reads / Writes: 95% / 5%
[--] Binary logging is disabled
[--] Physical Memory     : 7.6G
[--] Max MySQL memory    : 4.3G
[--] Other process memory: 0B
[--] Total buffers: 1.3G global + 19.7M per thread (151 max threads)
[--] P_S Max memory usage: 104M
[--] Galera GCache Max memory usage: 0B
[OK] Maximum reached memory usage: 1.7G (21.62% of installed RAM)
[OK] Maximum possible memory usage: 4.3G (56.06% of installed RAM)
[OK] Overall possible memory usage with other process is compatible with memory available
[OK] Slow queries: 0% (0/48M)
[OK] Highest usage of available connections: 9% (14/151)
[OK] Aborted connections: 0.00%  (1/192942)
[OK] Query cache is disabled by default due to mutex contention on multiprocessor machines.
[OK] Sorts requiring temporary tables: 0% (44 temp sorts / 10M sorts)
[!!] Joins performed without indexes: 2912
[!!] Temporary tables created on disk: 34% (272K on disk / 783K total)
[OK] Thread cache hit rate: 99% (14 created / 192K connections)
[OK] Table cache hit rate: 99% (1K open / 1K opened)
[!!] table_definition_cache(400) is lower than number of tables(1585)
[OK] Open file limit used: 0% (67/32K)
[OK] Table locks acquired immediately: 100% (5K immediate / 5K locks)

-------- Performance schema ------------------------------------------------------------------------
[--] Memory used by P_S: 104.0M
[--] Sys schema isn't installed.

-------- ThreadPool Metrics ------------------------------------------------------------------------
[--] ThreadPool stat is enabled.
[--] Thread Pool Size: 4 thread(s).
[--] Using default value is good enough for your version (10.3.30-MariaDB)

-------- MyISAM Metrics ----------------------------------------------------------------------------
[!!] Key buffer used: 18.3% (24M used / 134M cache)
[OK] Key buffer size / total MyISAM indexes: 128.0M/3.3M
[OK] Read Key buffer hit rate: 98.8% (1K cached / 21 reads)

-------- InnoDB Metrics ----------------------------------------------------------------------------
[--] InnoDB is enabled.
[--] InnoDB Thread Concurrency: 0
[OK] InnoDB File per table is activated
[!!] InnoDB buffer pool / data size: 1.0G/1.5G
[OK] Ratio InnoDB log file size / InnoDB Buffer pool size: 128.0M * 2/1.0G should be equal to 25%
[OK] InnoDB buffer pool instances: 1
[--] Number of InnoDB Buffer Pool Chunk : 8 for 1 Buffer Pool Instance(s)
[OK] Innodb_buffer_pool_size aligned with Innodb_buffer_pool_chunk_size & Innodb_buffer_pool_instances
[OK] InnoDB Read buffer efficiency: 100.00% (2181003656 hits/ 2181088118 total)
[!!] InnoDB Write Log efficiency: 75.7% (1591920 hits/ 2102867 total)
[OK] InnoDB log waits: 0.00% (0 waits / 510947 writes)

-------- Aria Metrics ------------------------------------------------------------------------------
[--] Aria Storage Engine is enabled.
[OK] Aria pagecache size / total Aria indexes: 128.0M/0B
[OK] Aria pagecache hit rate: 98.6% (18M cached / 264K reads)

-------- TokuDB Metrics ----------------------------------------------------------------------------
[--] TokuDB is disabled.

-------- XtraDB Metrics ----------------------------------------------------------------------------
[--] XtraDB is disabled.

-------- Galera Metrics ----------------------------------------------------------------------------
[--] Galera is disabled.

-------- Replication Metrics -----------------------------------------------------------------------
[--] Galera Synchronous replication: NO
[--] No replication slave(s) for this server.
[--] Binlog format: ROW
[--] XA support enabled: ON
[--] Semi synchronous replication Master: OFF
[--] Semi synchronous replication Slave: OFF
[--] This is a standalone server

-------- Recommendations ---------------------------------------------------------------------------
General recommendations:
    Run OPTIMIZE TABLE to defragment tables for better performance
      OPTIMIZE TABLE `mydb`.`http_error_log`; -- can free 100 MB
      OPTIMIZE TABLE `mydb`.`versions`; -- can free 5382 MB
    Total freed space after theses OPTIMIZE TABLE : 5482 Mb
    Restrict Host for 'root'@% to 'root'@LimitedIPRangeOrLocalhost
    RENAME USER 'root'@'%' TO 'root'@LimitedIPRangeOrLocalhost;
    We will suggest raising the 'join_buffer_size' until JOINs not using indexes are found.
             See https://dev.mysql.com/doc/internals/en/join-buffer-size.html
             (specially the conclusions at the bottom of the page).
    When making adjustments, make tmp_table_size/max_heap_table_size equal
    Reduce your SELECT DISTINCT queries which have no LIMIT clause
    Consider installing Sys schema from https://github.com/mysql/mysql-sys for MySQL
    Consider installing Sys schema from https://github.com/FromDual/mariadb-sys for MariaDB
Variables to adjust:
    join_buffer_size (> 1.0M, or always use indexes with JOINs)
    tmp_table_size (> 16M)
    max_heap_table_size (> 16M)
    table_definition_cache(400) > 1585 or -1 (autosizing if supported)
    innodb_buffer_pool_size (>= 1.5G) if possible.

Zu prüfende Einstellungen auf einem dedizierten MariaDB-System:

binlog_format = MIXED
innodb_buffer_pool_instances = 2
innodb_buffer_pool_size = 80% vom verfügbaren ("available") RAM
innodb_file_format = barracuda
innodb_file_per_table = on
innodb_io_capacity = 4000
innodb_large_prefix = on
innodb_log_file_size = 25% von innodb_buffer_pool_size / 2
innodb_stats_on_metadata = off
join_buffer_size = 1M
log_error = hostname.err
max_heap_table_size = 256M
performance_schema = on
query_cache_limit = 2M
query_cache_size = 0
query_cache_type = off
skip_name_resolve = on
thread_cache_size = 256
tmp_table_size = 256M

DARE - Data Encryption at Rest

DARE: Unbenutzte Daten („Data at rest“ = Daten im Ruhezustand) werden verschlüsselt auf der Disk abgelegt. Sowohl Backup-Tools als auch Replication funktionieren nach der Aktivierung daher wie gewohnt. Die Kommunikation mit dem Client muss anderweitig verschlüsselt werden.

Das „Eperi Key Management Plugin“ ist nicht mehr verfügbar, obwohl es in der Dokumentation wiederholt erwähnt wird.

Siehe auch:

File Key Management Plugin

Die Installation/Aktivierung des Plugins encrypted noch nichts - erst das Einschalten der Option innodb_encrypt_tables = ON führt dazu, dass alle neuen und existierenden Tabellen mit dem ersten Key verschlüsselt gespeichert werden.

Das Plugin unterstützt Keys mit einer Länge von 128, 192 und 256 Bit. Es unterstützt keine Key Roation, da es keinen Backend Key Management Service (KMS) verwendet.

Beispiel: Key-File mit drei Keys, bestehend aus Key Identifier, gefolgt von einem Semikolon und dem eigentlichen 256 Bit (32 Byte) Encryption Key erstellen, wobei die Key-Identifier bedeuten:

  • 1: Pflicht. Key zur Verschlüsselung von System-Daten wie Redo-Logs, Binary Logs usw.

  • 2: Optional. Key zur Verschlüsselung von temporären Daten. Fehlt dieser Identifier, wird der System-Key zur Verschlüsselung verwendet.

  • 3..n: Optional. Beliebiger Key-Identifier zur Verwendung in einem CREATE TABLE … ENCRYPTED=YES ENCRYPTION_KEY_ID=n;-Statement

(echo -n "1;" ; openssl rand -hex 32 ) | sudo tee --append /etc/my.cnf.d/keyfile
(echo -n "2;" ; openssl rand -hex 32 ) | sudo tee --append /etc/my.cnf.d/keyfile
(echo -n "100;" ; openssl rand -hex 32 ) | sudo tee --append /etc/my.cnf.d/keyfile

Einmalig ein Passwort für die Verschlüsselung des Key-Files anlegen (muss zwingend mittels „Cipher Block Chaining (CBC) mode of Advanced Encryption Standard (AES)“ geschehen):

# create a random 256 character encryption password (= max length)
sudo openssl rand -hex 128 > /etc/my.cnf.d/keyfile.key

Nach dem Hinzufügen beliebiger Keys das Keyfile veschlüsseln - das unverschlüsselte Keyfile kann danach vom Server an einen sicheren Ort verschoben werden, zum Beispiel in einen Passwort-Tresor:

# encrypt the key file
sudo openssl enc \
    -aes-256-cbc \
    -md sha1 \
    -pass file:/etc/my.cnf.d/keyfile.key \
    -in /etc/my.cnf.d/keyfile \
    -out /etc/my.cnf.d/keyfile.enc
# `WARNING : deprecated key derivation used` can be ignored in this use case

Bemerkung

Die Schlüssel werden nur beim Start des MariaDB-Daemons aus der Datei gelesen.

DARE auf dem MariaDB-Server aktivieren:

/etc/my.cnf.d/linuxfabrik.cnf
# File Key Management
plugin_load_add                                = file_key_management
loose_file_key_management_filename             = /etc/my.cnf.d/keyfile.enc
loose_file_key_management_filekey              = FILE:/etc/my.cnf.d/keyfile.key
loose_file_key_management_encryption_algorithm = AES_CTR

# Basic Encryption Configuration
encrypt_binlog                      = ON
encrypt_tmp_files                   = ON

# InnoDB Encryption
innodb_default_encryption_key_id    = 1
innodb_encrypt_log                  = ON
innodb_encrypt_tables               = ON
innodb_encrypt_temporary_tables     = ON
innodb_encryption_rotate_key_age    = 1
innodb_encryption_threads           = 4
sudo systemctl restart mariadb

Liste der verschlüsselten Tablespaces prüfen (verschlüsselt bedeutet ENCRYPTION_SCHEME != 0):

SELECT COUNT(*) AS "Number of Encrypted Tablespaces"
FROM information_schema.INNODB_TABLESPACES_ENCRYPTION

Achtung

Gehen Keys mit Identifier >= 3 verloren, mit dem einzelne Tabellen verschlüsselt wurden, dann sind diese nach einem Restart der Datenbank nicht mehr lesbar, und der Inhalt verloren (Error Code: 1877. Table `linuxfabrik`.`t` is corrupted. Please drop the table and recreate.).

Fehlende Keys mit Identifier 1 und 2 verhindern den Start des MariaDB-Daemons, zum Beispiel mit Meldungen wie Cannot decrypt [page id: space=0, page number=7] und Table is compressed or encrypted but uncompress or decrypt failed.

InnoDB-Encryption abschalten

Das einfache Abschalten der encrypt-Settings sowie des Plugins führt nicht dazu, dass verschlüsselt gespeicherte Daten entschlüsselt werden. Dafür muss man wie folgt vorgehen:

SET GLOBAL innodb_encrypt_tables = OFF;
SET GLOBAL innodb_encryption_threads = 4;
SET GLOBAL innodb_encryption_rotate_key_age = 1;

Individuell verschlüsselte Tabellen müssen manuell entschlüsselt werden:

SELECT TABLE_SCHEMA AS 'Database', TABLE_NAME AS 'Table'
FROM information_schema.TABLES
WHERE ENGINE = 'InnoDB' AND CREATE_OPTIONS LIKE '%`ENCRYPTED`=YES%';

Für jede Tabelle aus der obigen Liste:

ALTER TABLE my_table ENCRYPTED=NO;

Am Ende die Konfigurationsdatei überarbeiten und alle encrypt-Settings auf OFF stellen. plugin_load_add kann ebenfalls deaktiviert werden. Anschliessend ein systemctl restart mariadb durchführen.

Built on 2024-11-18