Progetto

Generale

Profilo

Configurare istanze multiple di MySQL

In alcuni casi, ad esempio se si devono gestire una serie di repliche di database diversi su una singola macchina, può essere necessario lanciare più istanze di MySQL. Benché sia possibile duplicare gli script di avvio e la configurazione dell'istanza principale (quella installata e configurata direttamente dal pacchetto), questo comporta anche l'uso di diverse directory e file di configurazione. Ma con MySQL viene distribuito il programma mysqld_multi il cui scopo è proprio quello di lanciare e gestire istanze multiple, utilizzando un solo file di configurazione.

Di default il programma usa come configurazione direttamente /etc/mysql/my.cnf, ma se si vuole mantenere separata la gestione dell'istanza principale rispetto a quelle gestite tramite mysqld_multi si può fare ricorso ad un file qualunque, da indicare con l'opzione --defaults-file, nel nostro caso useremo /etc/mysql-multi/my.cnf. Per evitare errori, e semplificarsi la vita nello scrivere i comandi, abbiamo provveduto a definire un alias di shell in .bashrc nella forma:

alias mysqld_multi='mysqld_multi --defaults-file=/etc/mysql-multi/my.cnf'

Per poter lanciare istanze multiple queste devono essere identificate nel file di configurazione con un numero (denominato GNR), da configurare in altrettante sezioni distinte del file di configurazione, introdotte da una voce nella forma [mysqldN]. Inoltre devono essere indicate le configurazioni specifiche di mysqld_multi stesso in una sezione [mysqld_multi], nel nostro caso il contenuto di questa sezione è:

[mysqld_multi]
mysqld = /usr/bin/mysqld_safe
mysqladmin = /usr/bin/mysqladmin
log = /var/log/multi_mysql.log

Le configurazioni da applicare alle varie istanze aggiuntive sono identiche a quelle della sezione [mysqld] di una installazione ordinaria, si tratta però di evitare l'uso degli stessi file e delle stesse directory, inoltre ogni istanza dovrà mettersi in ascolto su un indirizzo IP o su una porta diversa. Questo significa che si dovrà o usare la direttiva port per indicare una diversa porta ad ogni istanza, o usare la direttiva bind-address per specificare un indirizzo IP diverso (nel qual caso ovviamente si saranno dovuti assegnare indirizzi multipli alla propria scheda di rete). In quest'ultimo caso si deve tenere presente che non sarà più possibile per nessuna istanza usare l'indirizzo generico 0.0.0.0 e che per ascoltare su localhost occorrerà usare specificamente bind-address=127.0.0.1 e che questo sarà possibile per una sola istanza.

Un esempio di configurazione di una istanza aggiuntiva lanciata con mysqld_multi è il seguente, si noti come si sia usata la convenzione di aggiungere ai vari file e directory utilizzati il numero che identifica l'istanza stessa; si noti anche la presenza di una direttiva skip-grant-tables che andrà rimossa completata la configurazione iniziale.

[mysqld1]
user            = mysql
pid-file        = /var/run/mysqld/mysqld1.pid
socket          = /var/run/mysqld/mysqld1.sock
basedir         = /usr
datadir         = /var/lib/mysql1
tmpdir          = /tmp
lc-messages-dir = /usr/share/mysql
log-error=/var/log/mysqld1.log
skip-external-locking
bind-address    = istanza1.miodominio.it
key_buffer              = 16M
max_allowed_packet      = 16M
thread_stack            = 192K
thread_cache_size       = 8
myisam-recover         = BACKUP
query_cache_limit       = 1M
query_cache_size        = 16M
expire_logs_days        = 10
max_binlog_size         = 100M
# to be removed #
skip-grant-tables
# to be removed #

Si ripeta la sezione precedente per le ulteriori istanze volute, inserendo altrettante analoghe sezioni [mysqldN] con contenuto analogo ed un valore diverso per N. Si tenga presente che ogni istanza deve avere una datadir diversa, pertanto per ciascuna le si creino nella forma:

mkdir /var/lib/mysql1 -m 700
mkdir /var/lib/mysql2 -m 700
...
chown mysql.mysql /var/lib/mysql1
chown mysql.mysql /var/lib/mysql2
...

Una volta configurate le varie istanze occorre creare per ciascuna di esse il database iniziale di MySQL (mysql), questo nel caso dell'istanza precedente potrà essere effettuato con il comando:

mysql_install_db --user=mysql --datadir=/var/lib/mysql1

