Kulcsszó - mysql

Nagy terheltségű, főleg InnoDB alapú MySQL adatbázisszervereknél előfordulhat üzemszünet amiatt, mert a szofver nem tud újabb állományokat megnyitni. Ilyen esetekben a szerver hibanaplójában a következőhöz hasonló hibaüzenetek kerülhetnek logolásra:

2017-11-10 00:11:22 [ERROR] /usr/sbin/mysqld: Can open file: ./example_db/example_table.frm (errno: 24 - Too many open files)
2017-11-10 00:11:23 [ERROR] /usr/sbin/mysqld: Can open file: ./example_db/example_table.frm (errno: 24 - Too many open files)

A hibakeresésnél érdemes lehet az alábbi parancsokat lefuttatni a mysql prompt alatt:
SHOW VARIABLES LIKE open_files_limit; # lekérjük az aktuálisan beállított open_files_limit-et
SHOW GLOBAL STATUS LIKE Open_files; # megnézzük, hogy hány fájl került megnyitásra

A fenti parancsok közül az első kimenetéből látni fogjuk az aktuális limitet, ezt jegyezzük fel magunknak, a további hibajavításnál ezt a számot kell majd megemelnünk.

Az alábbi tutorial CentOS 7-re készült, más operációs rendszereknél egy-egy konfigurációs állomány más helyen lehet, de a hibajavítás logikája ezeken is megegyezik az alább vázoltakkal.vi /etc/my.cnf # a fájlban az open_files_limit kezdetű sorban található számot az előzőleg már megállapított értéknél magasabbra állítjuk; ha nem volt ilyen sor a fájlban, akkor adjuk hozzá azt így: open_files_limit = $ÚJÉRTÉK
vi /etc/security/limits.conf # a fájlba beszúrjuk a következő sort (vagy ha már létezett, megnöveljük az adott sor végén szereplő értéket): mysql hard nofile $ÚJÉRTÉK
vi /etc/systemd/system/mysql.service # a fájlban a LimitNOFILE értéket megemeljük az $ÚJÉRTÉK-re
/etc/systemd/system/mysql.service.d/limits.conf # a fájlban a LimitNOFILE értéket megemeljük az $ÚJÉRTÉK-re
systemctl daemon-reload; service mysql restart # újratöltjük a daemon szolgáltatást, majd újraindítjuk a MySQL szervízt

Érdemes lehet még a javítás végén az összes adatbázisra egy MySQL ellenőrzést és automatikus hibajavítást futtatni:

mysqlcheck --all-databases --auto-repair

A mai cikkünkben egy MySQL replika készítésének lépéseit fogom röviden leírni. A cikkben található tutorial egy megbízásom miatt készült, melyben Ubuntu 16.04 LTS szerver alapokon kellett egy master-slave MySQL replikát összerakni.
A master-slave MySQL replika esetén a külső alkalmazások a master szerveren lévő MySQL adatbázisokhoz csatlakoznak, az azokon végzett módosítások pedig automatikusan szinkronizációra kerülnek a slave szerverre. A master-slave felállás előnye, hogy az adatbázisokról real time másolat készül, amit a master szerver kiesése esetén kézzel egy-két perc alatt használhatóvá lehet tenni. A slave szerver ideiglenes kiesése esetén a szinkronizálás annak újra elérhetővé válása után folytatódik. Üzemeltetési szempontból azért is hasznos, mert az adatbázismentéseket lehet futtatni a slave szerveren, ezzel tehermentesítve a mastert. Némely alkalmazásfejlesztő az alkalmazása gyorsítása érdekében úgy írja meg szoftverét, hogy azon read only query-ket, ahol egy-két rekord eltérésnyi hiba elfogadható, a slave szerveren futtatják, ezzel tehermentesítve a master szervert, és gyorsítva a szoftvert.

Először is, mindkét Ubuntura feltelepítjük a MySQL szervert:
apt install mysql-server mysql-client -y

Ezután a master szerveren elvégzünk egy-két konfigurációt:
service mysql stop
vi /etc/mysql/mysql.conf.d/mysqld.cnf # végére alábbi négy sor hozzáadása:
server-id = 250 # beállítunk egy egyedi szerver azonosítót - nálam ez az IP cím utolsó tagja lett
binlog_ignore_db = mysql
log-error = /var/log/mysql/mysql.err
log-bin = /var/log/mysql/mysql-replication.log
Fentieket kívül kommentezzük ki a bind-address sort is a mysqld.cnf-ből.
TODO: érdemes tűzfallal védeni ez esetben a szervert, hogy ne lehessen bárhonnan elérni a MySQL portokat (pl. iptables + fail2ban kombinációval). Erre nekem most nem volt szükségem, mivel egy komplett tűzfal volt a szerverek előtt.
service mysql restart
mysql # alábbi három parancs futtatása
CREATE USER masterslave@'%' IDENTIFIED BY 'IdeJonATavoliKapcsolodastBiztositoFelhasznaloJelszava';
GRANT SELECT, PROCESS, FILE, SUPER, REPLICATION CLIENT, REPLICATION SLAVE, RELOAD ON *.* TO masterslave@'%';
FLUSH PRIVILEGES;

Most következik a slave szerver konfigurációja:
service mysql stop
vi /etc/mysql/mysql.conf.d/mysqld.cnf # végére alábbi sor hozzáadása:
server-id = 251 # beállítunk egy egyedi szerver azonosítót - nálam ez az IP cím utolsó tagja lett

A fenti műveletek elvégzése után feltöltjük ugyanazt a teszt adatbázist mindkét szerverre. (Nem vagyok biztos benne, hogy ez a művelet szükséges - az általam kiindulási alapnak vett dokumentációkban szerepelt. Mindenesetre a replika beállítása után alapértelmezetten az újonnan létrehozott adatbázisok is automatikusan replikálásra kerülnek a slavere.)

Ezután a master szerveren lekérünk egy-két egyedi információt, ami szükséges lesz ahhoz, hogy később párosítsuk a slave szerverrel.
Fontos! A művelet alatt LOCK-oljuk a master szerveren az adatbázist, így az nem lesz írható!
mysql # alábbi két parancs kimenetét jegyezzük fel (file és position érték fog kelleni)
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;

Ezután a slave szervert párosítjuk a master szerverrel:
mysql
CHANGE MASTER TO MASTER_HOST='192.168.1.250', MASTER_USER='masterslave', MASTER_PASSWORD='IdeJonATavoliKapcsolodastBiztositoFelhasznaloJelszava', MASTER_LOG_FILE='mysql-replication.000001', MASTER_LOG_POS=8794; # ennél a parancsnál a mysql-replication.000001 és a 8794 sztringeket cseréljük ki az előző bekezdésben lekérdezett információkkal, valamint a 192.168.1.250 részt a master IP címével
START SLAVE;
SHOW SLAVE STATUS; # akkor sikerült megfelelően a párosítás, ha a "Waiting for master to send event." üzenet fogad

Végezetül a master szerveren feloldjuk a lockolást:
mysql
UNLOCK TABLES;

A fenti konfiguráció után van egy működő mysql replikánk.

Az alábbi parancs kiadásával egy adott szerveren található összes MySQL adatbázis tartalmát kidumpolhatjuk:

for db in $(mysql -u root -pPASSWORD -s -e "SHOW DATABASES;"); do mysqldump -u root -pPASSWORD $db > $db-backup.sql; done

(A "PASSWORD" helyére a mysql root felhasználó jelszavát kell megadni)