mysqldump對于導出10g以下的資料庫或幾個表,還是适用的,而且更快捷。一旦資料量達到100-500g,無論是對原庫的壓力還是導出的性能,mysqldump就力不從心了。percona-xtrabackup備份工具,是實作mysql線上熱備工作的不二選擇,可進行全量、增量、單表備份和還原。(但當資料量更大時,可能需要考慮分庫分表,或使用 lvm 快照來加快備份速度了)
2.2版本 xtrabackup 能對innodb和xtradb存儲引擎的資料庫非阻塞地備份,innobackupex通過perl封裝了一層xtrabackup,對myisam的備份通過加表讀鎖的方式實作。2.3版本 xtrabackup 指令直接支援myisam引擎。
xtrabackup優勢 :
無需停止資料庫進行innodb熱備
增量備份mysql
流壓縮到傳輸到其它伺服器
能比較容易地建立主從同步
備份mysql時不會增大伺服器負載
為什麼要做主從複制?
我想這是要在實施以前要想清楚的問題。是為了實作讀寫分離,減輕主庫負載或資料分析? 為了資料安全,做備份恢複?主從切換做高可用?
大部分場景下,以上三個問号一主一從都能夠解決,而且任何生産環境都建議你至少要有一個從庫,假如你的讀操作壓力特别大,甚至要做一主多從,還可以不同的slave扮演不同的角色,例如使用不同的索引,或者不同的存儲引擎,或使用一個小記憶體server做slave隻用于備份。(當然slave太多也會對master的負載和網絡帶寬造成壓力,此時可以考慮級聯複制,即 a->b->c )
還有需要考慮的是,一主一從,一旦做了主從切換,不通過其它ha手段幹預的話,業務通路的還是原ip,而且原主庫很容易就廢棄了。于是 主-主 複制就産生了,憑借各自不同的 server-id ,可以避免 “a的變化同步到b,b應用變化又同步到a” 這樣循環複制的問題。但建議是,主主複制,其中一個主庫強制設定為隻讀,主從切換後架構依然是可用的。
複制過程是slave主動向master拉取,而不是master去推的,是以理想情況下做搭建主從時不需要master做出任何改變甚至停服,slave失敗也不影響主庫。
複制類型:
基于語句的複制:<code>statement</code>,在主伺服器上執行的sql語句,在從伺服器上執行同樣的語句,有可能會由于sql執行上下文環境不同而是資料不一緻,例如調用now()函數。mysql在5.7.7以前預設采用基于語句的複制,在 5.7.7 及以後版本預設改用 row-based。
基于行的複制:<code>row</code>,把改變的内容複制過去,而不是把指令在從伺服器上執行一遍。從mysql5.0開始支援,能夠嚴格保證資料完全一緻,但此時用<code>mysqlbinlog</code>去分析日志就沒啥意義。因為任何一條update語句,都會把涉及到的行資料全部set值,是以binlog檔案會比較大。
(遇到的一個坑是,遷移時,從庫改正了字段預設值定義,但資料在主庫更改後,即使産生的新資料預設值是正确的,但基于行的複制依然用不正确的值字段全部更新了)
混合類型的複制: <code>mixed</code>,預設采用基于語句的複制,一旦發現基于語句的無法精确的複制時,就會采用基于行的複制。
mysql系統庫<code>mysql</code>庫裡面表的日志記錄格式需要說明:在通過如insert、update、delete、truncate等方式直接修改資料的語句,使用<code> binlog_format</code>指定的方式記錄,但使用grant、alter、create、rename等改動的mysql庫裡資料的,會強制使用<code>statement-based</code>方式記錄binlog。
可以線上修改二進制日志類型,如<code>set session binlog_format=mixed;</code>,需要<code>super</code>權限。
複制類型還可以分為 異步複制和半同步複制。
通常沒說明指的都是異步,即主庫執行完commit後,在主庫寫入binlog日志後即可成功傳回用戶端,無需等等binlog日志傳送給從庫,一旦主庫當機,有可能會丢失日志。而半同步複制,是等待其中一個從庫也接收到binlog事務并成功寫入relay log之後,才傳回commit操作成功給用戶端;如此半同步就保證了事務成功送出後至少有兩份日志記錄,一份在主庫binlog上,另一份在從庫的relay log上,進而進一步保證資料完整性;半同步複制很大程度取決于主從網絡rtt(往返時延),以插件 semisync_master/semisync_slave 形式存在。
原理:
master将改變記錄到二進制日志(binary log)中(這些記錄叫做二進制日志事件,binary log events);
slave将master的binary log events拷貝到它的中繼日志(relay log);
slave重做中繼日志中的事件,将改變反映它自己的資料。
該過程的第一部分就是master記錄二進制日志。在每個事務更新資料完成之前,master在二進制日志記錄這些改變。mysql将事務串行的寫入二進制日志,即使事務中的語句都是交叉執行的。在事件寫入二進制日志完成後,master通知存儲引擎送出事務。
下一步将master的binary log拷貝到它自己的中繼日志。首先,slave開始一個工作線程——i/o線程。i/o線程在master上打開一個普通的連接配接,請求從指定日志檔案的指定位置之後的日志内容,然後開始binlog dump process。binlog dump process從master的二進制日志中讀取事件,如果已經跟上master,它會睡眠并等待master産生新的事件。i/o線程将這些事件寫入中繼日志。
sql slave thread(sql從線程)處理該過程的最後一步。sql線程從中繼日志讀取事件,并重放其中的事件而更新slave的資料,使其與master中的資料一緻。隻要該線程與i/o線程保持一緻,中繼日志通常會位于os的緩存中,是以中繼日志的開銷很小。
此外,在master中也有一個工作線程:和其它mysql的連接配接一樣,slave在master中打開一個連接配接也會使得master開始一個線程。複制過程有一個很重要的限制——複制在slave上是串行化的,也就是說master上的并行更新操作不能在slave上并行操作。
補充:
mysql 5.7開始加入了多源複制,這個特性對同時有很多個mysql執行個體是很有用的,阿裡雲rds(遷移)實作了類似的方式。
從mysql 5.6.2開始,mysql binlog支援checksum校驗,并且5.6.6預設啟用(crc32),這對自己模拟實作mysql複制的場景有影響。
下面開始配置主從:
主從版本一緻—>主庫授權複制帳号—>確定開啟binlog及主從server_id唯一—>xtrabackup恢複到從庫—>記錄xtrabackup_binlog_info中binlog名稱及偏移量—>從庫change master to —>slave start—>檢查兩個yes
在主庫上
這裡假設比較簡單的情況:全量備份,全量恢複,不涉及增量。
安裝和具體使用,見[文章]()。
賦予備份使用者權限:
完整的選項使用請執行innobackupex –-help,這裡隻介紹使用常用的選項進行完整備份及增量備份和還原。
這一節是把資料恢複到從庫,借此記錄一下xtrabackup的使用(用了雲之後,備份技能都丢了~)。生産環境你應該是早就有了xtrabackup的備份,做從庫時隻需要把備份拷過來,解壓恢複。
假設 mysql 安裝目錄在<code>/opt/mysql</code>,my.cnf配置檔案<code>/opt/mysql/my.cnf</code>,端口3306,資料目錄<code>/opt/mysql_data</code>,sock位于<code>/opt/mysql_data/mysql.sock</code>。備份資料放在<code>/data/backup/mysql/</code>。
1. 全量備份
預設會以當天 日期+時間 戳命名備份目錄,如 2015-09-16_00-00-02。一般會對它進行tar壓縮,由于tar隻能單程序,是以往往這個壓縮過程會比備份過程耗時2倍還多。拷貝到需要恢複(做從庫)的目錄。
如果手頭有一份未壓縮的全備資料,要在另一台恢複,其實還不如直接 rsync 過來,将近400g的資料壓縮與解壓縮過程特别漫長。
2. 全量恢複
在恢複的資料庫伺服器(從庫)上:
第一步是恢複準備,apply-log應用全備時 log sequence number 之後的資料,完了後會輸出類似 innodb: last mysql binlog file position 0 262484673, file name ./mysql-bin.000135 的資訊,告訴我們了後面的從庫應該從哪個地方開始複制。時間不會很長,但最好用screen之類的軟體放到背景執行,以免終端斷開,功虧一篑。
第二步使用新的my.cnf檔案,将完整的mysql資料檔案拷貝到datadir下。
上面恢複過程最後一步<code>apply-log</code>完成之後,會得到一個lsn position 和binlog檔案名:262484673、mysql-bin.000135。下面開始從庫制作。
一般在<code>copy-back</code>之後需要修改資料檔案目錄的屬性:
從庫的配置檔案簡單一點可以從主庫拷貝過來,但根據需要,要注意以下幾處
server-id一定不能與主庫相同
否則,會出現如下錯誤:
slave: received end packet from server, apparent master shutdown
從庫一般作為隻讀庫使用,是以為安全起見,設定隻讀 <code>set global read_only=1</code>;
可以在從伺服器的 my.cnf 裡加入<code>read-only</code>參數來實作這一點,唯一需要注意的一點事read-only僅對沒有super權限的使用者有效。是以最好核對一下連接配接從伺服器的使用者,確定其沒有super權限。
關于從庫的事件
mysql replication 可以很好的達到你的預期:從庫的事件不會自己去執行,主庫會把event執行的結果直接同步。在statement模式下,複制的是 event body 裡的sql,在row模式下是主庫事件執行完成後影響的行精确複制。
從庫 event_scheduler 參數是被忽略的,并且每個event 狀态會是 slaveside_disabled ,但create/alter event等操作語句是會複制。主從切換後,從庫事件狀态會變成enable。
參數調整
從庫是不允許寫入的,否則資料就不一緻了。從庫執行個體的配置可以不要主庫那麼高,比如原16g的buffer pool,根據用途,從庫可以設到4-8g(當時前提是将來你也不打算把它切換為主庫用)。
相應的,read_buffer_size,sort_buffer_size, query_cache_size 這些讀相關參數可以略微增大。當然我一般都懶得去改。
skip-slave-start
主從建立完成後,預設情況下次啟動從庫,會自動啟動複制程序,一般這也正是我們需要的,但在維護階段時你可能不想從庫啟動後立即開始複制,<code>--skip-slave-start</code>選項可以幫到你。
log-slave-updates
正常情況從庫是不需要寫回放日志産生的binlog,無形中增加伺服器壓力。但如果你想要實作級聯複制即 <code>a -> b -> c</code> ,b同時是a的從庫,也是c的主庫,就需要開啟 log-bin 和 log-slave-updates 。
另外,建議顯示設定 <code>log-bin=mysql-bin</code> 確定主從正常切換。 <code>show variables like 'log%'</code> 檢視目前值。
關于過濾表見[mysql-replica-filter]()
sync_binlog
for the greatest possible durability and consistency in a replication setup using innodb with transactions, you should use innodb_flush_log_at_trx_commit=1 and sync_binlog=1 in the master my.cnf file.
上面的話同時也意味着性能最低。可以在這埋點,假如出現慢的情況,把兩參數調成2。
啟動資料庫,注意看日志
提示:如果你不确定這個庫是誰的從庫,保守起見加上<code>--skip-slave-start</code>啟動,興許能防止資料不一緻。
在從庫上
上面的 master_log_file 和 master_log_pos 即是輸出的值,也可以在新的資料目錄下<code>xtrabackup_binlog_info</code>找到資訊。
從庫執行 show slave status\g
節選:
<code>master_log_file</code>: i/o線程目前正在讀取的主伺服器二進制日志檔案的名稱
<code>read_master_log_pos</code>:本機i/o線程讀取主伺服器二進制日志位置
上面2各值,與在主庫執行<code>show master status;</code>看到的值如果基本接近,說明從庫io線程已經趕上了主庫的binlog。
<code>relay_master_log_file</code>: 由sql線程執行的包含多數近期事件的主伺服器二進制日志檔案的名稱
<code>exec_master_log_pos</code>: sql線程執行來自master的二進制日志最後一個事件位置
與上面的<code>relay_master_log_file</code>一起,同<code>master_log_file</code>、<code>read_master_log_pos</code>比較,能看到sql線程是否已經趕上從庫本地的io線程。
<code>slave_io_running</code>:i/o線程是否啟動并成功連接配接到主伺服器上
一般和下面的<code>slave_io_running</code>和<code>seconds_behind_master</code>一起監控主從健康狀态
<code>slave_sql_running</code>:sql線程是否啟動
<code>seconds_behind_master</code>: 從屬伺服器“落後”多少秒
官網的解釋是:the number of seconds that the slave sql thread is behind processing the master binary log。但是當 sbm 為 0 時也不代表一定沒有延遲,因為可能因為網絡慢的緣故,從庫的io線程傳輸binlog太慢,它的sql線程應用日志很容易就趕上relay log,但實際主庫産生的binlog比傳輸的快,就會造成為0的假象。
有時你反複status會發現 seconds_behind_master 的值在0與一個很大的數之間波動,有可能是主庫上執行了一個非常大的event,沒執行完畢的時候從庫sbm顯示為0,event執行完成并傳輸完binlog後,就會顯示sbm非常巨大。(我在從機房遷移mysql到阿裡雲上部分庫老出現這種情況,應該跟網絡和大event都有關系)。
另外,relay log 中event記錄的時間戳是主庫上的時間戳,而sql thread的時間戳是從庫上的,如果主庫和從庫的時間偏差較大,那麼這個sbm的意義就基本不存在了。