[MySQL進階之路][No.0001] MySQL的Replication基礎

前記

距離上一次在segmentfault上發文章足足過了兩年時間,本身也已經從在日本留學進入到了工做崗位。選擇留在日本工做的理由其實本身也不是很清楚,只是不管身在哪裏,都只想作一個技術人員的理想至少如今並無改變。雖然目前爲止日本的IT行業不管在規模仍是技術層面都沒法和國內相提並論, 可是本身身邊仍是有不少大神的,本身在這段時間學到的東西不管如何也想和你們交流分享。還請你們多多指教。html

關於這個系列

這個系列主要介紹本身工做上面關於MySQL的運用和研究。這個系列可能會偏向MySQL的底層和架構設計。對於開發方面的SQL語句設計以及數據表的設計等可能只會在介紹索引index的時候稍微說起。最後, 本系列涉及到的MySQL版本將主要集中在5.7和8.0。存儲引擎將只介紹Innodb。(主要Myasim等由於本身也沒接觸過-_-)mysql

爲何要學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

數據庫的複製(Replication)

說了這麼對廢話,仍是快點進入今天的正題。Replicaiton多是學習數據庫架構的最基礎的東西了。Replication翻譯過來是複製,那就是複製數據庫,或者備份數據庫唄。那爲何須要複製數據庫呢?sql

想象一下下面一個場景,若是你只有一臺數據庫服務器,寫數據和讀數據全都經過這一個數據庫來作,當你的流量大了之後,這臺服務器的負載將愈來愈大, 發生故障的機率也愈來愈大。最後當這臺服務器掛掉之後,你的數據庫將變的不可用,整個應用死掉,那可能你就要寫好多故障報告了。docker

爲了減小上面發生的機率,咱們會使用replication,也就是主從架構。一臺master(主)服務器底下掛着幾臺slave(從)服務器。slave數據庫經過Replication和master數據庫保持數據同步。這時候master數據庫能夠只用來寫數據,讀數據的流量就能夠分散到slave數據庫服務器上了。可以前相比,服務器的負載獲得了分散。並且對於這個架構來講,容錯性也獲得了提升,當一臺slave服務器死掉之後,其餘或者的slave依然能夠接受流量,應用也不會中斷。master死掉之後,只要將一臺slave升級成master就好了(故障損害雖然不是0,但也能儘量的減小)。
圖片描述數據庫

在上圖的架構中,有一臺slave沒有讀操做也沒有寫操做,這個服務器能夠被用來按期獲取數據庫的snapshot。這樣作的話就不會由於常常獲取snapshot而對生產環境中的服務器形成影響。segmentfault

MySQL的Replication原理

圖片描述

若是在master服務器中設置binlog有效的話,對數據庫有更新的操做都會被記錄在binlog文件中。(binlog文件將在以後的文章中作詳細介紹)
當slave鏈接到master服務器上時,master會建立一個binlog dump現成。而slave會建立一個IO線程和SQL線程。
具體的複製過程:安全

  1. master出現數據庫更新,在binlog中記錄這個更新操做
  2. binlog dump線程binlog中有更新,讀取binlog並將它傳到鏈接到的slave。
  3. slave中的IO Thread接受這個binlog,將這個binlog記錄在relay log文件中。
  4. slave中的SQL線程從relay log中讀取這個更新操做,經過SQL操做將這個更新反應到數據庫中
  5. 經過上面的一系列操做,slave和master能夠保持一致。

官方文檔: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。

master

要使用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

在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中的數據已經被同步了過來。

查看關於replicaiton的線程

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中的參數, 經過這些參數咱們能夠實時把握當前主從複製的狀況。

相關文章
相關標籤/搜索