WhyInstalling a MariaDB server with replication done on a second host, encryption will be used to protect communications.
- Requirement: ZFS
- Reference: MariaDB documentation
- Follow-up: phpMyAdmin
Build information
Ensure the following options:
[x] AWS_KEY_MGMT AWS Encryption Key Management Plugin [ ] CONNECT_EXTRA Enable ODBC and XML in CONNECT engine [ ] DOCS Build and/or install documentation [x] HASHICORP_VAULT Enable HashiCorp vault key-storage plugin [x] WSREP Build wsrep clustering ( ) GSSAPI_BASE GSSAPI support via base system (needs Kerberos) ( ) GSSAPI_HEIMDAL GSSAPI support via security/heimdal ( ) GSSAPI_MIT GSSAPI support via security/krb5 (*) GSSAPI_NONE Disable GSSAPI support [x] LZO LZO compression support [ ] SNAPPY Snappy compression library support [ ] COLUMNSTORE Columnar storage engine [x] INNOBASE InnoDB default engine [x] MROONGA Mroonga Full Text Search engine [x] OQGRAPH Open Query Graph Computation engine [ ] ROCKSDB RocksDB LSM engine [ ] S3 S3 storage engine (Gamma) [x] SPHINX SphinxSE engine [x] SPIDER Partitioning and XA-transactions engine [x] VIDEX What-if analyses engine [ ] ZMQ ZeroMQ support [x] MSGPACK MsgPack support
- The commands on this page are the
mariadbones:mariadb,mariadb-admin,mariadb-dump,mariadbd. - The old
mysql-prefixed names still work, as symlinks — an existing script is not broken. - Everything that is an identifier rather than a program
keeps the
mysqlspelling: the[mysqld]configuration section, the schema namedmysql, themysqlaccount, the/var/db/mysqldata directory. Not branding — renaming them would break a working server.
Tuning
Tuning occurs principally in the server.cnf file in the mysqld
section. It is raised this early because some of these settings cannot
be changed once the server has been initialised.
ZFS
Adapt ZFS filesystem characteristics to have good performance with the selected storage engine.
The configuration proposed is for MariaDB using InnoDB as main storage engine
- with
innodb_file_per_table=ondata are created in$datadir/$db/$table - with ZFS
primarycachedisabled, it is vital to have recordsize matching MariaDB read
Due to 1+2 it is strongly advised to not create database/tables with a storage engine other than InnoDB if applying this configuration.
# Adapt to InnoDB storage engine zfs set atime=off system/services/mysql zfs set sync=disabled system/services/mysql zfs set primarycache=metadata system/services/mysql zfs set recordsize=16k system/services/mysql # Fallback to standard behaviour, but compress zfs set sync=standard system/services/mysql/logs zfs set primarycache=all system/services/mysql/logs zfs set recordsize=128k system/services/mysql/logs zfs set compress=lz4 system/services/mysql/logs # Ensure that newly created mountpoints have correct ownership chown -R mysql:mysql /var/db/mysql
This operation must be done before MariaDB starts for the first time or creates files, otherwise the block size used will be the one configured when the various files are created.
The logs dataset keeps sync=standard precisely
so the InnoDB redo log and the binary log can live there: with
sync=disabled on the data dataset, fsync is a no-op, and
durability options such as those of the Master
section would silently be ineffective. The redo log is relocated
accordingly (the binary log is placed there when configuring
replication):
innodb-log-group-home-dir = /var/db/mysql/logs
In MariaDB the double write will be disabled and file system directly accessed as ZFS with its copy-on-write policy provide the necessary warranties to avoid half written data in case of crash:
innodb-doublewrite = FALSE
SSL
Setting up SSL takes place in the client-server section of
the my.cnf configuration file if it is to be shared between
client and server; otherwise it can be put in the
dedicated section of the client.cnf and server.cnf files.
- Client side (without authenticating the client)
-
[client] ssl-ca = Chain of certificate authorities - Server side:
-
[mysqld] ssl-ca = Chain of certificate authorities ssl-cert = Server certificate ssl-key = Certificate key
To require SSL encryption for a particular user add REQUIRE SSL
to the GRANT, for example:
GRANT USAGE ON *.* TO 'user'@'hostname' REQUIRE SSL;
If an SSL certificate has been updated, it can be reloaded without interrupting the server:
FLUSH LOCAL SSL; -- using LOCAL so it is not propagated to the replicas
Replication
- Commands:
SHOW SLAVE STATUS,CHANGE MASTER TO mariadb-dump- https://mariadb.com/docs/server/ha-and-performance/standard-replication/multi-source-replication
- https://mariadb.com/docs/server/ha-and-performance/standard-replication/gtid
- https://mariadb.com/docs/server/ha-and-performance/standard-replication/replication-filters
- Replication can be incorrect with the use of
LIMITclauses inDELETE,UPDATE, andINSERT ... SELECTstatements ifORDER BYis not specified (See MariaDB documentation for details). - Servers, master or slaves, participating in the replication process need to be identified by a unique id set with the server-id directive.
Master
The master will be configured (in server.cnf) using these steps:
-
We specify the server unique id and the file to use for the log file (which is at the heart of replication), placed on the
logsdataset (see ZFS)server-id = Unique server identifier log-bin = /var/db/mysql/logs/mysql-binlog -
For a behavior more resistant to crashes (ACID), it is necessary to activate the following options, but it has a cost on performances:
innodb-flush-log-at-trx-commit = 1 sync-binlog = 1
-
The log file can grow indefinitely, so it is wise to limit its expansion, we will assume that slaves would have time to synchronize in a reasonable amount of time and only keep here the last 45 days. But if your database sustains heavy modification and you don’t have disk space you should reduce it to a few days:
expire-logs-days = 45
Checking master configuration and correct operations:
SHOW MASTER STATUS;
To setup the replication it is necessary to have an administrative
account with “replication” rights, we choose to name it
db-sync. We will consider that the backup server for our
slave (Replication server) is
not on the same network and will require an SSL connection to maintain
confidentiality:
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*
TO 'db-sync'@Replication server
IDENTIFIED BY Password REQUIRE SSL;
Slave
If for some reasons the mysql database used by MariaDB to hold
information about privileges, users and other internal data should not
be replicated, it is possible to exclude it (and other databases as
well if needed) by setting in server.cnf:
replicate-wild-ignore-table=mysql.% and restarting
mariadbd.
The slave configuration can be done entirely in the my.cnf file, but
in this case one need to be aware that future modification of the file
concerning master information will be ignored. This is why the
configuration will be split into two steps:
-
The configuration file
server.cnfspecifying the unique server id and a relay log file:server-id = Unique server identifier relay-log = relay-logThe
server-idvalue must be different for each server.
(Verify that the value for the master server hasn’t been reused) -
SQL configuration of the master information, we will setup an SSL connection without verification of the master certificate (such a verification can be done by changing value for the
MASTER_SSL_VERIFY_SERVER_CERT):CHANGE MASTER Connection name TO MASTER_HOST = Master host, MASTER_USER = "db-sync", MASTER_PASSWORD = Password, MASTER_USE_GTID = slave_pos, MASTER_HEARTBEAT_PERIOD = 30, MASTER_SSL = 1, MASTER_SSL_CA = Chain of certificate authorities, MASTER_SSL_VERIFY_SERVER_CERT = 0;
- The
MASTER_SSL_CAfile must contain the complete certificate chain.
If it holds only an intermediate certificate, the I/O thread fails with the opaque message:
SSL connection error: error:00000000:lib(0)::reason(0). - A CA path is only exercised when
MASTER_SSL = 1.
- The
Checking slave configuration and correct operations:
SHOW ALL SLAVES STATUS\G -- Show status for all replicas
SHOW SLAVE Connection name STATUS\G -- Show status for the specified replica connection
Renaming a replicated database
It can be necessary, especially when doing multi-master replication, to rename the replicated database to avoid a clash with an already existing database on the replication server.
There is no option to do it when dumping or importing the database, so the SQL statements are patched in the dump before loading it during initialization:
# Usage: cat dump.sql | db-rename db1_from db1_to | db-rename db2_from db2_to gsed -E \ -e 's/^(CREATE DATABASE (\/*(.*?)*\/ )?`)'$1'(`( \/*(.*?)*\/)?;)/\1'$2'\4/' \ -e 's/^(USE `)'$1'(`;)$/\1'$2'\2/'
cat Dumped databases | db-rename Database name on master Database name on replicated server | db-rename Database name on master Database name on replicated server
and renaming rules are inserted in server.cnf on the slave:
master-name.replicate-rewrite-db=Database name on master->Database name on replicated server master-name.replicate-rewrite-db=Database name on master->Database name on replicated server
Renaming does not protect the mysql database:
replicate-rewrite-db only affects statements involving tables, and
DROP USER / CREATE USER statements would still apply to it,
clobbering the replica’s own privileges. To exclude it:
master-name.replicate-ignore-db=mysql
Initialization
-
As
SET GLOBAL gtid_slave_posreplaces the whole position list (there is no way to update a single domain), the positions of the other domains have to be merged in by hand. A script to do that: -
Setting
sql_log_binto 0 keeps the restore out of the binary log. Without it the restore is written to the binlog and sent to any downstream replica — possibly back to the master it came from — and adds one GTID in the local domain per transaction. It is provisioning, not new data.
-
Creating an SQL dump on the master side:
Session 1 Session 2 FLUSH TABLES WITH READ LOCK;(keep the client running) mariadb-dump --gtid --opt \ --apply-slave-statements \ --all-databases --flush-logs \ --master-data=2 > dump.sqlUNLOCK TABLES;Session 1 will protect against table modification (such as
ALTER,DROP,RENAME,TRUNCATE), while session 2 will perform the dump locking all tables (implicit with--master-data) protecting against row modifications (such asINSERT,DELETE,UPDATE). If all databases are of InnoDB type it is possible to add--single-transactionso to have a dump without blocking row modifications while still having consistent data.Using
--apply-slave-statementswill insert necessary “STOP/START SLAVE” statements, so it won’t be necessary to manually stop/start slave when importing dump.With
--master-datatheCHANGE MASTERstatement is generated without the connection name: using=2it stays commented out (the position is set throughgtid_slave_posin the next step); with=1the dump would have to be edited to insert the connection name. -
Loading and starting the slave (on slave side):
mariadb-admin stop-all-slaves # Stop all slaves gtid=`gtid-merge Dumped databases` # Query DB and merge GTID mariadb -e "SET GLOBAL gtid_slave_pos='$gtid'" # Position new GTID { echo "SET SESSION sql_log_bin=0;"; # Avoid re-propagating cat Dumped databases; } | mariadb # ... and load data mariadb-admin start-all-slaves # Restart slaves
-
Flushing privileges on slave (eventually)
mariadb -e 'FLUSH PRIVILEGES' # If `mysql` table was altered
Backup
The following script allows to perform a full backup from the slave while ensuring that data is in a consistent state:
#!/bin/sh
dir=Backup directory
file=backup-`date +%Y%m%d`.sql.bz2
mariadb-admin stop-all-slaves
mariadb-dump --comments --quote-names --routines --opt \
--lock-all-tables --all-databases | bzip2 > "${dir}/${file}"
mariadb-admin start-all-slaves
Commands
SHOW GRANTS FOR user
SHOW CREATE TABLE table_name