『壹』 mysql怎麼實現主從復制
mysql主從復制的配置
1. 准備工作
有兩台MySQL資料庫伺服器Master和slave,Master為主伺服器,slave為從伺服器。
初始狀態時,Master和slave中的數據信息相同,當Master中的數據發生變化時,slave也跟著發生相應的變化,使得master和slave的數據信息同步,達到備份的目的。
要點:
負責在主、從伺服器傳輸各種修改動作的媒介是主伺服器的二進制變更日誌,這個日誌記載著需要傳輸給從伺服器的各種修改動作。
因此,主伺服器必須激活二進制日誌功能。從伺服器必須具備足以讓它連接主伺服器並請求主伺服器把二進制變更日誌傳輸給它的許可權。
環境:
Master和slave的MySQL資料庫版本同為5.6.28
操作系統:CentOS release 6.5 (Final)
IP地址:master:120.77.153.204 slave:120.77.148.74
2. master的配置
(1) 創建復制帳號
mysql> CREATE USER'masterslave'@'120.77.148.74' IDENTIFIED BY '123456';Query OK, 0 rows affected (0.00 sec)
(2) 主從復制授權
GRANT REPLICATION SLAVE,RELOAD,SUPER ON *.* TO 'masterslave'@'120.77.148.74' IDENTIFIED BY '123456';
(3) 拷貝數據
(假如是你完全新安裝mysql主從伺服器,這一步就不需要。因為新安裝的master和slave有相同的數據)
關停Master伺服器,將Master中的數據拷貝到B伺服器中,使得Master和slave中的數據同步,並且確保在全部設置操作結束前,
禁止在Master和slave伺服器中進行寫操作,使得兩資料庫中的數據一定要相同!
3. 修改配置文件
對master進行配置,包括打開二進制日誌,指定唯一的servr ID
[root@myserver ~]# find / -type f -name my.cnf/usr/my.cnf[root@myserver ~]# vim /usr/my.cnfserver_id=1log-bin=mysql-bin
4. 重啟master,運行SHOW MASTER STATUS,輸出如下:
[root@myserver ~]# service mysql stopShutting down MySQL.... SUCCESS! [root@myserver ~]# service mysql startStarting MySQL. SUCCESS! [root@myserver ~]# mysql -uroot -pEnter password: Welcome to the MySQL monitor. Commands end with ; or g.Your MySQL connection id is 3Server version: 5.6.28-log MySQL Community Server (GPL)Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.mysql> mysql> show master status; mysql> show master status;+------------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+------------------+----------+--------------+------------------+-------------------+| mysql-bin.000001 | 120 | | | |+------------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)mysql>
配置slave
1. 修改my.cnf文件
[root@wenhaijin mysql-5.6.28]# find / -type f -name my.cnf/usr/my.cnf[root@wenhaijin mysql-5.6.28]# vim /usr/my.cnf log_bin = mysql-binserver_id = 2relay_log = mysql-relay-binlog_slave_updates = 1read_only = 1
server_id是必須的,而且唯一。
slave沒有必要開啟二進制日誌,但是在一些情況下,必須設置。
例如,如果slave為其他slave的master,必須設置bin_log。
在這里,我們開啟了二進制日誌,而且顯示了命名(默認名稱為hostname,但是,如果hostname改變則會出現問題)。
relay_log配置中繼日誌,log_slave_updates表示slave將復制事件寫進自己的二進制日誌(後面會看到它的用處)。
有些人開啟了slave的二進制日誌,卻沒有設置log_slave_updates,然後查看slave的數據是否改變,這是一種錯誤的配置。
所以,盡量使用read_only,它防止改變數據(除了特殊的線程)。但是,read_only並是很實用,特別是那些需要在slave上創建表的應用。
2. 啟動slave
接下來就是讓slave連接master,並開始重做master二進制日誌中的事件。
你不應該用配置文件進行該操作,而應該使用CHANGE MASTER TO語句,該語句可以完全取代對配置文件的修改,而且它可以為slave指定不同的master,而不需要停止伺服器。如下:
mysql> CHANGE MASTER TO MASTER_HOST='120.77.153.204', -> MASTER_USER='masterslave', -> MASTER_PASSWORD='123456', -> MASTER_LOG_FILE='mysql-bin.000001', -> MASTER_LOG_POS=0;Query OK, 0 rows affected, 2 warnings (0.01 sec)
MASTER_LOG_POS的值為0,因為它是日誌的開始位置。
你可以用SHOW SLAVE STATUS語句查看slave的設置是否正確:
mysql> SHOW SLAVE STATUSG*************************** 1. row *************************** Slave_IO_State: Master_Host: 120.77.153.204 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 4 Relay_Log_File: mysql-relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: No Slave_SQL_Running: No 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: 4 Relay_Log_Space: 120 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: NULLMaster_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: 0 Master_UUID: Master_Info_File: /var/lib/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: 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: 01 row in set (0.00 sec)
Slave_IO_State, Slave_IO_Running, 和Slave_SQL_Running是No
表明slave還沒有開始復制過程。日誌的位置為4而不是0,這是因為0隻是日誌文件的開始位置,並不是日誌位置。
實際上,MySQL知道的第一個事件的位置是4。
為了開始復制,你可以運行START SLAVE;
mysql> START SLAVE; mysql> SHOW SLAVE STATUSG;*************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 120.77.153.204 Master_User: masterslave Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 1762 Relay_Log_File: mysql-relay-bin.000001 Relay_Log_Pos: 1925 Relay_Master_Log_File: mysql-bin.000001 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: 1762 Relay_Log_Space: 2098 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: 0Master_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: 4df9a165-03fd-11e7-b234-00163e0243e8 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 the slave I/O thread to update it 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: 01 row in set (0.00 sec)
在這里主要是看:
Slave_IO_Running=Yes
Slave_SQL_Running=Yes
slave的I/O和SQL線程都已經開始運行,而且Seconds_Behind_Master不再是NULL。
日誌的位置增加了,意味著一些事件被獲取並執行了。
如果你在master上進行修改,你可以在slave上看到各種日誌文件的位置的變化,同樣,你也可以看到資料庫中數據的變化。
你可通過show processlistG;查看master和slave上線程的狀態。在master上,你可以看到slave的I/O線程創建的連接。
3. 授權masterslave用戶遠程登入,然後使用navicat遠程連接
說明已經成功實現mysql的主從復制。
『貳』 如何實現兩個mysql資料庫之間的主從同步
配置主的配置文件
vi /etc/my.cnf
正常,說明主從搭建成功
『叄』 MySQL 主從,5 分鍾帶你掌握
MySQL 主從一直是面試常客,裡面的知識點雖然基礎,但是能回答全的同學不多。
比如樓哥之前面試小米,就被問到過主從復制的原理,以及主從延遲的解決方案,因為回答的非常不錯,給面試官留下非常好的印象。你之前面試,有遇到過哪些 MySQL 主從的問題呢?
所謂 MySQL 主從,就是建立兩個完全一樣的資料庫,一個是主庫,一個是從庫, 主庫對外提供讀寫的操作,從庫對外提供讀的操作 ,下面是一主一從模式:
對於資料庫單機部署,在 4 核 8G 的機器上運行 MySQL 5.7 時,大概可以支撐 500 的 TPS 和 10000 的 QPS, 當遇到一些活動時,查詢流量驟然,就需要進行主從分離。
大部分系統的訪問模型是讀多寫少,讀寫請求量的差距可能達到幾個數量級,所以我們可以通過一主多從的方式, 主庫只負責寫入和部分核心邏輯的查詢,多個從庫只負責查詢,提升查詢性能,降低主庫壓力。
MySQL 主從還能做到服務高可用,當主庫宕機時,從庫可以切成主庫,保證服務的高可用,然後主庫也可以做數據的容災備份。
整體場景總結如下:
MySQL 的主從復制是依賴於 binlog 的,也就是記錄 MySQL 上的所有變化並以二進制形式保存在磁碟上二進制日誌文件。
主從復制就是將 binlog 中的數據從主庫傳輸到從庫上,一般這個過程是非同步的,即主庫上的操作不會等待 binlog 同步的完成。
詳細流程如下:
當主庫和從庫數據同步時,突然中斷怎麼辦?因為主庫與從庫之間維持了一個長鏈接,主庫內部有一個線程,專門服務於從庫的這個長鏈接的。
對於下面的情況,假如主庫執行如下 SQL,其中 a 和 create_time 都是索引:
我們知道,數據選擇了 a 索引和選擇 create_time 索引,最後 limit 1 出來的數據一般是不一樣的。
所以就會存在這種情況:在 binlog = statement 格式時,主庫在執行這條 SQL 時,使用的是索引 a,而從庫在執行這條 SQL 時,使用了索引 create_time,最後主從數據不一致了。
那麼我們改如何解決呢?
可以把 binlog 格式修改為 row,row 格式的 binlog 日誌記錄的不是 SQL 原文,而是兩個 event:Table_map 和 Delete_rows。
Table_map event 說明要操作的表,Delete_rows event用於定義要刪除的行為,記錄刪除的具體行數。 row 格式的 binlog 記錄的就是要刪除的主鍵 ID 信息,因此不會出現主從不一致的問題。
但是如果 SQL 刪除 10 萬行數據,使用 row 格式就會很占空間的,10 萬條數據都在 binlog 裡面,寫 binlog 的時候也很耗 IO。但是 statement 格式的 binlog 可能會導致數據不一致。
設計 MySQL 的大叔想了一個折中的方案,mixed 格式的 binlog,其實就是 row 和 statement 格式混合使用, 當 MySQL 判斷可能數據不一致時,就用 row 格式,否則使用就用 statement 格式。
有時候我們遇到從資料庫中獲取不到信息的詭異問題時,會糾結於代碼中是否有一些邏輯會把之前寫入的內容刪除,但是你又會發現,過了一段時間再去查詢時又可以讀到數據了,這基本上就是主從延遲在作怪。
主從延遲,其實就是「從庫回放」 完成的時間,與 「主庫寫 binlog」 完成時間的差值, 會導致從庫查詢的數據,和主庫的不一致 。
談到 MySQL 資料庫主從同步延遲原理,得從 MySQL 的主從復制原理說起:
總結一下主從延遲的主要原因 :主從延遲主要是出現在 「relay log 回放」 這一步,當主庫的 TPS 並發較高,產生的 DDL 數量超過從庫一個 SQL 線程所能承受的范圍,那麼延時就產生了,當然還有就是可能與從庫的大型 query 語句產生了鎖等待。
我們一般會把從庫落後的時間作為一個重點的資料庫指標做監控和報警,正常的時間是在毫秒級別,一旦落後的時間達到了秒級別就需要告警了。
解決該問題的方法,除了縮短主從延遲的時間,還有一些其它的方法,基本原理都是盡量不查詢從庫。
具體解決方案如下:
在實際應用場景中,對於一些非常核心的場景,比如庫存,支付訂單等,需要直接查詢從庫,其它非核心場景,就不要去查主庫了。
兩台機器 A 和 B,A 為主庫,負責讀寫,B 為從庫,負責讀數據。
如果 A 庫發生故障,B 庫成為主庫負責讀寫,修復故障後,A 成為從庫,主庫 B 同步數據到從庫 A。
一台主庫多台從庫,A 為主庫,負責讀寫,B、C、D為從庫,負責讀數據。
如果 A 庫發生故障,B 庫成為主庫負責讀寫,C、D負責讀,修復故障後,A 也成為從庫,主庫 B 同步數據到從庫 A。
『肆』 資料庫讀寫分離如何保證主從一致性
當我們的資料庫壓力主鍵變大的時候,我們會嘗試增加一些從節點來分攤主節點的查詢壓力。而一般來說,我們是用一主多從的結構來作為讀寫分離的基本結構。
而一般來說我們有兩種常用的方法來實現讀且分離架構:
客戶端直接分離
這種方式是由客戶端,或者我們的微服務直接進行資料庫的讀寫選擇。將讀庫選擇路由到主庫上進行,將查詢路由到從主庫上進行。
這種方式的優點在於因為是直連所以性能比較高,但是需要由業務團隊了解資料庫的實例細節,當資料庫做調整的時候就需要業務側同步改造。
使用數據中間件代理
這種方式是由一層代理層對數據的讀寫做分發,業務層將所有的請求都通過代理來實現。
這種方式的優點在於對於業務層不需要感知到資料庫的存在,但問題在於數據中間件的性能要求較高,還需要專人來進行優化和維護,整體架構較為復雜。
但是我們發現,盡管這兩種方式各有優劣。但核心都是通過數據的寫入、查詢請求的路由而實現的,那麼這就會引發標題的問題:
主備同步存在延遲,所以在延遲時間內對插入的內容進行查詢則無法查詢到最新提交的事務。
那麼如何保證主從一致性的問題,其實就變成了如何處理主從延遲的問題。
根據項目的大小,團隊的規模以及主機的部署模式。我們處理問題的方法也有很多種。
最簡單強硬的就是強制讀主庫。
一般情況下我們在不同的查詢中會有不同程度的一致性要求。我們可以將需要保證數據一致性的請求配置強制查詢主庫,而對於無強依賴的查詢請求仍然查詢備庫。
盡管這個方案不是很優雅,但是是最簡單實現的方法,並且在Spring等框架的支持下一般只需要加一個註解就能實現。但這個方法的問題也是顯而易見的,如果存在大量的強一致性要求的查詢語句,則相當於沒有進行讀寫分離與擴展。那麼這種方法就會導致系統在資料庫層面沒有有效的擴展手段了。
由於問題產生的來源是主從延遲,所以在下一次查詢的時候進行一段時間的等待以彌補這種延遲即可。
所以在進行主庫的數據插入之後,讓資料庫數據連接或者對應的執行線程等待一段時間後返回。通過等待時間來消化掉主從備份的延遲時間。但是這個方法也有一些問題比如:這個等待時間一般是固定的,即便主從已經無延遲了也會繼續等待到時間結束;如果在服務高峰時期,有可能數據在等待時間結束後仍然沒有完成同步則仍然會存在一致性問題。
但這種方法優雅的地方是可以配合業務來進行實現,舉例來說當用戶下單之後,通過下單送卷或者下單抽獎的方式從前端拖住用戶,從而當用戶在一次連續操作中再次查詢自己訂單的時候中間必然會間隔一定時間,也就讓需要再次查詢數據的時候保證了數據的一致性。
上述兩種方案看起來可能不那麼「技術」,感覺有點投機取巧。那麼下面咱們可以分兩種情況來討論用更高技術的方法如何實現一致性。
對於主從復制來說,是當主庫完成一個事務後,通知給從庫,當從庫接受到後,則主庫完成返回客戶端。所以當主庫完成事務後,僅能確保從庫已經接受到了,但是不能保證從庫執行完成,也就是導致了主從備份延遲。
但是從庫執行數據是有進度的,而這個進度是可以通過show slave status語句中的seconds_behind_master來進行描述,這個參數描述從庫落後了主庫數據多少秒,當這個參數為0時,我們可以認為從庫和主庫已經基本上沒有延遲了,那麼這時候就可以查詢請求。
但seconds_behind_master是秒級的,所以只能大概地判斷,由於精度較低,所以還是可能出現不一致的情況。
如果要求精準執行的話,我們可以比較同步文件的執行記錄,具體來說是:
所以當Relay_Master_Log_File和Exec_Master_Log_Pos和其一致的時候,就說明從庫的已執行數據已經追上主庫了,那麼這時就可以說保證了主從一致性了
但是比較同步文件的執行記錄方法的問題在於,如果當前的這個事務的binlog尚未傳入到從庫,即Master_Log_File和Read_Master_Log_Pos未更新,也就無法保證從庫已經包含最新的主庫事務了。
而為了保證在一主一備的情況下,從庫里一定接受到數據了,也就是Master_Log_File和Read_Master_Log_Pos中的數據是和主庫一致的,我們可以開啟semi-sync replication半同步復制。
半同步復制的原理是在主庫提交事務前先將binlog發送給從庫,然後當從庫接受後返回一個應答,主庫只有在接受到這個應答之後才返回事務執行完成。這樣就可以保證從庫的Master_Log_File和Read_Master_Log_Pos與主庫是一致的,從而解決了主從一致的問題。
半同步復制可以解決一主一備的情況,但是當一主多備的時候,只要主庫接受到一個從庫的應答,就會返回事務執行完成。而這時當請求打到未完成同步的從庫上時就會發生主從延遲。
所以針對一主多備的情況,我們可以將目光集中在執行查詢的從庫上,即確保 我們即將查詢的備庫已經執行了我們預期的事務。 那麼我們的問題就變成兩部分:1. 確認主庫事務,2. 查詢數據條件。
確認主庫事務
當我們提交完一個事務後,可以通過執行show master status來得到主庫中的數據事務文件(File)和位置記錄(Position)。
查詢數據條件
當我們要查詢從庫數據的時候,我們可以通過語句select master_pos_wait(File, Position, 1);來查詢當前是否已經執行到了該記錄(當返回值>=0的時候說明已經執行過了)。其中最後的數字1表示阻塞時長。
通過先確認主庫事務記錄,再判確認備庫是否已經執行了了主庫對應的事務。
但是可以發現,這種方法要求查詢的時候知道主庫的事務信息,對場景有很大的限制。
主從一致的問題源自主從延遲,所以我們就是從如何消除延遲來解決問題。簡單點的方案我們可以不走備庫、或者直接等待一段時間來忽略延遲的影響。在一主一備的情況下我們可以粗力度的用seconds_behind_master來判斷或者用Relay_Master_Log_File和Exec_Master_Log_Pos來判斷。而當一主多從的情況下我們則需要在查詢前傳入主庫執行的事務記錄才能保證數據一致性。
可以看出,當數據規模和部署方式變更的時候,好的解決方案將會越來越多。我認為根據實際業務情況選擇最合適的方法才是最重要的。