Let’s export data from your existing database (assuming you have a single MariaDB instance and want to migrate a database or more into this HA galera cluster).
In this case, we will consider migrating a WordPress instance, as those are quite common still.
Log into the web server via SSH and find the wp-config.php file.
# The exact path may differ
cd /opt/www/html/bachelor-tech
nano wp-config.php
mysql -u root -p
-- Creates a new database for WordPress. You can skip this if the import file creates it.
CREATE DATABASE wordpress_db;
-- This is the main command. It grants a user full rights to the wordpress_db
-- ONLY when connecting from your app's specific IP address. Replace the IP with your web server's.
GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wordpress_user'@'X.Y.I.Z' IDENTIFIED BY 'strong_db_password';
# GRANT ALL PRIVILEGES ON iriskayan_com_db.* TO 'iriskayan_com_user'@'192.168.%' IDENTIFIED BY 'YourWordPressDbPassword';
-- Applies the new permissions immediately.
FLUSH PRIVILEGES;
mysqldump -u root -p wordpress_db > /tmp/wordpress_backup.sql
sudo systemctl stop ufw and then start it back on afterwards.# On the original MariaDB single instance, change the following to suit your SSH port, file names and IP:
rsync -rvz -e 'ssh -p 2222' --progress /tmp/your_exported_db.sql [email protected]:/tmp
Data copying process from a single node to a cluster node
rsync -rvz -e 'ssh -p 2222' --progress /tmp/yourfile.sql [email protected]:/tmp
mysql -u root -p your_galera_db < /path/to/db.sql
mysql -u root -p -e "SET wsrep_on=OFF; SOURCE /path/to/your/db.sql;" db_dump.sql. The additional command turns off Galera’s replication for each INSERT command, as Galera must replicate and get approval (certify) for each of these transactions across all nodes in the cluster. So essentially, we say ‘just execute all of the following commands locally without replicating them one-by-one’ and the replication will start only after it is all done. However, then we would need to perform a full State Snapshot Transfer (SST), such as by logging into each node, switching mariadb off, removing the content of /var/lib/mysql/ and then switching it back on. In most cases, this approach is not needed.# On another Galera node:
mariadb -u root -p
-- OPTION 1 - list the size of all the DBs in your instance:
SELECT
table_schema 'DB Name',
SUM(data_length + index_length) 'Size in Bytes',
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) 'Size in MiB'
FROM information_schema.tables
GROUP BY table_schema;
-- OPTION 2 - Examine the size of a particular DB
SELECT
SUM(data_length + index_length) 'Size in Bytes',
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) 'Size in MiB'
FROM information_schema.tables
WHERE table_schema = 'your_db'
# WHERE table_schema = 'bachelor_tech_com_db'
GROUP BY table_schema;
Option 1 - InnoDB tables are being used
MyISAM or MEMORY tables while Galera transfers only InnoDB tables. Let’s verify that by comparing the fully imported DB versus another one that the DB was supposed to replicate to but did not fully:# On the original node where you imported the DB into:
mysql -u root -p
USE your_db;
SELECT
TABLE_NAME,
ENGINE,
TABLE_ROWS AS 'Rows',
ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS 'Total MiB'
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = 'iriskayan_com_db'
AND ENGINE IN ('MyISAM', 'MEMORY');
MyISAM and MEMORY. See below for a comparison between the original and another node to which it was supposed to replicate:# Login and remove the DB from the cluster:
mysql -u root -p
# Remove it and create a fresh new one:
DROP DATABASE your_db;
CREATE DATABASE your_db;
# Grant privileges as before:
GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wordpress_user'@'X.Y.I.Z' IDENTIFIED BY 'strong_db_password';
FLUSH PRIVILEGES;
EXIT;
# Modify the table properties from the MySQL dump:
sed \
-e 's/ENGINE=MyISAM/ENGINE=InnoDB/g' \
-e 's/ENGINE=MEMORY/ENGINE=InnoDB/g' \
/tmp/mydb_backup.sql > /tmp/mydb_fixed.sql
# Re-import it:
mysql -u root -p your_db < /tmp/your_db_fixed.sql
#mysql -u root -p iriskayan_com_db < /tmp/iriskayan_db_fixed.sql
Option 2 - low memory limit in the MariaDB configuration (less likely the case). How to check? On any Galera cluster node:
mysql -u root -p
SELECT
VARIABLE_NAME,
VARIABLE_VALUE AS 'Value in Bytes',
ROUND(VARIABLE_VALUE / 1024 / 1024, 2) AS 'Value in MB'
FROM information_schema.GLOBAL_VARIABLES
WHERE VARIABLE_NAME IN ('wsrep_max_ws_size', 'max_allowed_packet');
max_allowed_packet before, but in case you skipped this step or stuck to your own config - if the value is anything smaller than 256 MB, you could change it in the MariaDB config file:nano /etc/mysql/mariadb.conf.d/60-galera.cnf
# Locate or add these rows:
max_allowed_packet = 512M
wsrep_max_ws_size = 512M
Congratulations on your data import! Now you just need to change the configuration in your web application to point to the virtual IP address that your load balancer operates with. That is also where you can observe where the traffic is going.
Once all done, verify that your cluster is fully operational with these commands:
SHOW STATUS LIKE 'wsrep_cluster_size';
SHOW STATUS LIKE 'wsrep_local_state_comment';
SHOW STATUS LIKE 'wsrep_connected';
SHOW STATUS LIKE 'wsrep_ready';
wsrep_cluster_size: 5+ (whatever number makes sense)wsrep_local_state_comment: Syncedwsrep_connected: ONwsrep_ready: ON mysql -u root -p -e "SHOW VARIABLES LIKE 'wsrep_provider_options';" | tr ';' '\n' | grep -E 'segment|weight'
gmcast.segment = 2
pc.weight = 2
What are the most common scenarios when a quorum is lost and thus the Galera cluster fails?
In either case, the cluster has to be recovered manually to prevent data loss. So it is a feature, not a bug! Please refer to this article if you have been affected by the cluster shutdown (or are just simulating it).
In a nutshell, the idea is to SSH into each node and verify which one is safe to bootstrap (the result should be 1 on one of them), then you can start a new cluster on that node. Once it is back up, you will need to restart MariaDB on each cluster node.
cat /var/lib/mysql/grastate.dat | grep safe_to_bootstrap
# Run this on whichever node results in 1:
sudo galera_new_cluster
# Watch the logs for changes
tail -n 50 /var/log/mysql/error.log
# Restart MariaDB on OTHER nodes
sudo systemctl restart mariadb
Such an approach definitely warrants its own article - let me know in the comments below if you are interested!
This concludes our rather comprehensive guide on how to deploy a Galera Cluster using technologies like Proxmox, OPNSense, HAProxy and LXC containers. Feel free to share your own experience and stack, perhaps this guide could be expanded to account for more options in the set up.
You might argue that the process we have been through related to setting up a new Galera node is rather very manual. You are correct! Yet we have options for a faster recovery in case a node goes down. From the point of having a template ready, we can utilize Ansible, create a playbook that would do the following:
community.general.proxmox_lxc module to force-stop that node identified by its IP address or hostname.template module, we modify the 60-galera.cnf file located in /etc/mysql/mariadb.conf. An example is below:# ...
wsrep_cluster_name="{{ cluster_name }}"
wsrep_cluster_address="gcomm://{{ cluster_ips }}"
wsrep_sst_auth = "{{ sst_username }}:{{ sst_password }}"
wsrep_node_address = "{{ node_ip }}"
wsrep_node_name = "{{ node_name }}"
wsrep_sst_receive_address = "{{ node_ip }}"
Would you like a step-by-step guide? Leave a comment and some magic may happen 😇