距離上一次在segmentfault上發文章足足過了兩年時間,本身也已經從在日本留學進入到了工做崗位。選擇留在日本工做的理由其實本身也不是很清楚,只是不管身在哪裏,都只想作一個技術人員的理想至少如今並無改變。雖然目前爲止日本的IT行業不管在規模仍是技術層面都沒法和國內相提並論, 可是本身身邊仍是有不少大神的,本身在這段時間學到的東西不管如何也想和你們交流分享。還請你們多多指教。html
這個系列主要介紹本身工做上面關於MySQL的運用和研究。這個系列可能會偏向MySQL的底層和架構設計。對於開發方面的SQL語句設計以及數據表的設計等可能只會在介紹索引index的時候稍微說起。最後, 本系列涉及到的MySQL版本將主要集中在5.7和8.0。存儲引擎將只介紹Innodb。(主要Myasim等由於本身也沒接觸過-_-)mysql
說到爲何要學MySQL,先得說爲何IT公司要用MySQL。MySQL是開源的,你能夠在Github上隨意的瀏覽它的源碼, 給MySQL開發者送bug report。最主要它是免費的,不論是本身買服務器搭架構,仍是用雲服務,MySQL都是很好的選擇。雖然Oracle, SQL Server等在功能上可能更強大,可是對於中等規模的IT公司來講,MySQL每每已經足夠夠用了。git
那可能就有人會說, 如今誰還用關係型數據庫呀。確實如今的數據庫種類也是愈來愈多,NoSQL數據庫不斷提供着時髦的使用方法,對開發者來講也能更好的節省開發時間。Google的firestore(firebase)在最近也是被日本的開發者們視爲掌中寶。可是MySQL在這麼多年的企業級使用中,也性能調優方面,數據安全方面也變的不斷成熟。雖然如今的NoSQL很方便,可是當涉及到一些敏感或者重要數據的時候,爲了數據完整性和安全性,我會選擇MySQL。學習MySQL, 對於一個公司的發展或者對於一個技術人員的自我提高來講,其實都是一件頗有逼格的事情。(雖然好像沒什麼說服力)github
說了這麼對廢話,仍是快點進入今天的正題。Replicaiton多是學習數據庫架構的最基礎的東西了。Replication翻譯過來是複製,那就是複製數據庫,或者備份數據庫唄。那爲何須要複製數據庫呢?sql
想象一下下面一個場景,若是你只有一臺數據庫服務器,寫數據和讀數據全都經過這一個數據庫來作,當你的流量大了之後,這臺服務器的負載將愈來愈大, 發生故障的機率也愈來愈大。最後當這臺服務器掛掉之後,你的數據庫將變的不可用,整個應用死掉,那可能你就要寫好多故障報告了。docker
爲了減小上面發生的機率,咱們會使用replication,也就是主從架構。一臺master(主)服務器底下掛着幾臺slave(從)服務器。slave數據庫經過Replication和master數據庫保持數據同步。這時候master數據庫能夠只用來寫數據,讀數據的流量就能夠分散到slave數據庫服務器上了。可以前相比,服務器的負載獲得了分散。並且對於這個架構來講,容錯性也獲得了提升,當一臺slave服務器死掉之後,其餘或者的slave依然能夠接受流量,應用也不會中斷。master死掉之後,只要將一臺slave升級成master就好了(故障損害雖然不是0,但也能儘量的減小)。數據庫
在上圖的架構中,有一臺slave沒有讀操做也沒有寫操做,這個服務器能夠被用來按期獲取數據庫的snapshot。這樣作的話就不會由於常常獲取snapshot而對生產環境中的服務器形成影響。segmentfault
若是在master服務器中設置binlog有效的話,對數據庫有更新的操做都會被記錄在binlog文件中。(binlog文件將在以後的文章中作詳細介紹)
當slave鏈接到master服務器上時,master會建立一個binlog dump現成。而slave會建立一個IO線程和SQL線程。
具體的複製過程:安全
官方文檔:https://dev.mysql.com/doc/ref...bash
方便你們hands-on,可使用我準備的這個庫。(只要裝了docker,就能夠立馬動手了)
https://github.com/leeif/mysq...
在docker中啓動MySQL。
//啓動container : mysql57_master,mysql57_slave,mysql80_master,mysql80_slave docker-compose up -d //進入container裏 docker-compose exec mysql57_master(mysql57_slave) bash
數據庫用戶root,密碼爲root。
要使用replication,master須要存儲binlog。要存儲binlog,須要在master中設置指定log-bin(binlog的名字和存儲位置)。
※MySQL8.0開始,默認binlog是有效的,無需設置log-bin。
master的配置文件以下:
//mysql57_master root@76e96aaae65d:/# cat /etc/mysql/conf.d/config-file.cnf [mysqld] server-id = 0001 log-bin = /var/log/mysql/mysql-bin.log binlog_format = statement binlog_cache_size = 1M max_binlog_size = 200M root@76e96aaae65d:/#
爲了讓slave識別master,server-id也是必須的。
這時候咱們能夠查看一下master的情況。
//mysql57_master mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000003 | 154 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql>
能夠看到當前的binlog文件名是mysql-bin.000003, 而且當前的binlog記錄位置是154。
咱們嘗試在數據庫寫入一些數據。運行如下腳本。
//mysql57_master root@76e96aaae65d:/# cat /mysql_etc/mysql_data_generator.sh #!/bin/bash mysql -uroot -P 3306 -proot -D mysql -e "create database replication_test;" mysql -uroot -P 3306 -proot -D mysql -e "create table replication_test.test_table (id int not null auto_increment, name varchar(255), primary key (id));" data="" for i in {1..99}; do d="('name_$i'),"; data=$data$d; done mysql -uroot -P 3306 -proot -D mysql -e "insert into replication_test.test_table (name) values $data('name_100');" root@76e96aaae65d:/#
//mysql57_master //寫入了100條數據 mysql> select count(*) from replication_test.test_table; +----------+ | count(*) | +----------+ | 100 | +----------+ 1 row in set (0.00 sec) mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000003 | 2163 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql>
能夠看到binlog的參數發生了改變,說明數據庫被更新了,而且更新內容被寫入binlog文件裏了。
在slave服務器中,咱們要讓它和master實現同步。首先咱們用change master語句讓slave知道要從哪一個master複製數據。
//mysql57_slave mysql> change master to MASTER_HOST='10.1.0.100', -> MASTER_USER='root', -> MASTER_PASSWORD='root', -> MASTER_LOG_FILE='mysql-bin.000003', -> MASTER_LOG_POS=154; Query OK, 0 rows affected, 2 warnings (0.12 sec) mysql>
MASTER_LOG_POS設置成了寫入數據以前master的binlog位置。
(這裏咱們用了root用戶,在實際的運用場景中咱們通常會在master建立一個只用於replication的用戶,給它賦予只能replication的權限。)
啓動slave
//mysql57_slave mysql> start slave; Query OK, 0 rows affected (0.00 sec) mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.1.0.100 Master_User: root Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos: 2163 Relay_Log_File: ebd7cc002e88-relay-bin.000002 Relay_Log_Pos: 2329 Relay_Master_Log_File: mysql-bin.000003 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 2163 Relay_Log_Space: 2543 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: 50655a33-bda5-11e8-b007-02420a010064 Master_Info_File: /var/lib/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec) mysql>
... Slave_IO_Running: Yes Slave_SQL_Running: Yes ... Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: ...
從上面的參數重,能夠看到IO線程和SQL線程已經在運行,而且沒有出現錯誤,說明replication被成功創建。
查看數據同步狀況:
//mysql57_slave mysql> select count(*) from replication_test.test_table; +----------+ | count(*) | +----------+ | 100 | +----------+ 1 row in set (0.01 sec) mysql>
能夠看到master中的數據已經被同步了過來。
master中運行的process
//mysql57_master mysql> show processlist\G *************************** 1. row *************************** //binlog dump線程 Id: 7 User: root Host: mysql_learning_hard_mysql57_slave_1.mysql_learning_hard_test: db: NULL Command: Binlog Dump Time: 693 State: Master has sent all binlog to slave; waiting for more updates Info: NULL *************************** 2. row *************************** Id: 8 User: root Host: localhost db: NULL Command: Query Time: 0 State: starting Info: show processlist 2 rows in set (0.00 sec) mysql>
slave中運行的process
//mysql57_slave mysql> show processlist\G *************************** 1. row *************************** //IO線程 Id: 3 User: system user Host: db: NULL Command: Connect Time: 790 State: Waiting for master to send event Info: NULL *************************** 2. row *************************** //SQL線程 Id: 4 User: system user Host: db: NULL Command: Connect Time: 92220 State: Slave has read all relay log; waiting for more updates Info: NULL *************************** 3. row *************************** Id: 5 User: root Host: localhost db: NULL Command: Query Time: 0 State: starting Info: show processlist 3 rows in set (0.00 sec) mysql>
關於MySQL replication的原理以及基本用法就先說到這。下篇準備具體介紹一下show slave status中的參數, 經過這些參數咱們能夠實時把握當前主從複製的狀況。