检查mysql的replication_MySQL Replication需要注意的问题
MySQL Replication 大家都非常熟悉了,我也不會(huì)寫怎么搭建以及復(fù)制的原理,網(wǎng)上相關(guān)文章非常多,大家可以自己去搜尋。我在這里就是想總結(jié)一下mysql主從復(fù)制需要注意的地方。有人說(shuō)主從復(fù)制很簡(jiǎn)單嘛,就是master,slave的server_id不一樣就搞定。確實(shí),簡(jiǎn)單的來(lái)說(shuō)就是這么簡(jiǎn)單。但是真正在生產(chǎn)環(huán)境我們需要注意的太多了。首先說(shuō)說(shuō)主庫(kù)宕機(jī)或者從庫(kù)宕機(jī)后復(fù)制中斷的問(wèn)題。
雖然很多知識(shí)點(diǎn)或許我博客其他文章中都有提到過(guò),或者重復(fù)了,但是我還是想總結(jié)一下。
主庫(kù)意外宕機(jī)
如果沒有設(shè)置主庫(kù)的sync_binlog選項(xiàng),就可能在奔潰前沒有將最后的幾個(gè)二進(jìn)制日志事件刷新到磁盤中。備庫(kù)I/O線程因此也可一直處于讀不到尚未寫入磁盤的事件的狀態(tài)中。當(dāng)主庫(kù)從新啟動(dòng)時(shí),備庫(kù)將重連到主庫(kù)并再次嘗試去讀該事件,但主庫(kù)會(huì)告訴備庫(kù)沒有這個(gè)二進(jìn)制日志偏移量。解決這個(gè)問(wèn)題的方法是指定備庫(kù)從下一個(gè)二進(jìn)制日志的開頭讀日志。但是一些事件將永久丟失。可以使用前面文章提到的工具來(lái)檢查主從數(shù)據(jù)一致以及修復(fù)pt-table-checksum。即使開啟了sync_binlog,myisam表的數(shù)據(jù)仍然可能在奔潰的時(shí)候損壞。對(duì)于innodb表,如果innodb_flush_log_at_trx_commit沒有設(shè)置為1,也可能丟失數(shù)據(jù),但是數(shù)據(jù)不會(huì)損壞。
因此主庫(kù)的參數(shù)建議開啟
sync_binlog=1innodb-flush-log-at-trx-commit=1
MySQL 5.6版本之前存在一個(gè)bug,即當(dāng)啟用上述兩個(gè)參數(shù)時(shí),會(huì)使得InnoDB存儲(chǔ)引擎的group commit失效,從而導(dǎo)致在寫密集的環(huán)境中性能的急劇下降。group commit是什么?這是一個(gè)知識(shí)點(diǎn),那為什么sync_binlog=1,innodb-flush-log-at-trx-commit=1
會(huì)導(dǎo)致組提交失敗?這又是一個(gè)知識(shí)點(diǎn),大家可以查閱相關(guān)資料。
因此,我們常常在性能和數(shù)據(jù)一致性中做了妥協(xié),通常將參數(shù)innodb-flush-log-at-trx-commit設(shè)置為2,而這就導(dǎo)致了master不再是crash safe的,主從數(shù)據(jù)可能會(huì)不一致。關(guān)于innodb_flush_log_at_trx_commit的有效值為0,1,2。我這里簡(jiǎn)單提一下,因?yàn)楹芏嘀R(shí)點(diǎn)是有連貫性的,往往提到這個(gè)問(wèn)題而又涉及到另外的問(wèn)題^_^
0代表當(dāng)提交事務(wù)時(shí),并不將事務(wù)的重做日志寫入磁盤上的日志文件,而是等待主線程每秒的刷新。當(dāng)宕機(jī)時(shí),丟失1秒的事務(wù)。
1和2有點(diǎn)相同,但是不同的地方在于:1表示在執(zhí)行commit時(shí)將重做日志緩沖同步寫到磁盤,即伴有fsync的調(diào)用。2表示將重做日志異步寫到磁盤,即寫到文件系統(tǒng)的緩存中。由操作系統(tǒng)控制刷新。因此不能完全保證在執(zhí)行commit時(shí)肯定會(huì)寫入重做日志文件,只是有這個(gè)動(dòng)作的發(fā)生。
因此為了保證事務(wù)的ACID中的持久性,必須將innodb_flush_log_at_trx_commit設(shè)置為1,也就是每當(dāng)有事務(wù)提交時(shí),就必須確保事務(wù)都已經(jīng)寫入重做日志文件。那么當(dāng)數(shù)據(jù)庫(kù)因?yàn)橐馔獍l(fā)生宕機(jī)時(shí),可以通過(guò)重做日志文件恢復(fù),并保證可以恢復(fù)已經(jīng)提交的事務(wù)。而將該參數(shù)設(shè)置為0或者2,都有可能發(fā)生恢復(fù)時(shí)部分事務(wù)的丟失。不同之處在于,設(shè)置為2時(shí),當(dāng)mysql數(shù)據(jù)庫(kù)發(fā)生宕機(jī)而操作系統(tǒng)及服務(wù)器并沒有發(fā)生宕機(jī)時(shí),由于此時(shí)未寫入磁盤的事務(wù)日志保存在文件系統(tǒng)緩存中,當(dāng)恢復(fù)時(shí)同樣能保證數(shù)據(jù)不丟失。
對(duì)于性能與安全我們都要的情況下,我們肯定會(huì)使用RAID,并且開啟Write Back功能,而且RAID卡提供電池備份單元(BBU,Battery Backup Unit),關(guān)于這塊的知識(shí),童鞋們可以自行查閱相關(guān)資料。
備庫(kù)意外宕機(jī):
當(dāng)備庫(kù)在一次非計(jì)劃的關(guān)閉后重啟時(shí),會(huì)去讀master.info文件以找到上次停止復(fù)制的位置。不幸的是,該文件可能并沒有同步寫到磁盤,因?yàn)樵撔畔⑹窃诰彺嬷?#xff0c;可能并沒有刷新到磁盤文件master.info。文件中存儲(chǔ)的信息可能是錯(cuò)誤的,備庫(kù)可能會(huì)嘗試重新執(zhí)行一些二進(jìn)制日志事件,這可能導(dǎo)致主鍵沖突,就是我們常??匆姷?062錯(cuò)誤。除非能確定備庫(kù)在哪里停止(很難),否則唯一的辦法就是忽略那些錯(cuò)誤。
在從庫(kù)導(dǎo)致復(fù)制中斷有兩方面的原因,即replication中的SQL thread和IO thread。首先來(lái)看SQL thread,其主要完成兩個(gè)操作:
1.運(yùn)行relay log中對(duì)應(yīng)的事務(wù)信息
2.更新relay-info.log文件
更新relay-info.log文件是為了記錄已經(jīng)執(zhí)行relay log中的位置,當(dāng)slave重啟后可以根據(jù)這個(gè)位置繼續(xù)同步relay log。但是,這里用戶會(huì)發(fā)現(xiàn)這兩個(gè)操作不是在一個(gè)事務(wù)中,一個(gè)是數(shù)據(jù)庫(kù)操作,一個(gè)是文件操作,因此不能達(dá)到原子的效果。此外,MySQL數(shù)據(jù)庫(kù)默認(rèn)對(duì)于文件relay-info.log是寫入到操作系統(tǒng)緩存,因此在發(fā)生宕機(jī)時(shí)可能導(dǎo)致大量的已更新位置的丟失,從而導(dǎo)致重復(fù)執(zhí)行SQL語(yǔ)句,最終的現(xiàn)象就是主從數(shù)據(jù)不一致。MySQL 5.5新增了參數(shù)sync_relay_log_info,可以控制每次事務(wù)更新relay-info.log后就進(jìn)行一次fdatasync操作,這加重了系統(tǒng)負(fù)擔(dān),而且即使這樣也可能存在最后一個(gè)事務(wù)丟失的情況。
IO thread用于同步master上的二進(jìn)制日志,但是其在crash時(shí)依然會(huì)導(dǎo)致數(shù)據(jù)不一致的情況發(fā)生。IO thread將收到的二進(jìn)制日志寫入到relay log,每個(gè)二進(jìn)制日志由多個(gè)log event組成,所以每接受到一個(gè)log event就需要更新master-info.log。和relay-info.log一樣,其也是寫入操作系統(tǒng)緩存,參數(shù)sync_master_info可以控制fdatasync的時(shí)間。由于IO thread的更新不能像SQL thread一樣進(jìn)行放到一個(gè)事務(wù)進(jìn)行原子操作,因此其是對(duì)數(shù)據(jù)一致性會(huì)產(chǎn)生影響,設(shè)想一個(gè)log event傳送到了relay log中兩次的情形。
不過(guò)好在從MySQL 5.5版本開始提供了參數(shù)relay_log_recovery,當(dāng)發(fā)生crash導(dǎo)致重連master時(shí),其不根據(jù)master-info.log的信息進(jìn)行重連,而是根據(jù)relay-info中執(zhí)行到master的位置信息重新開始拉master上的日志數(shù)據(jù)(不過(guò)需要確保日志依然存在于master上,否則就。。。)
so,mysql 5.5版本的從庫(kù)推薦配置參數(shù):
sync_master_info = 1sync_relay_log= 1sync_relay_log_info= 1read_only #從庫(kù)只讀,但是有super權(quán)限的依然可以寫入
relay_log_recovery = 1
skip_slave_start # 默認(rèn)啟動(dòng)從庫(kù)就開啟了同步,io線程和sql線程都運(yùn)行了,該參數(shù)是需要手動(dòng)執(zhí)行start slave方可啟動(dòng)同步
復(fù)制過(guò)濾選項(xiàng)
常常看見很多同學(xué)在主庫(kù)進(jìn)行過(guò)濾選項(xiàng)設(shè)置,當(dāng)然這也有好處,減少了帶寬,但是在主庫(kù)設(shè)置過(guò)濾選項(xiàng)是非常危險(xiǎn)的操作,因?yàn)闊o(wú)論是顯示要過(guò)濾的或者要同步的,二進(jìn)制日志只記錄你設(shè)置的,其他的是不會(huì)記錄的。當(dāng)主庫(kù)有數(shù)據(jù)需要用到binlog恢復(fù)時(shí),你就準(zhǔn)備哭吧。所以通常在備庫(kù)進(jìn)行過(guò)濾選項(xiàng)設(shè)置。比如忽略某個(gè)庫(kù),同步所有庫(kù),或者同步某一個(gè)庫(kù),當(dāng)然這會(huì)浪費(fèi)帶寬,但是和安全比起來(lái),這點(diǎn)浪費(fèi)不算什么。有時(shí)候安全與性能往往需要我們自己平衡。
還有就是跨庫(kù)更新,如果我們?cè)趥鋷?kù)是這樣設(shè)置的,比如同步y(tǒng)ayun這個(gè)庫(kù)
replicate_do_db=yayun
主庫(kù)記錄如下:
mysql> select * fromt1;+----+-------+
| id | name |
+----+-------+
| 1 | yayun |
| 2 | atlas |
| 3 | mysql |
+----+-------+
3 rows in set (0.00sec)
mysql>
備庫(kù)記錄如下:
mysql> select * fromt1;+----+-------+
| id | name |
+----+-------+
| 1 | yayun |
| 2 | atlas |
| 3 | mysql |
+----+-------+
3 rows in set (0.00sec)
mysql>
現(xiàn)在我們?cè)谥鲙?kù)插入一條記錄
mysql> usetest;
Readingtable information for completion of table and columnnames
You can turnoff this feature to get a quicker startup with -ADatabasechanged
mysql> insert into yayun.t1 (name) values ('good yayun');
Query OK,1 row affected (0.01sec)
mysql> select * fromyayun.t1;+----+------------+
| id | name |
+----+------------+
| 1 | yayun |
| 2 | atlas |
| 3 | mysql |
| 5 | good yayun |
+----+------------+
4 rows in set (0.00sec)
mysql>
查看備庫(kù):
mysql> select * fromt1;+----+-------+
| id | name |
+----+-------+
| 1 | yayun |
| 2 | atlas |
| 3 | mysql |
+----+-------+
3 rows in set (0.00sec)
mysql>
怎么回事?怎么沒有同步?這就是跨庫(kù)更新帶來(lái)的問(wèn)題,比如下面的更新:
usetestinsert into yayun.t1 (name) values ('good yayun')
當(dāng)然你會(huì)說(shuō)哪個(gè)2B會(huì)這么干啊,呵呵,有時(shí)2B還是有的。所以我們還有另外2個(gè)過(guò)濾復(fù)制參數(shù)
replicate_wild_do_table
replicate_wild_ignore_table
一個(gè)是要同步的表,一個(gè)是不同步的表,通常我們可以這樣寫
replicate_wild_do_table=yayun.%
表示同步y(tǒng)ayun庫(kù)下面的所有表,這樣就解決的跨庫(kù)更新的問(wèn)題。
復(fù)制格式的問(wèn)題
通常推薦使用ROW格式,為什么使用?看看我前面文章MySQL數(shù)據(jù)恢復(fù)和復(fù)制對(duì)InnoDB鎖機(jī)制的影響
不要用Seconds_Behind_Master來(lái)衡量MySQL主備的延遲時(shí)間
這個(gè)后續(xù)我會(huì)寫相關(guān)文章解釋為什么不要用該參數(shù)衡量主備的延遲時(shí)間。
總結(jié):
上面所提到的參數(shù)都是最大限度保證主從數(shù)據(jù)一致,以及主庫(kù)宕機(jī),從庫(kù)宕機(jī)復(fù)制不會(huì)中斷,但是性能會(huì)打折扣,所以需要我們自己去衡量,或者做妥協(xié)。
還有很多很多的問(wèn)題,我也只總結(jié)了這么一點(diǎn),要是還有大神知道更詳細(xì)的,歡迎一起交流,共同進(jìn)步。^_^
參考資料:
總結(jié)
以上是生活随笔為你收集整理的检查mysql的replication_MySQL Replication需要注意的问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 3年前的神机一加7系列适配ColorOS
- 下一篇: redis集群关闭 启动报错_使用虚拟机