Mysql的復制原理以及流程


MySQL復制概述

簡單來說就是保證主服務器(Master)和從服務器(Slave)的數據是一致性的,向Master插入數據后,Slave會自動從Master把修改的數據同步過來(有一定的延遲),通過這種方式來保證數據的一致性,就是Mysql復制

Mysql 復制能解決什么問題

一、高可用和故障切換
復制能夠幫避免MySql單點失敗,因為數據都是相同的,所以當Master掛掉后,可以指定一台Slave充當Master繼續保證服務運行,因為數據是一致性的(如果當插入Master就掛掉,可能不一致,因為同步也需要時間),當然這種配置不是簡單的把一台Slave充當Master,畢竟還要考慮后續的Salve同步Master

二、負載均衡
因為讀寫分離也算是負載均衡的一種,所以就不單獨寫了,因為一般都是有多台Slave的,所以可以將讀操作指定到Slave服務器上(需要代碼控制),然后再用負載均衡來選擇那台Slave來提供服務,同時也可以吧一些大量計算的查詢指定到某台Slave,這樣就不會影響Master的寫入以及其他查詢

三、數據備份
一般我們都會做數據備份,可能是寫定時任務,一些特殊行業可能還需要手動備份,有些行業要求備份和原數據不能在同一個地方,所以主從就能很好的解決這個問題,不僅備份及時,而且還可以多地備份,保證數據的安全

四、業務模塊化
可以一個業務模塊讀取一個Slave,再針對不同的業務場景進行數據庫的索引創建和根據業務選擇MySQL存儲引擎, 不同的slave可以根據不同需求設置不同索引和存儲引擎

主從配置需要注意的點
(1)主從服務器操作系統版本和位數一致;
(2) Master和Slave數據庫的版本要一致;
(3) Master和Slave數據庫中的數據要一致;
(4) Master開啟二進制日志,Master和Slave的server_id在局域網內必須唯一;

復制如何工作

復制有三個步驟:
1、Master將數據改變記錄到二進制日志(binary log)中,也就是配置文件log-bin指定的文件,這些記錄叫做二進制日志事件(binary log events)
2、Slave通過I/O線程讀取Master中的binary log events並寫入到它的中繼日志(relay log)
3、Slave重做中繼日志中的事件,把中繼日志中的事件信息一條一條的在本地執行一次,完成數據在本地的存儲,從而實現將改變反映到它自己的數據(數據重放)

 
mysql復制過程.png

第一步Master記錄二進制日志, 每次提交事務完成數據更新前,Master將數據更新的時間記錄到二進制日志中,MySql會按事務提交的順序而非每條語句的執行順序來記錄二進制日志。再記錄二進制日志后,主庫會告訴存儲引擎可以提交事務了。

第二步,Slave將Master的二進制日志復制到本地的中繼日志中,首先,Slave會啟動一個工作線程,成為I/O線程, I/O線程跟Master建立一個普通的客戶端鏈接,然后再Master上啟動一個特殊的二進制轉儲(binlog dump)線程(該線程沒有對應的SQL命令),這個二進制轉儲線程會讀取主庫上的二進制日志中的事件。從庫I/O線程將接受到時間記錄到中繼日志中。

第三步從庫的SQL線程執行最后異步,該線程的從中繼日志中讀取事件並在從庫執行,從而實現從庫數據更新。

這種復制架構實現了獲取事件和重放事件的解偶,允許這兩個過程異步進行。也就是說I/O線程能夠獨立於SQL線程之外工作。但這種架構頁限制了復制的過程,其中最重要的一點是主庫上並發運行的查詢再從庫只能串行化執行,因為只有一個SQL線程重放中繼日志中的事件。這是很多工作負載的性能瓶頸所在。因為始終受限於單線程。

復制類型

1、基於語句的復制
在Master上執行的SQL語句,在Slave上執行同樣的語句。MySQL默認采用基於語句的復制,效率比較高。一旦發現沒法精確復制時,會自動選着基於行的復制

2、基於行的復制
把改變的內容復制到Slave,而不是把命令在Slave上執行一遍。從MySQL5.0開始支持

3、混合類型的復制
默認采用基於語句的復制,一旦發現基於語句的無法精確的復制時,就會采用基於行的復制

相應地,binlog的格式也有三種:STATEMENT,ROW,MIXED。

啟動多個Mysql實例

要配置主從復制,我們在本機開多個Mysql實例來操作就可以了,讓他們監聽不同端口
多開實例可以看我另一篇教程:同一台Ubuntu 啟動多個mysql