ripetendo eventualmente il comando per tutte le istanze successive. A questo punto si potranno avviare manualmente le istanze (si da per assunto che si stato creato l'alias descritto in precedenza) con:

mysqld_multi start

A questo punto, come richiesto nelle istruzioni stampate da mysql_install_db, occorrerebbe impostare una password di accesso per l'utente root dei database appena creati.

L'installazione del database di default però restringe l'accesso senza password a root a localhost ed all'hostname principale della macchina, per cui non è possibile accedervi usando un indirizzo IP diverso ed i comandi indicati da mysql_install_db non funzionerebbero.

Per questo è necessario far partire la prima volta il servizio con la direttiva skip-grant-tables, in modo di poter accedere comuqnue al database ed effettuare le correzioni necessarie rispetto a quanto installato da mysql_install_db. Pertanto una volta fatte partire le istanze ci si colleghi a ciascuna di esse con mysql -h istanzaN.miodominio.it -u root e si eseguano i comandi:

DROP DATABASE test;
use mysql
DELETE FROM user WHERE user='';
UPDATE user SET host='istanzaN.miodominio.it' WHERE host='nomemacchina';
UPDATE user SET Password=PASSWORD("passwordlungaecomplicata") WHERE User="root";

A questo punto si potrà fermare l'esecuzione delle istanze aggiuntive, rimuovere l'opzione skip-grant-tables dal file di configurazione, e riavviare le stesse, collegandosi normalmente con la password impostata.

Questo non è necessario se invece si stanno usando istanze su porte diverse, ma in tal caso è necessario collegarsi con mysqladmin indicando la porta corretta. La cosa sembrerebbe banale non fosse per il fatto che se si esegue la connessione senza specificare l'hostname con -h il programma ignora la direttiva --port ed usa la connessione via socket locale, ma non solo, in maniera idiota lo fa anche quando si usa come hostname localhost, per cui se non si sta attenti ci si collegherà, se è attiva, sempre all'istanza principale usando il socket di default.

Pertanto occorre specificare sempre esplicitamente -h 127.0.0.1 che per fortuna non viene liberamente (e stupidamente) reinterpretata. Questo significa che in caso di uso delle porte sarà possibile cambiare password di root con mysqladmin usando il comando:

mysqladmin -h 127.0.0.1 --port NNNN -u root -p password 'passwordlungaecomplicata'

(dove NNNN è il numero di porta indicato nella configurazione per l'istanza in questione) sfruttando il fatto che la password iniziale dell'utente root è vuota.

Gestione dei servizi

Con il pacchetto di mysql fino a Wheezy è disponibile uno script di avvio minimale /usr/share/mysql/mysqld_multi.server che può essere adattato per essere inserito nel sistema di avvio a dipendenze di Wheezy con qualche modifica (alternativamente si può modificare lo script di avvio /etc/init.d/mysql usando mysqld_multi al posto di mysqladmin e togliendo i controlli che non fanno riferimento all'uso di mysqld_multi.

Con Jessie e l'introduzione di systemd si può ricorrere ad una unit file template dedicata, da installare sotto /etc/systemd/system, e nel caso specifico si è fatto riferimento ad una configurazione mantenuta sotto /etc/mysql-multi/my.cnf come descritto in precedenza. Per questo basterà inserire il seguente contenuto nel file /etc/systemd/system/mysqld@.service:

[Unit]
Description=MySQL Multi for instance %i
After=syslog.target
After=network.target

[Service]
User=mysql
Group=mysql
Type=forking
ExecStart=/usr/bin/mysqld_multi --defaults-file=/etc/mysql-multi/my.cnf start %i
ExecStop=/usr/bin/mysqld_multi  --defaults-file=/etc/mysql-multi/my.cnf stop %i
Restart=always
PrivateTmp=true

[Install]
WantedBy=multi-user.target

In questo caso, essendo eseguiti i programmi per conto dell'utente mysql occorrerà sincerarsi che i file di log citati nella configurazione esistano (o possano essere creati) e siano scrivibili dal suddetto utente. Una volta creato il file occorrerà eseguire systemctl daemon-reload per fargli leggere la nuova unit.

A questo punto si potrà far partire l'istanza N di mysql (che deve essere definita nella configurazione) con:

systemctl start mysqld@N

controllarne lo stato con:

systemctl status mysqld@N

fermarla con:

systemctl stop mysqld@N

ed abilitarne la partenza all'avvio del sistema con:

systemctl enable mysqld@N