====== Mysql - Βάση δεδομένων ======
===== Εγκατάσταση / Ρυθμίσεις =====
Για να εγκαταστήσουμε την mysql εκτελούμε
apt install mariadb-server mariadb-client
Αρχικά θα πρέπει να αλλάξουμε τον κωδικό του διαχειριστή της mysql. Αρχικά εκτελούμε
mysql -u root
Στην προτροπή "mysql>" πληκτρολογούμε:
**Για εκδόσεις έως 5.7.5**
mysql> set password = password("yournewpassword");
**Για εκδόσεις 5.7.6 και μετά** (βλ. https://www.percona.com/blog/2016/03/16/change-user-password-in-mysql-5-7-with-plugin-auth_socket/)
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'test';
Στην συνέχεια θα συνδεόμαστε με την παράμετρο -p ώστε να μας ζητείται κωδικός
mysql -u root -p
==== Ελληνικά ====
Για να ορίσουμε σωστά τα ελληνικά στην κονσόλα της mysql αλλά και να ορίσουμε utf-8 κωδικοποίηση στις νέες βάσεις που δημιουργούμε μπορούμε να εισάγουμε ένα αρχείο με όνομα greek.cnf στον φάκελο /etc/mysql/conf.d/ με τα παρακάτω περιεχόμενα
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
==== unix socket authentication plugin ====
Για να μπορεί να λειτουργήσει το mariadb-upgrade που εκτελείται σε κάθε εκκίνηση της mysql μέσα στο /etc/mysql/debian-start χρειάζεται να μπορεί να συνδεθεί στην mysql. Για να μην χρειάζεται να αποθηκευτεί ο κωδικός plain text στο /etc/mysql/my.cnf μπορούμε να ρυθμίσουμε το unix authentication plugin εκτελώντας
mysql_secure_installation -S /run/mysqld/mysqld.sock
Έτσι σε περίπτωση αναβάθμισης με ελέγχονται όλοι οι πίνακες και θα αναβαθμίζεται σωστά η εσωτερική δομή της mysql στην 1η εκκίνηση και δεν θα εμφανίζονται τα παρακάτω μηνύματα
Jun 14 10:09:47 s2 /etc/mysql/debian-start[4107]: Reading datadir from the MariaDB server failed. Got the following error when executing the 'mysql' command line client
Jun 14 10:09:47 s2 /etc/mysql/debian-start[4107]: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
Jun 14 10:09:47 s2 /etc/mysql/debian-start[4107]: FATAL ERROR: Upgrade failed
Στην συνέχεια ως root δεν θα χρειάζεται να παρέχουμε κωδικό στην σύνδεση τοπικά στην mysql.
===== Επιδόσεις =====
Κατεβάζουμε το MySQLTuner
wget http://mysqltuner.com/mysqltuner.pl
Το κάνουμε εκτελέσιμο
chmod +x mysqltuner.pl
και το εκτελούμε (προσοχή καλό είναι να το κάνουμε μετά από 2-3 μέρες συνεχούς λειτουργίας της mysql)
./mysqltuner.pl
Από τις προτάσεις του
==== my.cnf ====
Ακολουθούμε γενικά τις προτάσεις του αρχείου /usr/share/doc/mysql-server-5.0/examples/my-huge.cnf.gz που αφορά σύστημα με 1-2GB μνήμη
key_buffer = 384M
max_allowed_packet = 1M
table_cache = 512
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size = 32M
και στο τέλος του αρχείου
[isamchk]
key_buffer = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M
#
[myisamchk]
key_buffer = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M
==== defrag ====
Με την παρακάτω εντολή κάνουμε defrag
mysqlcheck -Aao --auto-repair -u root -p
===== phpmyadmin =====
Χρησιμοποιώντας το Web Developer/Performance utility του firefox παρατηρήθηκε ότι στο login screen και στην περιήγηση στο phpmyadmin υπήρχε μεγάλη καθυστέρηση περίπου **15s** από το **get_scripts.js.php** σε έναν server με 1Mbit upload.
Με την παρακάτω ρύθμιση στο αρχείο **/etc/phpmyadmin/apache.conf** γίνεται πλέον caching από τους browser και η λήψη μειώθηκε από από 1Mbyte σε 200Kb
..
AddOutputFilter DEFLATE css js
ExpiresActive On
ExpiresByType application/javascript A2592000
===== mycli =====
Για σύνδεση στην mysql από κονσόλα μπορούμε να επιλέξουμε το **mycli** το οποίο παρέχει **auto-completion**.
Για εγκατάσταση σε Debian 9
apt-get install mycli
Σε προηγούμενες εκδόσεις Debian
pip install mycli
===== Παρακολούθηση Λειτουργίας =====
Ο πιο απλός τρόπος είναι μια εντολή στο crontab του root. Εάν παρακολουθούμε τα e-mail του root θα ενημερωνόμαστε για τυχόν προβλήματα
Εκτελούμε ως root
crontab -e
και εισάγουμε την παρακάτω γραμμή
0 8 * * * cat /var/log/syslog.0 | grep mysqld
Στις 8:00am κάθε μέρα θα ελέγχεται το αρχείο syslog της προηγούμενης μέρας.
Εάν δεν υπάρχει έξοδος από την εντολή δεν θα λαμβάνουμε κανένα μήνυμα
Η ώρα μπορεί να επιλεχθεί βλέπωντας κάθε πότε γίνεται rotate στο σρχείο syslog
ls -al /var/log/syslog*
-rw-r----- 1 root adm 245701 2008-12-28 16:20 /var/log/syslog
-rw-r----- 1 root adm 3088106 2008-12-28 06:27 /var/log/syslog.0
-rw-r----- 1 root adm 34882 2008-12-27 06:25 /var/log/syslog.1.gz
-rw-r----- 1 root adm 23928 2008-12-26 06:25 /var/log/syslog.2.gz
-rw-r----- 1 root adm 13909 2008-12-25 06:25 /var/log/syslog.3.gz
..
Αυτό μας δείχνει ότι μπορούμε να επιλέξουμε μια ώρα μετά τις 6:25am
===== Εντολές =====
Για να εμφανίσουμε εγγραφές με τα πεδία αριστερά και τις τιμές δεξιά εκτελούμε με την παράμετρο \G π.χ
mysql> select * from mysql.user\G
===== Master - Master Replication Server =====
Ακολουθούμε τα βήματα από : http://www.howtoforge.com/mysql5_master_master_replication_debian_etch
Για την περίπτωση που σταματήσει το replication και αργήσουμε να το αντιληφθούμε μπορούμε να αυξήσουμε τις μέρες που κρατιώνται τα logs από 10 σε 30.
Τροποποιούμε το αρχείο /etc/mysql/my.cnf
expire_logs_days = 30
Καλό είναι επίσης να ορίσουμε την αυτόματη παράκαμψη κάποιων προβληματικών sql επερωτήσεων που μπορούν να προκύψουν κατά το replication (βλ http://www.ducea.com/2008/02/13/mysql-skip-duplicate-replication-errors/).
slave-skip-errors = 1062,1146
#1062 : duplicate inserts (common in joomla) #1146 : table does not exist
Άλλη μία καλή ρύθμιση είναι να γίνεται συγχρονισμός στο replication binary log. Ορίζουμε στο my.cnf
[mysqld]
sync_binlog = 1
=====Αντιμετώπιση Προβλημάτων=====
==== Access denied for user 'root'@'s1.myserver.com' ====
Εάν η εντολή
mysqladmin -h s1.myserver.com -p -u root password
μας βγάλει μήνυμα λάθους
error: 'Access denied for user 'root'@'s1.myserver.com' (using password: YES)
Θα πρέπει να ορίσουμε τον χρήστη 'root'@'s1.myserver.com' με πλήρη δικαιώματα
mysql -u root -p
mysql> GRANT ALL PRIVILEGES ON *.* to 'root'@'s1.myserver.com' identified by 'password';
mysql> quit
Εάν κατά την εκκίνηση της mysql η εντολή
tail -f /var/log/syslog
μας βγάλει το ακόλουθο μήνυμα λάθους
[ERROR] Could not find target log during relay log initialization
αρκεί να σβήσουμε ή να τροποποιήσουμε το αρχείο relay-log.info. Τέτοιου είδους πρόβλημα μπορεί να συμβεί και σε αλλαγή του ονόματος του μηχανήματος (hostname)
====/usr/bin/mysqladmin: connect to server at 'localhost' failed ====
Εάν μας βγάλει το ακόλουθο μήνυμα
/usr/bin/mysqladmin: connect to server at 'localhost' failed
error: 'Access denied for user 'debian-sys-maint'@'localhost' (using password: YES)'
θα πρέπει να τοποθετήσουμε το σωστό κωδικό για τον debian-sys-maint στο αρχείο /etc/mysql/debian.cnf. Τον κωδικό θα τον βρούμε κρυπτογραφημένο στο αντίστοιχο αρχείο του υπολογιστή από τον οποίο πήραμε backup της βάσης mysql
====Replication : Error running query, slave SQL thread aborted====
Εάν κάποιος από τους 2 servers σταματήσει την λειτουργία προσωρινά στην επαναφορά ελέγχουμε πάντα για τυχόν λάθη με
tail -f /var/log/syslog
Εάν μας εμφανιστεί το παρακάτω λάθος
Error_code: 145
Dec 27 16:50:25 s1 mysqld[4420]: 071227 16:50:25 [ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'mysql-bin.000544' position 18245
Για να δούμε την κατάσταση εκτελούμε
mysql>SHOW SLAVE STATUS \G
Ακολουθούμε με την σειρά τις παρακάτω προτεινόμενες μεθόδους.
Μετά από κάθε προτεινόμενη διαδικασία επίλυσης, ελέγχουμε εάν το πρόβλημα λύθηκε
mysql> START SLAVE;
mysql> SHOW SLAVE STATUS \G
Ελέγχουμε τις Slave_IO_Running και Slave_SQL_Running να είναι Yes καθώς και το Last_Erro να είναι κενό
Εναλλακτικά επανεκκινούμε την mysql
/etc/init.d/mysql restart
Και τσεκάρουμε από το syslog ότι όλα συνεχίστηκαν κανονικά
tail -f -n 100 /var/log/syslog
Τα mysql-bin logs αποθηκεύονται στον φάκελο /var/log/mysql/
=== 1η λύση ===
Αν αφορά απλή περίπτωση διπλοεγγραφής τότε από το phpmyadmin την διαγράφουμε. Επανεκκινώντας και πάλι τους 2 servers από τα replication logs του ενός θα ξαναεκτελεστεί
Αλλιώς μπορούμε να προσπεράσουμε την προβληματική εντολή ακολουθώντας τις οδηγίες εδω : http://www.brandonchecketts.com/archives/2008/09
mysql> stop slave; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; start slave;
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Για να δούμε αν όλα είναι ok
mysql> SHOW SLAVE STATUS \G
Αν δούμε κάποιο μήνυμα λάθους επαναλαμβάνουμε την διαδικασία
Καλό είναι να κάνουμε και μια επανεκκίνηση για να σιγουρευτούμε ότι όλα είναι ok
/etc/init.d/mysql restart
Τσεκάρωντας πάλι από το syslog ή με
mysql> SHOW SLAVE STATUS \G
=== 2η λύση ===
Εάν οι προβληματικές sql επερωτήσεις αφορούν μία βάση μόνο και είναι δεκάδες τότε μπορούμε προσωρινά να ρυθμίσουμε το replication να αγνοεί αυτή τη βάση ώστε να προχωρήσει.
Τροποποιούμε το αρχείο my.cnf ώστε να αγγνοεί την βάση testdb
replicate-ignore-db = testdb
Στην συνέχεια επανεκκινούμε την mysql
/etc/init.d/mysql restart
Ελέγχουμε πάλι αν όλα είναι ok
mysql> SHOW SLAVE STATUS \G
Στον server που υπάρχει η βάση testdb χωρίς πρόβλημα θα πρέπει να κρατήσουμε backup και ύστερα να την διαγράψουμε.
mysqldump -e --force --quick --quote-names -h localhost -u testdbuser -pPassword testdb > /backup/various/testdb-$(date +%Y-%m-%d).sql
mysql -uroot -e"DROP DATABASE testdb;"
Στην συνέχεια τροποιούμε πάλι το αρχείο my.cnf βάζωντας σε σχόλια
#replicate-ignore-db = testdb
Eπανεκκινούμε την mysql
/etc/init.d/mysql restart
Δημιουργούμε ξανά την βάση testdb στον άλλο server επαναφέροντας τα δεδομένα της από το backup
mysql -uroot -e"CREATE DATABASE testdb;"
mysql --force --quick -h localhost -u testdbuser -pPassword testdb < /backup/various/testdb-$(date +%Y-%m-%d).sql
Ελέγχουμε πάλι αν όλα είναι ok στον server που είχε προηγουμένως το πρόβλημα
mysql> SHOW SLAVE STATUS \G
=== 3η λύση ===
Ως τελευταία λύση (που δεν ενδείκνυται γιατί πιθανόν ΘΑ ΧΑΘΟΥΝ σημαντικές εγγραφές) για να παρακάμψουμε το replication από παλιά logs σε περιπτώσεις πολλών συνεχώμενων διπλοεγγραφών από εκεί που ξεκινάει τα logs μετά την επανεκκίνηση ο 2ος server (εκτελούμε στον 2ο server)
mysql> show master status;
Καταγράφουμε το master log file και log position π.χ. mysql-bin.000544 και position 77465
(εκτελούμε στον 1ο server)
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
FIXME Συνεχίζουμε στο mysql-bin.000545 (Xάνοντας πολλές εντολές, δυστυχώς)
mysql> CHANGE MASTER TO MASTER_HOST='server.domainname.gr', MASTER_USER='slave2_user', MASTER_PASSWORD='mypasswprd', MASTER_LOG_FILE='mysql-bin.000545', MASTER_LOG_POS=4;
Query OK, 0 rows affected (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
==== Table is marked as crashed and should be repaired ====
**(ή Incorrect key file for table)**
Ακολουθούμε τις οδηγίες στο link http://www.spiration.co.uk/post/1221
mysql> use databasename;
mysql> check table table_name;
αν επιμένει το λάθος εκτελούμε
/usr/bin/myisamchk -r /var/lib/mysql/database_name/table_name.MYI
==== Client requested master to start replication from impossible position ή I/O Error====
Εάν ο client εμφανίσει το παρακάτω μύνημα τότε στον client εκτελούμε
mysql>show slave status \G;
..
..
Relay_Master_Log_File: mysql-bin.002669
..
Exec_Master_Log_Pos: 172858
Με τις παραπάνω πληροφορίες πηγαίνουμε στον master στον φάκελο /var/log/mysql και ανοίγουμε το αρχείο π.χ. mysql-bin.002669 με vi
Στο vi εκτελούμε την παρακάτω εντολή ώστε να πάμε στο byte 172858
: goto 172858
Βρισκόμαστε κατά πάσα πιθανότητα στο μέσο μιας εντολής mysql. Με διαδοχικές δοκιμές goto βρίσκουμε το 1ο byte στο οποίο ξεκινάει η επόμενη mysql εντολή π.χ. 172964
Επιβεβαιώνουμε με την εντολή **mysqlbinlog**. Θα πρέπει να εμφανίσει την επόμενη έγκυρη mysql εντολή
mysqlbinlog --base64-output=decode-rows --verbose --verbose --start-position=172964 /var/log/mysql/mysql-bin.002669
Για να βρούμε την επόμενη έγκυρη θέση εκτελούμε
/usr/lib/wad/mysql2 checkValidLogPos -p 172964 -l "mysql-bin.002669" |less
Οι εντολές που εκτελούνται είναι περίπου οι εξής
pos="$1"
log="$2"
while [ "1" ]; do
mysqlbinlog --base64-output=decode-rows --verbose --verbose --start-position=$pos /var/log/mysql/$log &> /dev/null
retval=$?
output=$(mysqlbinlog --base64-output=decode-rows --verbose --verbose --start-position=$pos /var/log/mysql/$log 2>&1 | grep -w at)
if [ "$retval" = "0" ] && [ "$output" ]; then
echo $output
break
else
(( pos++ ))
fi
done
Στον client επανεκκινούμε το replication από την νέα θέση
Εάν είχαμε σταματήσει στην **θέση 4** (στην αρχή δηλαδή και η mysqlbinlog δείχνει αποτέλεσμα από την αρχή του log δοκιμάζουμε πάντα πρώτα θέση **MASTER_LOG_POS=1**, αλλιώς την θέση που πιστεύουμε ότι είναι έγκυρη
mysql> stop slave; CHANGE MASTER TO MASTER_HOST='masterdomain.com', MASTER_USER='master_user', MASTER_PASSWORD='xxxxxx', MASTER_LOG_FILE='mysql-bin.002669', MASTER_LOG_POS=172964; start slave;
Βλέπουμε εαν πέτυχε εκτελώντας
mysql>show slave status \G;
Αν δεν τα καταφέρουμε θα πρέπει να προχωρήσουμε στο επόμενο log (χάνοντας δυστυχώς δεδομένα στο replication)
mysql> stop slave; CHANGE MASTER TO MASTER_HOST='masterdomain.com', MASTER_USER='master_user', MASTER_PASSWORD='xxxxxx', MASTER_LOG_FILE='mysql-bin.002670', MASTER_LOG_POS=4; start slave;
==== Relay log read failure: ====
(βλ. https://alexzeng.wordpress.com/2013/10/17/how-to-fix-mysql-slave-after-relay-log-corrupted/)
Σε περίπτωση που έχει γίνει corruption στο master log ή στο relay log εκτελούμε
mysql> show slave status \G
..
Master_Log_File: mysql-bin.003436
Read_Master_Log_Pos: 39029
Relay_Log_File: slave-relay.000718
Relay_Log_Pos: 1649436
Relay_Master_Log_File: mysql-bin.003434
..
Exec_Master_Log_Pos: 1660435
..
Προσοχή χρειαζόμαστε το **Relay_Master_Log_File: mysql-bin.003434** όχι το //Master_Log_File// και το **Exec_Master_Log_Pos: 1660435** όχι το //Read_Master_Log_Pos//
Στον master
mysqlbinlog /var/log/mysql/mysql-bin.003434
Στον slave
mysqlbinlog /var/lib/mysql/slave-relay.000718
Αν το πρόβλημα είναι στον slave
mysql> stop slave;
mysql> reset slave all;
mysql> CHANGE MASTER TO MASTER_HOST='hostname', MASTER_USER='slave1_user', MASTER_PASSWORD='password', MASTER_LOG_FILE='mysql-bin.003434', MASTER_LOG_POS=1660435;
mysql> start slave;
Δοκιμάζουμε πάλι με
mysql> show slave status \G
κάθως και ελέγχουμε για λάθη στην επανεκκίνηση της mysql
service mysql restart
tail -f /var/log/syslog
==== both a password and an authentication plugin problem ====
Σε συγκεκριμένο χρήστη κάθε λίγες μέρες ή και ώρες χανόταν η σύνδεση από την βάση. Αλλάζοντας ξανά τον κωδικό από το διαχειριστικό virtualmin επανερχόταν η σύνδεση και μετά από λίγες μέρες ξανά τα ίδια. Δοκιμάστηκαν να απενεργοποιηθούν sites μήπως είχε γίνει κάποιο hack σε mysql από security hole αλλά και πάλι εμφανιζόταν το πρόβλημα.
Στο /var/log/syslog εμφανίστηκε
mysqld[18424]: [Warning] 'user' entry '(username)@localhost' has both a password and an authentication plugin specified. The password will be ignored.
Η λύση βρέθηκε [[https://forums.cpanel.net/threads/mysql-errors-password-and-plugin-authentication-specified.641169/|εδώ]]
Εκτελέστηκαν
mysqlcheck mysql -p
mysql.column_stats OK
mysql.columns_priv OK
..
mysql.user OK
mysql.user_info OK
και
mysql -p -sse "SELECT user, host, plugin FROM mysql.user;" | awk '{ print $3 }' | sort | uniq -c
59
6 mysql_native_password
Το πρόβλημα ήταν το mysql_native_password και διορθώθηκε με τις εντολές μέσα στην mysql
UPDATE mysql.user SET plugin = '' WHERE plugin = 'mysql_native_password';
FLUSH PRIVILEGES;
Προληπτικά εκτελέστηκαν οι ίδιοι ελέγχοι και στον 2o mysql server χωρίς να βρεθεί αντίστοιχο πρόβλημα.
==== Table mysql.gtid_slave_pos doesn't exist ====
Βλ. http://alidba.blogspot.com/2017/05/table-mysqlgtidslavepos-doesnt-exist.html
==== mysql.innodb_table_stats doesn’t exist in engine. mysql.innodb_table_stats not found ====
Βλ. https://globedrill.com/table-mysql-innodb_index_stats-doesnt-exist-engine/
==== mysql.innodb_index_stats doesn’t exist in engine. mysql.innodb_index_stats not found ====
Βλ. https://globedrill.com/table-mysql-innodb_index_stats-doesnt-exist-engine/
===== Πηγές =====
* Master-Master Replication
* Ενεργοποίηση: http://www.howtoforge.com/mysql5_master_master_replication_debian_etch
* Κανόνες replication : http://dev.mysql.com/doc/refman/5.0/en/replication-rules.html
* Multi-Master MySQL Replication Guide : http://forums.mysql.com/read.php?26,169850,169850
* secure replication
* mysql docs : http://dev.mysql.com/doc/refman/5.0/en/secure-using-ssl.html
* quick howto on sarge : http://www.terryburton.co.uk/blog/2005/06/mysql-secure-replication-over-ssl-on.html
* ssh tunnels : http://www.jaisenmathai.com/blog/2008/10/10/secure-mysql-replication-between-colos-over-an-ssh-tunnel/
* Monitoring replication
* http://www.brandonchecketts.com/archives/checking-mysql-replication
* Επιδόσεις
* Περιγραφή ρυθμίσεων : http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/
* perl script : Έλεγχος και προτάσεις : http://www.debianadmin.com/check-your-mysql-server-performance-with-mysqltuner.html
* defrag : http://www.mydigitallife.info/2007/09/21/check-and-optimize-mysql-database-automatically-with-crontabcron/
* How To Back Up MySQL Databases Without Interrupting MySQL :
* http://www.howtoforge.com/back_up_mysql_dbs_without_interruptions
* Αντιμετώπιση προβλημάτων
* http://www.darkcoding.net/software/restarting-mysql-master-master-replication/
* Skipping the query : http://www.brandonchecketts.com/archives/2008/09
* http://www.spiration.co.uk/post/1221
* http://dev.mysql.com/doc/refman/5.0/en/change-master-to.html
* https://alexzeng.wordpress.com/2013/10/17/how-to-fix-mysql-slave-after-relay-log-corrupted/
* mysql_native : https://forums.cpanel.net/threads/mysql-errors-password-and-plugin-authentication-specified.641169/
* Versions : http://dev.mysql.com/doc/refman/5.0/en/releasenotes-cs.html
* FAQs
* http://www.modwest.com/help/kb6-242.html