主從復制配置

現在我們兩個實例Mysql
server1 : 127.0.0.1 3306 master
server2 : 127.0.0.1 3301 slave

配置master

在主庫創建一個復制帳號,這個帳號是給從庫的IO線程建立連接到主庫時用的,從庫會用這個帳號連接主庫並讀取主庫的二進制日志:

grant replication slave, replication client on *.* to 'repl'@'localhost' identified by '123456'; 

主庫添加配置:

# 設置server_id,一般設置為IP, 要獨一無二的 server-id = 10 # 開啟二進制日志功能,最好是絕對路徑 log_bin = /var/log/mysql/mysql-bin.log # 主從復制的格式(mixed,statement,row,默認格式是statement) binlog_format=mixed # 二進制日志自動刪除/過期的天數。默認值為0,表示不自動刪除。 expire_logs_days=7 # 為每個session 分配的內存,在事務過程中用來存儲二進制日志的緩存 binlog_cache_size=1M # 復制過濾:不需要備份的數據庫,不輸出(mysql庫一般不同步) binlog-ignore-db=mysql 

啟用二進制日志后,重啟后, show master status; 可以看到二進制相關信息

mysql> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000008 | 107 | | | +------------------+----------+--------------+------------------+ 

添加從庫配置

# 設置server_id,一般設置為IP, 要獨一無二的 server-id = 10 log_bin = /var/log/mysql/mysql-bin.log # 中繼日志路徑 relay_log = /home/mysql/3301/mysql-relay-bin # 允許從庫將其重放的事件也記錄到自身的二進制日志中 log_slave_updates = 1 read_only = 1 

從庫開啟復制

mysql>  CHANGE MASTER TO
MASTER_HOST='$host', MASTER_USER='repl', MASTER_PASSWORD='123456', MASTER_LOG_FILE='msyql-bin.00001', MASTER_LOG_POS=0; 

MASTER_LOG_POS設為0,是從日志開頭開始復制,MASTER_LOG_FILE是master的二進制文件

# 啟動復制
mysql> start slave; # 查看復制狀態 mysql> show slave status; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 127.0.0.1 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000008 Read_Master_Log_Pos: 107 Relay_Log_File: mysql-relay-bin.000020 Relay_Log_Pos: 253 Relay_Master_Log_File: mysql-bin.000008 Slave_IO_Running: Yes Slave_SQL_Running: Yes Seconds_Behind_Master: 0 Master_Server_Id: 10 # Slave_IO_Running: Yes,Slave_SQL_Running: Yes 說明同步正常進行 # Seconds_Behind_Master: 0 就是完全同步了 

這時就完成了主從復制的配置,當主服務器有更新,從庫也會更新。

我們還可以從線程列表看出復制線程,主庫上可以看到由從庫I/O線程向主庫發起的連接。

mysql> show processlist \G
*************************** 1. row *************************** Id: 44 User: repl Host: localhost:32866 db: NULL Command: Binlog Dump Time: 73032 State: Master has sent all binlog to slave; waiting for binlog to be updated Info: NULL 

同樣,我們看看從庫的線程,有兩個,一個I/O線程,一個SQL線程:

mysql> show processlist \G
*************************** 1. row *************************** Id: 4 User: system user Host: db: NULL Command: Connect Time: 73422 State: Waiting for master to send event Info: NULL *************************** 2. row *************************** Id: 5 User: system user Host: db: NULL Command: Connect Time: 72417 State: Slave has read all relay log; waiting for the slave I/O thread to update it Info: NULL 

這兩個線程都是再system user 帳號下運行,I/O線程是寫日志到中繼日志的線程, SQL線程是重放SQL的線程。

從已經運行已久的服務器開始復制

那么,至此我們已經完成了Mysql的主從配置。
但是上面是配置兩台剛好安裝號的服務器,數據相同,並且知道當前主庫二進制日志。
更典型的案例是,一個運行已經一段時間的主庫,要用一台新安裝的從庫與之同步,此時這台從庫還沒有數據。
所以我們得想辦法,線初始化從庫: 從主庫復制數據、使用最近依次備份來啟動從庫。
這需要三個條件來讓主庫和從庫保持同步:

復制數據到從庫

mysqldump  --single-transaction --all-databases --master-data=1 -uroot -p123456|mysql -S /home/mysql/3301/mysqld.sock -uroot -p123456



鏈接:https://www.jianshu.com/p/63c1a1babfd1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM