MySQL主備數(shù)據(jù)流轉(zhuǎn)流程
備庫B和主庫A維持了一個長連接
1、在備庫 B 上通過 change master 命令拆祈,設(shè)置主庫 A 的 IP逊脯、端口徘公、用戶名末患、密碼研叫,以及要從哪個位置開始請求 binlog,這個位置包含文件名和日志偏移量璧针。
2嚷炉、在備庫 B 上執(zhí)行 start slave 命令,這時候備庫會啟動兩個線程探橱,就是圖中的 io_thread 和 sql_thread申屹。其中 io_thread 負責與主庫建立連接。
3隧膏、主庫 A 校驗完用戶名哗讥、密碼后,開始按照備庫 B 傳過來的位置胞枕,從本地讀取 binlog杆煞,發(fā)給 B。
4腐泻、備庫 B 拿到 binlog 后决乎,寫到本地文件,稱為中轉(zhuǎn)日志(relay log)贫悄。
5瑞驱、sql_thread 讀取中轉(zhuǎn)日志,解析出日志里的命令窄坦,并執(zhí)行唤反。
binlog的三種格式
statement
當 binlog_format=statement 時,binlog 里面記錄的就是 SQL 語句的原文鸭津。但是對于下列語句全是不安全了彤侍,可能會導(dǎo)致主備不一致,因為如果選擇的索引不一樣逆趋,刪除的行也不一樣
mysql> delete from t /*comment*/ where a>=4 and t_modified<='2018-11-10' limit 1;
row
當 binlog_format 使用 row 格式的時候盏阶,binlog 里面記錄了真實刪除行的主鍵 id,這樣 binlog 傳到備庫去的時候闻书,就肯定會刪除 id=4 的行名斟,不會有主備刪除不同行的問題
mixed statement和row混合
- 因為有些 statement 格式的 binlog 可能會導(dǎo)致主備不一致,所以要使用 row 格式魄眉。
- 但 row 格式的缺點是砰盐,很占空間。比如你用一個 delete 語句刪掉 10 萬行數(shù)據(jù)坑律,用 statement 的話就是一個 SQL 語句被記錄到 binlog 中岩梳,占用幾十個字節(jié)的空間。但如果用 row 格式的 binlog,就要把這 10 萬條記錄都寫到 binlog 中冀值。這樣做也物,不僅會占用更大的空間,同時寫 binlog 也要耗費 IO 資源列疗,影響執(zhí)行速度滑蚯。
因此,MySQL 就取了個折中方案作彤,也就是有了 mixed 格式的 binlog膘魄。mixed 格式的意思是,MySQL 自己會判斷這條 SQL 語句是否可能引起主備不一致竭讳,如果有可能创葡,就用 row 格式,否則就用 statement 格式
當然我要說的是绢慢,現(xiàn)在越來越多的場景要求把 MySQL 的 binlog 格式設(shè)置成 row灿渴。因為恢復(fù)數(shù)據(jù)會比較方便,能清晰地恢復(fù)對應(yīng)id的數(shù)據(jù)胰舆,而statement則不好做骚露。
循環(huán)復(fù)制問題
雙 Master 結(jié)構(gòu)循環(huán)同步binlog問題:
- 規(guī)定兩個庫的 server id 必須不同,如果相同缚窿,則它們之間不能設(shè)定為主備關(guān)系棘幸;
- 一個備庫接到 binlog 并在重放的過程中,生成與原 binlog 的 server id 相同的新的 binlog倦零;
- 每個庫在收到從自己的主庫發(fā)過來的日志后误续,先判斷 server id,如果跟自己的相同扫茅,表示這個日志是自己生成的蹋嵌,就直接丟棄這個日志。
日志在備庫上的執(zhí)行葫隙,就是圖中備庫上 sql_thread 更新數(shù)據(jù) (DATA) 的邏輯栽烂。如果是用單線程的話,就會容易導(dǎo)致備庫應(yīng)用日志不夠快恋脚,造成主備延遲腺办。
在官方的 5.6 版本之前,MySQL 只支持單線程復(fù)制糟描,由此在主庫并發(fā)高菇晃、TPS 高時就會出現(xiàn)嚴重的主備延遲問題。
官方 MySQL5.6 版本蚓挤,支持了并行復(fù)制,只是支持的粒度是按庫并行。理解了上面介紹的按表分發(fā)策略和按行分發(fā)策略灿意,你就理解了估灿,用于決定分發(fā)策略的 hash 表里,key 就是數(shù)據(jù)庫名缤剧。