3.1 MySQL復制
為了保證應用24小時提供服務,那么我們需要做2件事情,系統數據的備份和冗余。備份可以將數據恢復到崩潰之前的狀態,而冗余則是保證在一個或多個節點停止服務的情況下,應用仍能提供服務。
3.1.1 什么是復制
這里說的復制,就是指MySQL復制主節點(master)的所有數據改變到從節點(slave),并應用改變的數據,與主節點數據保存一致。通常復制就是為了給master創建一個可靠的副本。
MySQL復制,有什么特點呢?
(1) 數據分布 (Data distribution ),數據可以分布在不同的數據中心。
(2) 負載平衡(load balancing),可以分配查詢,降低主服務器壓力。
(3) 備份(Backups) ,復制本身就是一種master的備份。
(4) 高可用性和容錯行 High availability and failover,當master宕機后,slave可以接管master的任務,同時具有及時糾正錯誤,挽回數據的容錯率。
從MySQL5.0開始,MySQL默認采用日志復制,效率非常高,可靠性也非常高,前提是主從,一開始是完全相同的數據。當無法保證精準復制時,MySQL會基于行的復制。
3.1.2 異步與同步的區別
MySQL的復制準確的說,是異步的,不是同步復制的。事務首先在主節點提交,然后復制給從節點,并在從節點上應用。這意味著主節點和從節點可能并不一致,如果主節點一直在更新,那么從節點始終是落后與主節點的。
異步復制優點在于,比同步復制更快,擴展性更好,占用系統資源更少。
同步復制則需要master等待所有的slave的寫都完成后,才能提交,導致寫的速度大大降低,同時需要額外的同步機制來保證一致性,但卻有額外的通信消息傳遞,增加了網絡數據量。
3.2 主從復制
搭建一個主從復制,大致看看是一個什么樣的效果,一主一從,最簡單的開始。
這里需要涉及到二進制日志,后面來詳細說明,本次主要說明復制過程。
3.2.1 配置復制
第一步:配置master。首先需要開啟二進制日志,配置好server-id,然后啟動MySQL,如下所示幾行添加到/etc/my.cnf文件中:
log-bin=master-bin 二進制日志文件名稱格式。
log-bin-index=master-bin.index 二進制日志的索引文件名
server-id=1 server id用于標示主從。
一般情況下log-bin默認是hostname-bin。Hostname的值來自pid-file選項,但是這樣也會有問題,主機名修改之后,binlog日志文件名也會隨之改變,索引文件還是可以讀取到正確的值。
當不給log-bin-index值的時候,默認與binlog文件基本名相同,索引文件隨主機名改變而改變,當你重啟了服務器之后,索引文件就找不到日志文件了,認為不存在了。
接下來,需要創建一個復制用的用戶。例如:

mysql> change master to
-> master_host='vm11.qq.com',
-> master_port=3306,
-> master_user='repl_user',
-> master_password='mysql';
Query OK, 0 rows affected, 2 warnings (0.04 sec)

注意:最好在同步之前,主從兩邊的數據庫是一樣的,因為master在沒有開啟二進制日志之前的所有操作都不會同步過去到slave的。
我們這里在master沒有開啟二進制日志之前,先建立了一個庫test,slave肯定同步不過去,這時候master刪除這個庫。然后再次新建test的時候,出現了問題。

這是master的,看看slave的。

這里沒有同步過去,看看什么問題。

錯誤:1008,test庫不存在,drop database test語句執行不了,所以slave_sql_running狀態變成了NO。生產環境很容易忽略,出現這樣的問題。

CHANGE MASTER TO MASTER_HOST='vm11.qq.com',
MASTER_USER='repl_user',
MASTER_PASSWORD='mysql',
MASTER_LOG_FILE='master-bin.000001',
MASTER_LOG_POS=756;
Start slave;從新的位置從新同步,前面的忽略。
3.2.2 二進制日志
什么是二進制日志,就是記錄表改變的記錄,以上例來看。

來看看日志都記錄了什么;

對比一下,我們以下的操作,那些記錄了,那些沒有記錄。
mysql> create database test; 記錄
mysql>use test; 記錄
mysql>create table tab(text text); 記錄
mysql>insert into tab values("hello!"); 記錄,自動添加use test命令。
mysql>select * from tab; 沒有,日志記錄了一次commit;
mysql> flush logs; 記錄
最后一條記錄:Info:master-bin.000002;pos=4是slave下一次讀取二進制日志的位置,因為我們執行了flush logs;強制切換日志。
當我們想看第二個日志文件的內容時,默認是無法看到的,可以這樣:
mysql> show binlog eventsin 'master-bin.000002' \G;
3.2.3 復制工作原理
整體上來說,復制有3個步驟:
(1) master將改變記錄到二進制日志(binary log)中(這些記錄叫做二進制日志事件,binary logevents);
(2) slave將master的binary log events拷貝到它的中繼日志(relay log);
(3) slave重做中繼日志中的事件,將改變反映它自己的數據。

