一皮璧、GTID的概述:
1、全局事物標(biāo)識(shí):global transaction identifieds分飞。
2悴务、GTID事物是全局唯一性的,且一個(gè)事務(wù)對(duì)應(yīng)一個(gè)GTID譬猫。
3讯檐、一個(gè)GTID在一個(gè)服務(wù)器上只執(zhí)行一次,避免重復(fù)執(zhí)行導(dǎo)致數(shù)據(jù)混亂或者主從不一致染服。
4别洪、GTID用來(lái)代替classic的復(fù)制方法,不在使用binlog+pos開(kāi)啟復(fù)制柳刮。而是使用master_auto_postion=1的方式自動(dòng)匹配GTID斷點(diǎn)進(jìn)行復(fù)制挖垛。
5、MySQL-5.6.5開(kāi)始支持的秉颗,MySQL-5.6.10后開(kāi)始完善痢毒。
6、在傳統(tǒng)的slave端蚕甥,binlog是不用開(kāi)啟的闸准,但是在GTID中,slave端的binlog是必須開(kāi)啟的梢灭,目的是記錄執(zhí)行過(guò)的GTID(強(qiáng)制)夷家。
二蒸其、GTID的組成部分:
前面是server_uuid:后面是一個(gè)序列號(hào)
例如:server_uuid:sequence number
7800a22c-95ae-11e4-983d-080027de205a:10
UUID:每個(gè)mysql實(shí)例的唯一ID,由于會(huì)傳遞到slave库快,所以也可以理解為源ID摸袁。
Sequence number:在每臺(tái)MySQL服務(wù)器上都是從1開(kāi)始自增長(zhǎng)的序列,一個(gè)數(shù)值對(duì)應(yīng)一個(gè)事務(wù)义屏。
三靠汁、GTID比傳統(tǒng)復(fù)制的優(yōu)勢(shì):
1、更簡(jiǎn)單的實(shí)現(xiàn)failover闽铐,不用以前那樣在需要找log_file和log_Pos蝶怔。
2、更簡(jiǎn)單的搭建主從復(fù)制兄墅。
3踢星、比傳統(tǒng)復(fù)制更加安全。
4隙咸、GTID是連續(xù)沒(méi)有空洞的沐悦,因此主從庫(kù)出現(xiàn)數(shù)據(jù)沖突時(shí),可以用添加空事物的方式進(jìn)行跳過(guò)五督。
四藏否、GTID的工作原理:
1、master更新數(shù)據(jù)時(shí)充包,會(huì)在事務(wù)前產(chǎn)生GTID副签,一同記錄到binlog日志中。
2基矮、slave端的i/o 線(xiàn)程將變更的binlog淆储,寫(xiě)入到本地的relay log中。
3愈捅、sql線(xiàn)程從relay log中獲取GTID,然后對(duì)比slave端的binlog是否有記錄慈鸠。
4蓝谨、如果有記錄,說(shuō)明該GTID的事務(wù)已經(jīng)執(zhí)行青团,slave會(huì)忽略譬巫。
5、如果沒(méi)有記錄督笆,slave就會(huì)從relay log中執(zhí)行該GTID的事務(wù)芦昔,并記錄到binlog。
6娃肿、在解析過(guò)程中會(huì)判斷是否有主鍵咕缎,如果沒(méi)有就用二級(jí)索引珠十,如果沒(méi)有就用全部掃描。
五凭豪、要點(diǎn):
1焙蹭、slave在接受master的binlog時(shí),會(huì)校驗(yàn)master的GTID是否已經(jīng)執(zhí)行過(guò)(一個(gè)服務(wù)器只能執(zhí)行一次)嫂伞。
2孔厉、為了保證主從數(shù)據(jù)的一致性,多線(xiàn)程只能同時(shí)執(zhí)行一個(gè)GTID帖努。
六撰豺、使用GTID搭建mysql的主從復(fù)制的主要參數(shù):
[mysqld]
#GTID:
gtid_mode=on
enforce_gtid_consistency=on
server_id=2003306 #每天實(shí)例的server_id都要不一樣
#binlog
log-bin=mysqlbin
log-slave-updates=1 #允許下端接入slave
binlog_format=row #強(qiáng)烈建議,其他格式可能造成數(shù)據(jù)不一致
#relay log
skip_slave_start=1
注意:建議使用mysql-5.6.5以上的最新版本拼余。
啟動(dòng)GTID的兩種方法:
方法一污桦、
1、如果是在已經(jīng)跑的服務(wù)器姿搜,你需要重啟一下mysql server寡润。
2、啟動(dòng)之前舅柜,一定要先關(guān)閉master的寫(xiě)入梭纹,保證所有slave端都已經(jīng)和master端數(shù)據(jù)保持同步。
3致份、所有slave需要加上skip_slave_start=1的配置參數(shù)变抽,避免啟動(dòng)后還是使用老的復(fù)制協(xié)議。
方法二氮块、
1绍载、如果是新搭建的服務(wù)器,直接啟動(dòng)就行了滔蝉。
七击儡、master-slave搭建的注意事項(xiàng):
(一)、使用GTID的方式蝠引,把salve端掛載master端:
1阳谍、啟動(dòng)以后最好不要立即執(zhí)行事務(wù),而是先change master上螃概。
2矫夯、然后在執(zhí)行事務(wù),當(dāng)然知不是必須的吊洼。
3训貌、使用下面的sql切換slave到新的master。
stop slave;
CHANGE MASTER TO
MASTER_HOST='127.0.0.1',
MASTER_PORT=3306,
MASTER_USER='repl',
MASTER_PASSWORD='repl',
master_auto_position = 1;
(二)冒窍、如果給已經(jīng)運(yùn)行的GTID的master端添加一個(gè)新的slave
有兩種方法:
方法一递沪、適用于master也是新建不久的情況豺鼻。
1、如果你的master所有的binlog還在区拳【辛欤可以選擇類(lèi)似于上面的方法,安裝slave樱调,直接change master to到master端约素。
2、原理是直接獲取master所有的GTID并執(zhí)行笆凌。
3圣猎、優(yōu)點(diǎn):簡(jiǎn)單方便。
4乞而、缺點(diǎn):如果binlog太多送悔,數(shù)據(jù)完全同步需要時(shí)間較長(zhǎng),并且master一開(kāi)始就啟用了GTUD爪模。
方法二欠啤、適用于擁有較大數(shù)據(jù)的情況。(推薦)
1屋灌、通過(guò)master或者其他slave的備份搭建新的slave洁段。(看第三部分)
2、原理:獲取master的數(shù)據(jù)和這些數(shù)據(jù)對(duì)應(yīng)的GTID范圍共郭,然后通過(guò)slave設(shè)置@@global.gtid_purged跳過(guò)備份包含的gtid祠丝。
3、優(yōu)點(diǎn):是可以避免第一種方法的不足除嘹。
4写半、缺點(diǎn):相對(duì)來(lái)說(shuō)有點(diǎn)復(fù)雜。
(三)尉咕、通過(guò)備份搭建新的slave:(方法二的擴(kuò)展)
兩種方法:
方法一叠蝇、mysqldump的方式:
1、在備份的時(shí)候指定--master-data=2(來(lái)保存binlog的文件號(hào)和位置的命令)年缎。
2悔捶、使用mysqldump的命令在dump文件里可以看到下面兩個(gè)信息:
SET @@SESSION.SQL_LOG_BIN=0;
SET @@GLOBAL.GTID_PURGED='7800a22c-95ae-11e4-983d-080027de205a:1-8';
3、將備份還原到slave后晦款,使用change master to命令掛載master端炎功。
注意:在mysql5.6.9以后的命令才支持這個(gè)功能枚冗。
方法二缓溅、percona Xtrabackup
1、Xtrabackup_binlog_info文件中赁温,包含global.gtid_purged='XXXXXX:XXXX'的信息坛怪。
2淤齐、然后到slave去手工的 SET GLOBAL.GTID_PURGED='XXXXXX:XXXX'。
3袜匿、恢復(fù)備份更啄,開(kāi)啟change master to 命令。
注意:如果系統(tǒng)運(yùn)行了很久居灯,無(wú)法找到GTID的變好了祭务,可以通過(guò)上面的方式進(jìn)行查找。
八怪嫌、GTID如何跳過(guò)事務(wù)沖突:
1义锥、這個(gè)功能主要跳過(guò)事務(wù),代替原來(lái)的set global sql_slave_skip_counter = 1岩灭。
2拌倍、由于在這個(gè)GTID必須是連續(xù)的,正常情況同一個(gè)服務(wù)器產(chǎn)生的GTID是不會(huì)存在空缺的噪径。所以不能簡(jiǎn)單的skip掉一個(gè)事務(wù)柱恤,只能通過(guò)注入空事物的方法替換掉一個(gè)實(shí)際操作事務(wù)。
3找爱、注入空事物的方法:
stop slave;
set gtid_next='xxxxxxx:N';
begin;commit;
set gtid_next='AUTOMAIC';
start slave;
4梗顺、這里的xxxxx:N 也就是你的slave sql thread報(bào)錯(cuò)的GTID,或者說(shuō)是你想要跳過(guò)的GTID缴允。
九荚守、GTID的參數(shù)注釋?zhuān)?/h2>
[master]>show global variables like '%gtid%';
1、enforce_gtid_consistency:開(kāi)啟gtid的一些安全限制(介意開(kāi)啟)练般。
2矗漾、gtid_executed:全局和seeeion級(jí)別都可以用。用來(lái)保存已經(jīng)執(zhí)行過(guò)的GTIDs薄料。
貼士:show master status\G;輸出結(jié)果中的Executed_Gtid_Set和gitd_executed一致敞贡。reset master時(shí),此值會(huì)被清空摄职。
3誊役、gtid_owned:全局和session級(jí)別都可用,全局表示所有服務(wù)器擁有GTIDs谷市,session級(jí)別表示當(dāng)前client擁有所有GTIDs蛔垢。(此功能用的少)
4、gtid_mode:是否開(kāi)啟GTID功能迫悠。
5鹏漆、gtid_purged:全局參數(shù),設(shè)置在binlog中,已經(jīng)purged的GTIDs艺玲,并且purged掉的GTIDs會(huì)包含到gtid_executed中括蝠。
[master]>show global variables like '%gtid%';
1、enforce_gtid_consistency:開(kāi)啟gtid的一些安全限制(介意開(kāi)啟)练般。
2矗漾、gtid_executed:全局和seeeion級(jí)別都可以用。用來(lái)保存已經(jīng)執(zhí)行過(guò)的GTIDs薄料。
貼士:show master status\G;輸出結(jié)果中的Executed_Gtid_Set和gitd_executed一致敞贡。reset master時(shí),此值會(huì)被清空摄职。
3誊役、gtid_owned:全局和session級(jí)別都可用,全局表示所有服務(wù)器擁有GTIDs谷市,session級(jí)別表示當(dāng)前client擁有所有GTIDs蛔垢。(此功能用的少)
4、gtid_mode:是否開(kāi)啟GTID功能迫悠。
5鹏漆、gtid_purged:全局參數(shù),設(shè)置在binlog中,已經(jīng)purged的GTIDs艺玲,并且purged掉的GTIDs會(huì)包含到gtid_executed中括蝠。
貼士:從而導(dǎo)致slave不會(huì)再去master請(qǐng)求這些GTIDs,并且Executed_Gtid_Set為空時(shí)饭聚,才可以設(shè)置此值忌警。
6、gtid_next:這個(gè)時(shí)session級(jí)別的參數(shù):
[master]>show session variables like '%gtid_next%';
十秒梳、關(guān)于GTID的一些功能限制:
(一)法绵、更新非事務(wù)引擎:
1、Case重現(xiàn):
master:對(duì)一個(gè)innodb表做一個(gè)多sql更新的事物酪碘,效果是產(chǎn)生一個(gè)GTID礼烈。
slave:對(duì)應(yīng)的表是MYISAM引擎,執(zhí)行這個(gè)GTID的第一個(gè)語(yǔ)句后就會(huì)報(bào)錯(cuò)婆跑,因?yàn)榉鞘聞?wù)引擎一個(gè)sql就是一個(gè)事務(wù)此熬。
2、錯(cuò)誤編號(hào):
last_Errno:1756
3滑进、異诚溃恢復(fù)方案:
(1)、簡(jiǎn)單的stop slave; start slave;就能夠忽略錯(cuò)誤扶关。但是這個(gè)時(shí)候主從的一致性已經(jīng)出現(xiàn)問(wèn)題阴汇。需要手工的把slave差的數(shù)據(jù)補(bǔ)上。
(2)节槐、首先將引擎調(diào)整為一樣的搀庶,slave也改為事務(wù)引擎。
(二)铜异、create table ....select statements
1哥倔、case重現(xiàn):
master:直接執(zhí)行一個(gè)create table select * from table;的sql
2、報(bào)錯(cuò):
error 1786
3揍庄、原理:
由于create table ...select語(yǔ)句會(huì)生成兩個(gè)sql咆蒿,一個(gè)是DDL創(chuàng)建表SQL,一個(gè)是insert into 插入數(shù)據(jù)的sql蚂子。由于DDL會(huì)導(dǎo)致自動(dòng)提交沃测,所以這個(gè)sql至少需要兩個(gè)GTID,但是GTID模式下食茎,只能給這個(gè)sql生成一個(gè)GTID蒂破,如果強(qiáng)制執(zhí)行會(huì)導(dǎo)致和上面更新非事務(wù)引擎一樣的結(jié)果。
(三)别渔、一個(gè)sql同事操作innodb引擎和myisam引擎:
case重現(xiàn):t1表是innodb附迷,t2表是myisam
1田巴、update t1,t2 set t1.id=1000,t2.id=1000 where t1.id=t2.id;
2、報(bào)錯(cuò):1785
3挟秤、原理和第二個(gè)相同。
(四)抄伍、在一個(gè)replication grouop 中艘刚,所有的mysql必須要統(tǒng)一開(kāi)啟或者關(guān)閉GTID功能。
1截珍、case重現(xiàn):
將一個(gè)未開(kāi)啟gtid的slave通過(guò)原始的binlog和pos方式連接到開(kāi)啟GTID的master攀甚。
2、報(bào)錯(cuò):
The slave IO thread stops because the master has @@GLOBAL.GTID_MODE ON and this server has @@GLOBAL.GTID_MODE OFF岗喉。
(五)秋度、在一個(gè)replication group中,如果開(kāi)啟GTID以后钱床,就不再允許使用classic的復(fù)制方式:
1荚斯、case重現(xiàn):
將一個(gè)開(kāi)啟gtid的slave通過(guò)原始的binlog和pos方式連接到開(kāi)啟GTID的master。
2查牌、報(bào)錯(cuò):
ERROR 1776(HY000):Parameters MASTER_LOG_FILE事期,MASTER_LOG_POS,RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active纸颜。
(六)兽泣、GTID_MODE是not online的:
需要重啟才能生效,官方暫時(shí)不支持平滑的從classic replication切換到GTID replication胁孙。
貼士:
由于GTID開(kāi)啟需要重啟系統(tǒng)唠倦,一個(gè)復(fù)制組中所有的實(shí)例必須統(tǒng)一開(kāi)啟或者關(guān)閉GTID,開(kāi)啟GTID以后不能在使用classic復(fù)制。
問(wèn)題:
也就是說(shuō)在線(xiàn)業(yè)務(wù)必須統(tǒng)一關(guān)閉涮较,然后再啟動(dòng)稠鼻,會(huì)導(dǎo)致服務(wù)中斷。
解決方案:
1狂票、針對(duì)這種情況枷餐,社區(qū)有兩種對(duì)應(yīng)的平滑升級(jí)的方案:
一種是booking.com出品,這兩個(gè)差別在淘寶9月份數(shù)據(jù)庫(kù)月報(bào)里有說(shuō)明苫亦,加了一個(gè)橋接的服務(wù)器毛肋,既可以運(yùn)行GTID模式下,也可以運(yùn)行classic模式下屋剑。
另外一種是facebook.com出品润匙。所有的slave可以在開(kāi)啟GTID模式的情況下,可以連接到?jīng)]有開(kāi)啟GTID模式的master唉匾。
2孕讳、可以關(guān)閉一個(gè)部分匠楚,停止寫(xiě)操作,但是讀不用厂财,將另一部分改成GTID模式芋簿。
(七)、Temporary tables璃饱。
1与斤、create temporary table和drop temporary table語(yǔ)句一樣在GTID環(huán)境下不支持。
如果--enforce_gtid_consistency參數(shù)開(kāi)啟荚恶,并且autocommit=1撩穿,那么可以使用。
(八)谒撼、關(guān)于Errant transaction
1食寡、Errant transaction:所謂的errant transaction也就是沒(méi)有規(guī)范的從master執(zhí)行,而是直接從slave執(zhí)行的事務(wù)廓潜。
2抵皱、由于GTID協(xié)議的原因,最開(kāi)始已經(jīng)提過(guò)(參見(jiàn)GTID architecture)辩蛋。
3叨叙、如果slave有errant transaction產(chǎn)生,由于GTID協(xié)議中的規(guī)則堪澎,很容易導(dǎo)致failover失敗擂错。主要有兩種情況:
a、在slave上做了無(wú)用的或者臨時(shí)的errant transaction操作樱蛤,如果該slave升級(jí)成為master的話(huà)钮呀,連接到它的所有數(shù)據(jù)庫(kù)都會(huì)獲取到這個(gè)事務(wù)。如果一樣就會(huì)產(chǎn)生沖突昨凡。
b爽醋、由于做了這個(gè)errant transaction這個(gè)事務(wù)以后,其他的slave還沒(méi)有獲取這個(gè)errant transaction的GTID便脊,需要從master上發(fā)同步給其他的slave蚂四,但是主的binlog又被刪掉了,這時(shí)將會(huì)報(bào)錯(cuò)哪痰。
4遂赠、總之:盡量避免產(chǎn)生errant transaction∩谓埽可以通過(guò):set sql_log_bin=off的方式在slave執(zhí)行sql跷睦,但是也要考慮到數(shù)據(jù)一致性。
··············跳過(guò)錯(cuò)誤
從庫(kù)已經(jīng)執(zhí)行過(guò)的事務(wù)是'e10c75be-5c1b-11e6-ab7c-000c296078ae:1-5',執(zhí)行出錯(cuò)的事務(wù)是'e10c75be-5c1b-11e6-ab7c-000c296078ae:6'肋演,當(dāng)前主備的數(shù)據(jù)其實(shí)是一致的抑诸,可以通過(guò)設(shè)置gtid_next跳過(guò)這個(gè)出錯(cuò)的事務(wù)烂琴。
在從庫(kù)上執(zhí)行以下SQL:
mysql> set gtid_next='e10c75be-5c1b-11e6-ab7c-000c296078ae:6';
Query OK, 0 rows affected (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> set gtid_next='AUTOMATIC';
Query OK, 0 rows affected (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
設(shè)置gtid_next的方法一次只能跳過(guò)一個(gè)事務(wù),要批量的跳過(guò)事務(wù)可以通過(guò)設(shè)置gtid_purged完成蜕乡。
十一奸绷、GTID與crash safe salve
crash safe slave是MySQL 5.6提供的功能,意思是說(shuō)在slave crash后层玲,把slave重新拉起來(lái)可以繼續(xù)從Master進(jìn)行復(fù)制号醉,不會(huì)出現(xiàn)復(fù)制錯(cuò)誤也不會(huì)出現(xiàn)數(shù)據(jù)不一致。
1称簿、基于binlog文件位置的復(fù)制
在基于binlog文件位置的復(fù)制下,要保證crash safe slave惰帽,配置下面的參數(shù)即可憨降。
relay_log_info_repository = TABLE
relay_log_recovery = ON
這樣可行的原因是,relay_log_info_repository = TABLE時(shí)该酗,apply event和更新relay_log_info表的操作被包含在同一個(gè)事務(wù)里授药,innodb要么讓它們同時(shí)生效,要么同時(shí)不生效,保證位點(diǎn)信息和已經(jīng)應(yīng)用的事務(wù)精確匹配呜魄。同時(shí)relay_log_recovery = ON時(shí)悔叽,會(huì)拋棄master_log_info中記錄的復(fù)制位點(diǎn),根據(jù)relay_log_info的執(zhí)行位置重新從Master獲取binlog爵嗅,這就回避了由于未同步刷盤(pán)導(dǎo)致的binlog文件接受位置和實(shí)際不一致以及relay log文件被截?cái)嗟膯?wèn)題娇澎。
在同時(shí)使用MTS(multi-threaded slave)時(shí),為保證crash safe slave基于binlog文件位置的復(fù)制還需要設(shè)置sync_relay_log=1,因?yàn)镸ySQL在Crash恢復(fù)時(shí)必須先通過(guò)讀取relay log補(bǔ)齊MTS導(dǎo)致的事務(wù)空洞睹晒。
2趟庄、基于GTID的復(fù)制
上面的設(shè)置并不適用于基于GTID的復(fù)制。在基于GTID的復(fù)制下伪很,crash的Slave重啟后戚啥,從binlog中解析的gtid_executed決定了要apply哪些binlog記錄,所以binlog必須和innodb存儲(chǔ)引擎的數(shù)據(jù)保持一致锉试。要做到這一點(diǎn)猫十,需要把sync_binlog和innodb_flush_log_at_trx_commit都設(shè)置為1,即所謂的"雙1"呆盖。
另外MySQL啟動(dòng)時(shí)拖云,會(huì)從relay log文件中獲取已接收的GTIDs并更新Retrieved_Gtid_Set。由于relay log文件可能不完整应又,所以需要拋棄已接收的relay log文件江兢。因此relay_log_recovery = ON也是必須的。
這樣丁频,對(duì)于基于GTID的復(fù)制杉允,保證crash safe slave的設(shè)置就是下面這樣邑贴。
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
relay_log_recovery = ON
關(guān)于如何設(shè)置以確保crash safe slave,官方文檔有明確記載叔磷,見(jiàn) 17.3.2 Handling an Unexpected Halt of a Replication Slave拢驾。
但是其中關(guān)于GTID的記載中存在筆誤,將relay_log_recovery=1寫(xiě)成了relay_log_recovery=0 (#83711)。同時(shí)也沒(méi)有提到必須設(shè)置"雙1"改基,但是"雙1"是必要的繁疤,否則crash的Slave重啟后,可能會(huì)重復(fù)應(yīng)用binlog event也可能會(huì)遺漏應(yīng)用binlog event(#70659)秕狰。其中遺漏應(yīng)用binlog event的情況更可怕稠腊,因?yàn)镾lave在不觸發(fā)SQL錯(cuò)誤的情況下就默默的和Master不一致了。
3鸣哀、設(shè)置"雙1"對(duì)性能的影響
出于安全考慮架忌,強(qiáng)烈推薦設(shè)置"雙1"。"雙1"會(huì)增大每個(gè)事務(wù)的RT我衬,但得益于MySQL的組提交機(jī)制叹放,高并發(fā)下"雙1"對(duì)系統(tǒng)整體tps的影響在可接受范圍內(nèi)。
sysbench oltp.lua 10張表每張表100w記錄(qps/并發(fā)數(shù))
對(duì)更新同一行這樣無(wú)法有效并行的場(chǎng)景挠羔,"雙1"對(duì)性能的影響非常大井仰。
sysbench update_non_index.lua 1張表1條記錄(qps/并發(fā)數(shù))
對(duì)不能有效并行的Slave replay,存在同樣的問(wèn)題破加。
通過(guò)指定tx-rate執(zhí)行sysbench的update_non_index.lua腳本壓測(cè)30秒俱恶,完成后檢查主備延遲。
可以發(fā)現(xiàn)在Slave被配置為"雙1"的情況下范舀,延遲非常嚴(yán)重,1000以上的QPS就會(huì)出現(xiàn)延遲速那,非"雙1"下QPS到5000以上才會(huì)出現(xiàn)延遲(主庫(kù)配置為"雙1")。
sysbench update_non_index.lua 1張表100w條記錄 128并發(fā)(延遲/qps)
以上測(cè)試環(huán)境是Percona Server 5.6運(yùn)行在配置HDD的8 core虛機(jī)尿背,由于測(cè)試結(jié)果和系統(tǒng)IO能力有很大關(guān)系端仰,僅供參考。
4田藐、如何在非"雙1"下保證crash safe slave
如果是MySQL 5.7可以關(guān)閉log_slave_updates荔烧,這樣MySQL會(huì)將已執(zhí)行的GTIDs實(shí)時(shí)記錄到系統(tǒng)表mysql.gtid_executed中,mysql.gtid_executed是和用戶(hù)事務(wù)一起提交的汽久,因此可以保證和實(shí)際的數(shù)據(jù)一致鹤竭。
log_slave_updates = OFF
relay_log_recovery = ON
如果是MySQL 5.6可以采用如下變通的方式。
按照基于binlog文件復(fù)制時(shí)crash safe slave的要求設(shè)置
relay_log_info_repository = TABLE
relay_log_info_repository = TABLE
relay_log_recovery = ON
在Slave crash后景醇,根據(jù)relay_log_info_repository設(shè)置相應(yīng)的gitd_purged再開(kāi)啟復(fù)制臀稚,
步驟如下:
1.啟動(dòng)MySQL,但不開(kāi)啟復(fù)制
mysqld --skip-slave-start
2.在Slave上修改為基于binlog文件位置的復(fù)制
change master to MASTER_AUTO_POSITION = 0
3.啟動(dòng)slave IO線(xiàn)程
start slave io_thread
這里不能啟動(dòng)SQL線(xiàn)程三痰,如果接受到的GTID已經(jīng)在Slave的gtid_executed里了吧寺,會(huì)被Slave skip掉窜管。
4.檢查binlog傳輸?shù)拈_(kāi)始位置(即Retrieved_Gtid_Set的值)
show slave status\G
假設(shè)輸出的Retrieved_Gtid_Set值為e10c75be-5c1b-11e6-ab7c-000c296078ae:7-10
5.在Master上檢查gtid_executed
show master status
假設(shè)輸出的Executed_Gtid_Set值為e10c75be-5c1b-11e6-ab7c-000c296078ae:1-10
6.在Slave上設(shè)置gitd_purged為binlog傳輸位置的前面的GTID的集合
reset master;
set global gitd_purged='e10c75be-5c1b-11e6-ab7c-000c296078ae:1-6';
7.修改回auto position的復(fù)制
change master to MASTER_AUTO_POSITION = 1
8.啟動(dòng)slave SQL線(xiàn)程
start slave sql_thread
但是,這種變通的方法不適合多線(xiàn)程復(fù)制稚机。因?yàn)槎嗑€(xiàn)程復(fù)制可能產(chǎn)生gtid gap和Gap-free low-watermark position幕帆,這會(huì)導(dǎo)致Salve上重復(fù)apply已經(jīng)apply過(guò)的event赖条。后果就是數(shù)據(jù)不一致或者復(fù)制中斷失乾,除非設(shè)置binlog格式為row模式并且slave_exec_mode=IDEMPOTENT,slave_exec_mode=IDEMPOTENT允許Slave回放binlog時(shí)忽略重復(fù)鍵和找不到鍵的錯(cuò)誤,使得binlog回放具有冪等性,但這也意味著如果真的出現(xiàn)了主備數(shù)據(jù)不一致也會(huì)被它忽略诅蝶。
5、MTS下特有的問(wèn)題
在同時(shí)使用MTS(slave_parallel_workers > 1)時(shí),即使按上面crash safe slave的要求設(shè)置了基于GTID的復(fù)制代嗤,Slave crash后再重啟還是會(huì)導(dǎo)致復(fù)制中斷硝逢。
通過(guò)強(qiáng)制殺掉MySQL所在虛機(jī)的方式模擬Slave宕機(jī),然后再啟動(dòng)MySQL憨奸,MySQL日志中有如下錯(cuò)誤消息:
啟動(dòng)slave時(shí)也會(huì)報(bào)錯(cuò)
mysql> start slave;
ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository
出現(xiàn)這種現(xiàn)象的原因在于额各,relay_log_recovery=1 且 slave_parallel_workers>1的情況下傲醉,mysql啟動(dòng)時(shí)會(huì)進(jìn)入MTS Group恢復(fù)流程,即讀取relay log逻悠,嘗試填補(bǔ)由于多線(xiàn)程復(fù)制導(dǎo)致的gap饥伊。然后relay log文件由于不是實(shí)時(shí)刷新的茫因,在relay log文件中找不到gap對(duì)應(yīng)的relay log記錄(覆蓋了gap的relay log起始和結(jié)束位置分別被稱(chēng)為低水位和高水位,低水位點(diǎn)即slave_relay_log_info.Relay_log_pos的值)就會(huì)報(bào)這個(gè)錯(cuò)翼雀。
實(shí)際上狈邑,在GTID模式下城须,slave在apply event的時(shí)候可以跳過(guò)重復(fù)事件,所以可以安全的從低水位點(diǎn)應(yīng)用日志米苹,沒(méi)必要解析relay log文件糕伐。 這看上去是一個(gè)bug,于是提交了一個(gè)bug報(bào)告#83713蘸嘶,目前還沒(méi)有收到回復(fù)良瞧。
作為回避方法,可以通過(guò)清除relay log文件训唱,跳過(guò)這個(gè)錯(cuò)誤褥蚯。執(zhí)行步驟如下:
reset slave;
change master to MASTER_AUTO_POSITION = 1
start slave;
在這里,單純的調(diào)reset slave不能把狀態(tài)清理干凈况增,內(nèi)部的Relay_log_info.inited標(biāo)志位仍然處于未被初始化狀態(tài),此時(shí)調(diào)用start slave仍然會(huì)失敗赞庶。因此需要補(bǔ)一刀change master。
6澳骤、Master的crash safe
前面一直在講crash safe slave歧强,Master的crash safe同樣重要。 要想Master保持crash safe需要按下面的參數(shù)進(jìn)行設(shè)置为肮,否則不僅會(huì)丟失事務(wù)摊册,gtid_executed還可能和實(shí)際的innodb存儲(chǔ)引擎中的數(shù)據(jù)不一致。
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
在Master配置為"雙1"的情況下弥锄,Master crash后丧靡,如果沒(méi)有發(fā)生failover蟆沫,可以繼續(xù)作為Master籽暇。 如果發(fā)生了failover,可以檢查舊Master和新Master上由舊Master執(zhí)行的事務(wù)集合是否一致饭庞。
show master status
如果一致戒悠,可以按MASTER_AUTO_POSITION = 1的方式將舊Master作為Slave和新Master建立復(fù)制關(guān)系。否則舟山,考慮做事務(wù)補(bǔ)償或從新Master上拉取備份進(jìn)行恢復(fù)绸狐。
在Master配置不是"雙1"的情況下,在Master crash后由于難以準(zhǔn)確知道舊Master上究竟執(zhí)行了哪些事務(wù)累盗,安全的做法是實(shí)施主備切換寒矿,并從新Master上拉取備份,把舊Master作為新Master的Slave進(jìn)行恢復(fù)若债。
文章轉(zhuǎn)載https://www.cnblogs.com/icyblog/p/7241040.htm