mysql 複製 高效能mysql筆記
mysql 複製的兩種方式
1:行復制(對於網路延遲比較高的行復制也可以工作(因為基於行復制所以不會受到複製延遲帶來的語句錯誤影響),行復制資料多會對寬頻造成壓力。
2:語句複製(也稱為邏輯複製)
mysql的複製是向後相容(向前不相容)的新版本的資料庫可做為老版本的備庫
複製可以解決的問題
1,資料分佈
在不同的地理位置來分佈資料備份,例如不同的資料中心。
2,負載均衡
通過MySQL複製可以將讀操作分佈到多個伺服器上實現負載均衡。
3,備份
對於備份來說,複製是一項很有意義的技術補充,但複製既不是備份也不能夠取代備份。
4,高可用性和故障切換
避免MySQL單點失敗,縮短宕機時間。
5,MySQL升級測試
使用一個更高版本的MySQL作為備庫,保證在升級全部例項前,查詢能夠在備庫按照預期執行。
複製如何工作
簡易流程:
1,在主庫上把資料更改記錄到二進位制日誌(Binary Log)中(這些記錄被稱為二進位制日誌事件)。
2,備庫將主庫上的日誌複製到自己的中繼日誌(Relay Log)中。
3,備庫讀取中繼日誌中的事件,將其重放到備庫資料之上。
具體流程:
第一步是在主庫上記錄二進位制日誌。每次提交事務完成資料更新前,主庫將資料更新的事件記錄到二進位制日誌中。在記錄進二進位制日誌後,主庫後告訴儲存引擎可以提交事務了(MySQL會按事務提交的順序而非每條語句的執行順序來記錄二進位制日誌)。
第二步備庫將主庫的二進位制日誌複製到其本地的中繼日誌中首先,首先,備庫會啟動一個工作執行緒(稱為I/O執行緒)I/O執行緒與主庫建立一個普通客戶端連線,然後在主庫上啟動一個二進位制
轉儲(binlog dump )執行緒(該執行緒沒有對應sql命令),這個二進位制轉儲執行緒會讀取主庫上的二進位制日誌事件,他不會對事件輪訓,如果該執行緒追上了主庫,它將進入休眠狀態直到主庫傳送訊號通知有新的二進位制日誌事件才會被喚醒,備庫的i/o執行緒會將接受到的事件記錄到中繼日誌中。
第三步該執行緒從中繼日誌中讀取事件並在備庫執行,從而實現備庫資料的更新。當SQL執行緒追趕上I/O執行緒是,中繼日誌通常已經在系統快取中,所以讀取中繼日誌開銷很低sql執行緒可以通過配置把更新事件記錄到自己的二進位制日誌
配置複製
1,複製賬號。
在主庫和備庫都建立該賬號:
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*
-> TO [email protected]'192.168.0.%' IDENTIFIED BY 'p4ssword';
其中:
- REPLICATION SLAVE :授予slave庫連線master後,可執行replicate操作的許可權。
- REPLICATION CLIENT :複製使用者可以使用 SHOW MASTER STATUS, SHOW SLAVE STATUS和 SHOW BINARY LOGS來確定複製狀態。
- 在主庫和備庫都建立賬號原因:方便切換slave和master,賬戶不需要做任何改動。
- 對同一賬號賦予REPLICATION SLAVE和REPLICATION CLIENT 原因:方便監控管理不必要為了監控再建立一個賬號。
2,配置主庫和備庫。
配置master:
在配置檔案my.cnf加入以下下值:
1,開啟二進位制日誌。
2,指定唯一的servr ID。
log-bin=mysql-bin
server-id=10
3,重啟MySQL。
配置slave:
Slave的配置與master類似,你同樣需要重啟slave的MySQL。如下:
log_bin = mysql-bin
server_id = 2
relay_log = mysql-relay-bin
log_slave_updates = 1
read_only = 1
-
server_id:(預設名稱是主機名)必須指定並且唯一。
-
relay_log:指定中繼日誌的位置和命名。
-
log_slave_updates:表示允許備庫將複製執行的事件也記錄到自身的二進位制日誌中。
有時開啟slave的二進位制日誌,卻沒有設定log_slave_updates,會碰到奇怪現象,如當配置錯誤時可能會導致備庫資料被修改。最好使用使用read_only配置選項,該選項會阻止沒有任何特權許可權的執行緒修改資料。但read_only通常不是很實用,特別是那些需要在slave上建立表的應用。
注意:
- 某些mysql版本不允許server-id的值為1 。
- 不要再my.cnf設定master_prot master_host ,在my.cnf中配置後無法線上重新設定master_prot。
啟動複製:
語句:
mysql> CHANGE MASTER TO MASTER_HOST='server1',
MASTER_USER='repl',
MASTER_PASSWORD='p4ssword',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=0;
MASTER_LOG_POS=0: 是指要從日誌開頭讀取
校驗:用SHOW SLAVE STATUS語句檢視slave的設定是否正確
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: server1
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
...omitted...
Seconds_Behind_Master: NULL
開始複製執行:
mysql> START SLAVE;
執行SHOW SLAVE STATUS檢視輸出結果:
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: server1
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 164
Relay_Log_File: mysql-relay-bin.000001
Relay_Log_Pos: 164
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...omitted...
Seconds_Behind_Master: 0
注意,slave的I/O和SQL執行緒都已經開始執行,而且Seconds_Behind_Master不再是NULL。日誌的位置增加了,意味著一些事件被獲取並執行了。如果你在master上進行修改,可以在slave上看到各種日誌檔案的位置的變化,也可以看到資料庫中資料的變化。
檢查執行緒:show processlist
新增新的slave資料庫:
需要三個條件讓主備保持同步:
-
某個時間點快照
-
主庫當前二進位制日誌檔案和主庫當前二進位制日誌的快照時間點的偏移量這兩個值可以叫做日誌檔案座標(log file coordinate),因為它們確定了一個二進位制日誌的位置,你可以用SHOW MASTER STATUS命令找到日誌檔案的座標;
-
從快照時間到現在的二進位制日誌。
可以通過以下幾中方法來克隆一個slave:
(1) 冷拷貝(cold copy)
停止master,將master的檔案拷貝到slave;然後重啟master。缺點很明顯需要停止master。
(2) 熱拷貝(warm copy)
如果你僅使用MyISAM表,你可以使用mysqlhotcopy拷貝,即使伺服器正在執行。
(3) 使用mysqldump 從server1 複製到 server-slave
mysqldump --single-transaction --all-databases --master-data=1 --host=server1 | mysql --host=server-slave
選項 --single-transaction 使得轉儲的資料為事務開始前的資料。如果使用的是非事務型表,可以使用--lock--all-tables選項來獲得所有表的一致性轉儲。
(4) 使用快照備份
1備份快照, 2 SHOW MASTER STATUS 找到座標, 3在備庫啟動快照 並且 CHANGE MASTER TO 指定二進位制日誌的座標。
(5) 使用xtrabackup
此工具能夠在備份時不阻塞伺服器,通過克隆主庫建立備庫。如果是從主庫獲得備份,可以從xtrabackup_binlog_pos_innodb檔案中獲得複製開始的位置。如果是從另外的備庫獲得備份,可以從xtrabackup_slave_info檔案中獲得複製開始的位置。
注意:不要使用LOAD DATA FROM MASTER 或者LOAD TABLE MASTER 這些命令過時、緩慢,並且非常危險,並且只適用於MyISAM儲存引擎。
複製配置
在主庫上二進位制日誌最重要的選項是sync_binlog:
sync_binlog=1 (只適用於二進位制日誌不適用中繼日誌)如果開啟該選項,MySQL每次在提交事務前會將二進位制日誌同步到磁碟上,保證在伺服器奔潰時不會丟失事件但是會增加效能開銷。當伺服器崩潰會導致myisam引擎的表損壞,如果使用InnoDB,下列強烈推薦使用:
- innodb_flush_logs_at_trx_commit:每隔幾秒把事務日誌快取區的資料寫到日誌檔案中並重新整理到磁碟上。
- innodb_support_xa=1
- innodb_safe_binnlog
在備庫上,推薦開啟如下配置選項,為中繼日誌制定絕對路徑:
- relay_log=/path/to/logs/relay_bin
- skip_slave_start
- read_only
通過設定relay_log可以避免中繼日誌檔案基於機器名來命名制定絕對路徑可以避免多個MySQL版本中存在的BUG,這些BUG可能會導致中繼日誌在一個意料外的位置建立。skip_slave_start選項能夠阻止備庫在崩潰後自動啟動複製。read_only 選項可以阻止大部分使用者更改非臨時表.
在mysql5.5中不介意fsync開銷可開啟如下防止中級日誌不重新整理到磁碟
sync_master_info = 1
sync_relay_log = 1
sync_relay_log_info = 1
如果主備延遲很大,備庫的I/O執行緒可能會寫大量中繼日誌,SQL執行緒在重放完一箇中繼日誌中的事件會盡快將其刪除(通過relay_log_purger選項來控制)。但如果延遲非常嚴重,I/O執行緒可能會把整個磁碟撐滿。解決辦法是配置relay_log_space_limit變數。如果所有中繼日誌的大小之和超過這個值,I/O執行緒會停止,等待SQL執行緒釋放盤空間。
但是如果配置了relay_log_space_limit 而主備延遲很大,假如主庫崩潰則會導致主備不同步(主庫崩潰主庫二進位制檔案沒有傳遞到備庫)
複製的原理
基於語句的複製:
優點:
1,會使得二進位制檔案更加緊湊更小方便傳輸。
缺點:
1,有一些語句執行會產生錯誤比如時間戳 now()此時兩個機器是不一樣的。
2,更新必須是穿行的這就需要加鎖但不是所有的儲存引擎都支援加鎖。
基於行的複製:
優點:
1,可以減少鎖的使用。
2,對於所有的SQL構造、觸發器、儲存過程等都能正確執行。只是當你試圖做一些諸如在備庫修改表的schema這樣的事情時才可能導致複製失敗。
3,基於行的複製能夠更快地找到並解決資料不一致的情況。如果是使用基於語句的複製模式,在備庫更新一個不存在的記錄時不會失敗,但在基於行的複製模式下則會報錯並停止複製。
4,佔用更少的cpu。
缺點:
1,語句無在日誌記錄,難以判斷那些sql更新過程,像黑盒子,很難知道問題所在。
2,傳輸佔用更多的頻寬佔用更多i/o。
複製過濾:
主庫:
binlog_do_db=A
binlog_do_db=B
binlog_ignore_db=test
binlog_ignore_db=test2
注意:多個數據庫寫多條配置 最好不要在主庫上配置過濾 因為主庫上配置指定某個庫記錄二進位制檔案,當其他庫發生問題時由於沒有記錄到二進位制檔案所以無法從二進位制檔案恢復。所以不建議配置
備庫:
Replicate_do_db
Replicate_do_table
Replicate_ignore_db=db1.t1% ##過濾db1庫中t1開頭的表
Replicate_ignore_table
Replicate_rewrite_db
Replicate_wild_do_table
Replicate_wild_ignore_table
注意:在備庫配置的時候要注意主庫的use
比如 從庫 replicate-ignore-db = db2
主庫上 use mysql
主庫執行 delete from db1.tb1
此時 是不會複製到備庫執行 delete from db1.tb1 因為已經被過濾了
原因:設定了 replicate-ignore-db = db2 凡是在db2(use db2)上執行的都會被過濾.
複製拓撲圖
複製的體系結構有以下一些基本原則:
(1) 每個slave只能有一個master;
(2) 每個master可以有很多slave;
(3) 每臺機器必須有唯一的伺服器ID;
(4) 如果你設定log_slave_updates(從庫執行復制列印到二進位制日誌),slave可以是其它slave的master,從而擴散master的更新
一主多備結構:
一主多備是一種比較靈活的方式也是最常見的方式,不同的 備庫 用作不同功能:
1:使用不同的索引增加效能
2:某個庫用作資料統計以增加效能
3:某個庫用作容災
4:某個庫用作主備切換
5:某個庫用作測試開發
主主複製結構:
這種結構存在一些問題導致資料不一致:
1:比如兩臺auto_increment 自增id都從0開始會導致重複錯誤。
2:一臺機器執行update t set a=1 where a=2; 另一臺機器執行 update t set a=3 where a=2;此時如果語句複製就會資料不一致。
環形結構:
這種結構比較脆弱一環失敗環環失敗它也存在主主機構的問題。
主主被動機構:
兩個主庫其中一個是隻讀主庫。
這種結構是的主備切換非常方便避免了主主結構的缺點,
樹形金字塔形:
優點:可以減少主庫向多個備庫複製的壓力轉而由備庫去做其他的備庫分發。
缺點:出現不同步的問題排查將更加困難。
複製方案:
-
選擇性複製:把主庫中不同功能 複製到 不同的備庫,讓備庫去提供讀取,讓備庫作為全文檢索。
-
分離功能:把一些查詢分給專門的備庫,併為備庫定製化硬體和索引和引擎。
-
資料歸檔:主庫上某些資料可以放到備庫然後從主庫刪掉 刪除的時候注意不要讓刪除進入到二進位制日誌不然備庫也會刪除(設定sql_log_bin為0在)。
-
模擬多主庫複製:間隔一段時間把從庫從主庫1設定為主庫2 然後間隔時間再設定回來 。
管理和維護
複製的監控:
- 可以使用show master status 檢視主庫的二進位制日誌位置和配置。
- 可以使用show master logs 檢視主庫哪些二進位制日誌在磁碟上從而決定一臺新的從庫 執行 pugre master logs 的引數。
測量複製延遲:
雖然SHOW SLAVE STATUS輸出的Seconds_behind_master列理論上顯示了備庫的延時,但由於各樣的原因,並不總是準確的:
1.備庫Seconds_Behind_Master值是通過將伺服器當前的時間戳與二進位制日誌中的事件時間戳相對比得到的,所以只有在執行事件時才能報告延時。
2.如果備庫複製執行緒沒有執行,就會報延遲null。
3.一些錯誤(例如主備的max_allowed_packet不匹配,或者網路不穩定)可能中斷複製並且/或者停止複製執行緒,備庫有時可能無法計算延時。如果發生這種情況備庫會報0或者null
4.一個大事務可能會導致延遲波動,例如,有一個事務更新資料長達一個小時,最後提交。這條更新將比它實際發生時間要晚一個小時才記錄到二進位制日誌中。當備庫執行這條語句時,會臨時地報告備庫延遲為一個小時,然後又很快變成0
5.如果分發主庫落後了,並且其本身也有已經追趕上它的備庫,備庫的延遲將顯示為0,而事實上和源主庫是有延遲的。
解決辦法:
使用 heartbeat record(自定義一個心跳檢查),在主庫建立一個表 tb_heart 然後每秒插入一個值(系統當前時間秒) 然後對比從庫的 tb_heart 最大值和主庫的差距。
確定主備是否一致:
複製延時或網路問題並總是會讓主備資料不完全一致。主備一致應該是一種規範,檢查你的主備一致性應該是一個日常工作,特別是是當使用備庫來做備份時尤為重要。
1:Percona Toolkit裡的pt-table-checksum能夠用於確認主備庫資料是否一致。
2:mysql提供了checksum table來校驗主備表是否一致(複製進行時不可用)
解決不同步:
1.如果資料量小可以用mysqldump 轉儲 或者修改語句。
2.Percona Toolkit的pt-table-sync
改變主庫
計劃內提升:
1.停止主庫上的寫操作,最好關閉所有客戶端程式。
2.通過設定read only來停止活躍的寫入,不過read only不能禁止超級使用者寫入。通過flush tables wity readlock可以讓任何使用者都不可寫入。flush tables with read lock作用是將所有髒頁重新整理到硬碟並關閉所有表並給所有表加上讀鎖。實際上分為三個步驟:給全域性加上讀鎖避免更新;重新整理並關閉所有表快取,如果存在查詢或者更新正在執行那麼會進入waiting for flush tables狀態等待;加全域性commit鎖保證資料一致性。第一步和第三步的兩個鎖都屬於MDL鎖,即元資料鎖,該鎖可以保證事務正在操作表時,表不會被DDL語句修改刪除等。
3.選擇一個備庫作為主庫(一般選擇複製最接近主庫的那個),並確保它已經跟上主庫。
4.確保主備庫資料一致。
5.新主庫上stop slave。
6.新主庫上重置master info資訊。 change master to master_host='' 然後執行 reset slave , 斷開與老庫連結並丟棄master.info(如果連結資訊在my.cnf則無法正常工作)
7.show master status記錄新主庫binlog座標。
8.確保其他備庫趕上。
9.將客戶端臉上新主庫。
10.每個備庫change master to。
計劃外提升:
主要是處理主庫崩潰的情況。
1.重啟主庫binlog如果可以用,如果可以用那麼然備庫跟上主庫的binlog,
2.如果無法重啟那麼就選取備庫中日誌座標最接近主庫的那個備庫當作新主庫。
1.讓備庫執行完畢中繼日誌。
2.檢查每臺備庫show slave status 選擇master_log_file/red_master_log_pos 最新的做主庫。
3.按照上面計劃內執行切換。
主主切換:
1.停止主動一方的寫入。
2.在主動 設定set global read only=1,同時在配置檔案中也設定避免重啟失效但是這無法阻止管理員更改可以設定 flush tables with red lock 會阻止所有寫入。
3.在主動一方show master status記錄binlog位置。
4.在被動一方根據上一步位置執行select master pos wait()該語句將阻塞主知道複製跟上主動伺服器。
5.被動一方set read only=0變成主動一方。
6.修改客戶端配置,使其寫入主動一方。
複製的問題和解決方案:
主庫意外關閉:
1:沒有設定sync_binlog 崩潰後可能有二進位制日誌 a 沒有重新整理到磁碟,備庫處於讀不到a的狀態,主庫重啟備庫連結主庫後嘗試去讀 a 此時會卡在這裡.
解決這個問題需要重新設定 備庫 從下一個日誌偏移量開始讀
2:開啟了syn_binlog myisam的表仍有可能會在崩潰時損壞,innoDB 沒有設定innodb_flush_log_at_trx_commit也會丟失資料但是表不會損壞。
備庫意外關閉:
備庫意外關比並重啟後,會去重新讀取master.info檔案以找到上次停止複製的位置.但是此時該檔案並沒有同步寫入到磁碟,這時候檔案中的資訊就可能是錯誤的.
備庫常常會重新執行一些二進位制事件,這可能會導致主鍵衝突,唯一索引衝突等.唯一的辦法就是忽略錯誤.
解決辦法:
1:可以使用工具pt-slave-restart,
2:如果是innodb表可以重啟後觀察錯誤日誌
找到二進位制日誌座標,可以使用這個值重新指向主庫的便宜量,然後再用pt-table-checksum檢查資料是否一致
建議事項:
skip_slave_start=1
#能夠阻止備庫崩潰後自動啟動複製,這樣可以為你提供足夠的時間修復可能出現的問題
sync_master_info =1 #預設值為10000即每10000次sync_relay_log事件會重新整理到磁碟
sync_relay_log =1 #如果不介意額外的fsync()導致的效能問題可以都設定
sync_relay_log_info =1 #成1 即1次事件就重新整理至磁碟
二進位制日誌損壞
主庫二進位制日誌損壞
解決方法:
只能忽略損壞的位置,可以在主庫上執行flush logs 然後備庫指向該檔案的開始位置.
備庫二進位制日誌損壞
解決方法:
通過CHANGE MASTER TO 丟棄並重新獲取損壞的事件,只要將備庫指向它當前正在複製的位置(根據Relay_Master_Log_File/Exec_Master_Log_Pos確定),這樣會導致丟棄所有在磁碟上的中繼日誌.
二進位制日誌於InnoDB事務日誌不同步: 除非備庫中繼日誌有儲存,否則自求多福
1:syn_binlog =1
對於沒事務的複製
如果是基於語句的複製 當更新100條資料 在更新到50條的時候程序被kill了主備將不同步因為語句還沒更新到二進位制日誌。
避免混用事務和非事務:
如果備庫發生死鎖而主庫沒有,事務型會回滾而非事務型則不會造成不同步
不確定的語句
比如 insert ignoer 在擁有多個唯一索引的表中更新可能會 主備庫可能選擇不同索引使得資料不同或者 update t_a set b=now()
主備使用不同引擎
基於語句複製如果使用不同儲存引擎可能導致查詢結果不同(但是不同引擎可能會為備庫作為查詢庫 帶來一些效能提升)
備庫資料發生改變
把備庫設定為read_only
不唯一的伺服器id
小心設定伺服器id
臨時表丟失
備庫意外關閉導致臨時表丟失 可以新建和臨時表相同的表 然後執行同步完畢後刪除
InnoDB加鎖讀引起的鎖爭用:
將大命令拆成小命令可以有效減少鎖競爭
過大的複製延遲:
1:定位執行慢的語句,改善機器配置
2:大事務拆小事務如果說大事務對於binlog的產生有極大的影響,那麼我們認為定義小事務,大事務不允許執行有大事務的監控,可以基於時間,可以基於資料量,監控到不符合規範的trx自動kill
3:大量併發事務
1:sync_binlog = 0 && innodb_flush_trx_commit = 0 可以極大的提高事務處理的吞吐量,因為IO fsync的次數變少了,可以非常有效的降低資料延遲
風險:如果slave掛了,需要重做slave
2:MTS(enhanced multi-threaded slave)
3:半同步: 半同步可以讓延遲為0,但是半同步有自動切換為非同步複製的可能
4:全同步: MySQL的group replication 就是這類的代表,這個話題以後再聊
mysql複製的半同步和全同步
非同步複製:
MySQL複製預設是非同步複製,Master將事件寫入binlog,提交事務,自身並不知道slave是否接收是否處理;
缺點:不能保證所有事務都被所有slave接收。
半同步:
當事務提交時在客戶端接受到查詢結果之前,必須保證二進位制日誌至少傳輸到一臺裝置上,主庫將事務提交到磁碟後會增加一些延遲
當Master上開啟半同步複製功能時,至少有一個slave開啟其功能。當Master向slave提交事務,且事務已寫入relay-log中並重新整理到磁碟上,slave才會告知Master已收到;若Master提交事務受到阻塞,出現等待超時,在一定時間內Master 沒被告知已收到,此時Master自動轉換為非同步複製機制;
注意
1:備庫接受到事務就反饋而不是完成。
2:半同步不總是可以工作時間太長會轉非同步
3:備庫不會阻塞主庫事務提交只會阻塞主庫通知客戶端時間。
全同步:
Master提交事務,直到事務在所有slave都已提交,才會返回客戶端事務執行完畢資訊;
缺點:完成一個事務可能造成延遲。