1.基于語句復制
也稱為邏輯復制,需要保證主從基礎數據一樣,然后把主庫上記錄的更改在從庫上再執行一遍,實現簡單,同步效果較好,網絡傳輸少,但問題就是,存在著一些無法被正確復制的SQL,像時間戳,current_user()這樣的函數語句,觸發器,存儲過程等也容易出現問題。另外一個問題時更新必須串行的,所以會需要更多的鎖。
優點:適應場景廣泛,可以非常靈活,都是SQL執行方式,當出現問題可以很好的去定位。
缺點:有些語句存在無法正確復制問題,特別是存儲過程和觸發器。
2.基于行的復制
就是直接復制改變的行數據,在從庫中也做update操作,也種實現方式比較復雜,因為復制的數據可能不正確,從庫更新量大,主庫一個update操作更新2000條數據,但在從庫可能需要update2000次才能將數據與主庫保持一致,優點是直接復制數據,會比較高效,不用去分析日志,但是缺點也非常明顯。網絡傳輸量較大,
優點:這種方式什么情況都可以使用,存儲過程,觸發器等都沒有問題,但是備庫與主庫的字段有不一致的情況,那么復制就會失敗。
缺點:無法獲知執行了什么操作,只能看到變化了的值,當問題出現后,很難去判斷故障的原因,或是什么導致的,而且很多情況下,備庫的開銷非常大,而且網絡傳輸也更高。
3.2.4 推薦復制配置
此小結主要用來分析復制的配置,有些配置是沒有必要的,有些也是需要分適用場景的,主要還是以安全為第一,最小化可能出現的問題為前提,然后是性能上的建議。
主庫上最重要的一個參數:sync_binlog=1
開啟,MySQL每次提交事務前都會將二進制日志同步到磁盤上,能夠保證崩潰時不丟失事務,關閉則無需再提交之前寫到磁盤,對于中繼日志來說,不適用該參數,所以建議主庫上開啟,從庫上關閉。
如果使用InnoDB,那么建議配置以下設置:
innodb_flush_logs_at_trx_commit:設為1當然是最安全的,但性能頁是最差的(相對其他兩個參數而言,但不是不能接受)。如果對數據一致性和完整性要求不高,完全可以設為2,如果只最求性能,例如高并發寫的日志服務器,設為0來獲得更高性能。
Innodb_support_xa=1 保證binlog里面存在的事務一定在redo log里面存在,同時binlog里面事務順序與redo log事務順序一致。
Innodb_safe_binlog 表示在5.0版本之前,跟Innodb_support_xa參數意思一樣。
log-bin=/data/binlog/master-bin 一定要配置文件名,不然在其它應用的時候,容易出現問題,同時制定了它的路徑。
在備庫上推薦配置:
Relay_log=/data/relaylog/relay-bin 制定路徑避免不同版本之間的bug問題,
Skip_slave_start 表示備庫在崩潰后不自動復制,因為可能已經不一致了,自動復制,可能導致更多的損壞,所以一般都需要禁用掉。
Read_only 可以阻止大部分用戶更改非臨時表,除了SQL線程和超級權限用戶外。
3.2.5 復制延遲
復制延遲,在大部分的同步系統中,都存在這樣的問題,目前較為成熟的亞秒級實時同步的解決方案是GoldenGate,當然大部分系統是不需要這么高的要求,所以只要延遲在我們接受的范圍內都是科學的解決方案。
復制延遲一般存在2種:一種是產生延遲然后再跟上,一種是穩定的延遲增大,前一種基本都是由于運行一條運行很長時間的查詢導致,而后者,可能存在非常嚴重的問題導致。通常沒有太大的調優空間,簡單的辦法是配置InnoDB,可以不那么頻繁的刷新磁盤,事務提交更快。可以設置innodb_flush_log_at_trx_commit值為2來做,還可以禁止備庫上的二進制日志記錄,配置innodb_locks_unsafe_for_binlog為1,并配置MyISAM的delay_key_write為all,但這些都是犧牲安全為代價提升效率,還有一點,是這樣配置備庫后,那么這個永遠就只能是備庫,不能切換為主庫了,如果需要切換,需要將配置改回來。
優化主庫高代價操作
在主庫上任何昂貴的操作,都會在備庫上重復一次,某些工作可以移動到備庫,就不會讓高代價的操作在主從上執行2次。例如:一個大表,需要匯總到一個小表用于日常維護:
Replayce into s_db.ip_table(col1,col2,…)
Select col1,sum(col2,….) from s_db.epc_table group by col1;
如果在主庫上執行,那么備庫也需要執行龐大的group by操作,當進行的太多的話,那么備庫就容易跟不上了,如果在備庫上操作,完成之后可以select into outfile,然后再load data infile將結果集加載到主庫中,這樣重負的工作變成了load data infile操作了。
備庫并行寫入
由于備庫要求串行寫入,某些應用更新就很吃力,那么我們能不能并行寫入呢,當然復制本身是不具備的,這需要區分寫入的類別了,例如禁止歸檔日志記錄到二進制日志,然后再主庫和備庫上分別執行,提高效率,這就是OLTP系統的歸檔數據操作,往往這樣來做比讓數據庫自己靠復制完成要高效的多。
還需要注意一個問題,主庫和備庫的max_allowed_packet配置不一致,主庫可能會記錄一個備庫認為過大的包,備庫獲取到該二進制事件后,可能會無限報錯和重試,或中繼日志損壞。
3.2.6 半同步和復制心跳
半同步復制在提交過程中增加了一個延遲,當提交事務時,客戶端接收到查詢結束反饋前必須保證二進制日志已經傳輸到至少一臺備庫上。主庫將事務提交到磁盤上之后會增加一個延遲。那么速度上延遲增加,但同步復制也會增加2段提交,增加的額外消息交換而性能不高。
也就是說主庫執行完事務后,是不會管備庫進度的,這樣提高了主庫的效率,而備庫上的事務至少有一個是跟主庫一致的,所以某種程度上講,實現了事務同步,不保證備庫已經執行完成,在性能上主庫提升較大。
復制心跳,就是主庫和備庫相互聯系功能,避免不聲不響的斷開連接。當出現斷開連接,備庫會注意到丟失的心跳數據,當再次恢復的時候,以此為依據,再次同步數據。
來自: http://m.blog.chinaunix.net/uid-29784755-id-5006955.html