Mysql-8.0.2 高可用MGR(一) 理論

一、背景

主從復(fù)制,一主多從,主庫提供讀寫功能,從庫提供只讀功能。當(dāng)一個(gè)事務(wù)在master 提交成功時(shí),會(huì)把binlog文件同步到從庫服務(wù)器上落地為relay log給slave端執(zhí)行,這個(gè)過程主庫是不考慮從庫是否有接收到binlog文件,有可能出現(xiàn)這種情況,當(dāng)主庫commit一個(gè)事務(wù)后,數(shù)據(jù)庫發(fā)生宕機(jī),剛好它的binlog還沒來得及傳送到slave端,這個(gè)時(shí)候選任何一個(gè)slave端都會(huì)丟失這個(gè)事務(wù),造成數(shù)據(jù)不一致情況。 為了避免出現(xiàn)主從數(shù)據(jù)不一致的情況,MySQL引入了半同步復(fù)制,添加多了一個(gè)從庫反饋機(jī)制,即半同步復(fù)制。這個(gè)有兩種方式設(shè)置:

  1. 主庫執(zhí)行完事務(wù)后,同步binlog給從庫,從庫ack反饋接收到binlog,主庫提交commit,反饋給客戶端,釋放會(huì)話;
  2. 主庫執(zhí)行完事務(wù)后,主庫提交commit ,同步binlog給從庫,從庫ack反饋接收到binlog,反饋給客戶端,釋放會(huì)話;

雖然滿足了一主多從,讀寫分析,數(shù)據(jù)一致,但是,依舊有兩個(gè)弊端:

  1. 寫操作只能在master上;
  2. 如果master宕機(jī),需要人為選擇新主并重新給其他的slave端執(zhí)行change master;

為了解決一系列問題,官方推出了MySQL Group Replication,從group replication發(fā)布以后,就有3種方法來實(shí)現(xiàn)MySQL的高可用集群:

  • 異步復(fù)制
  • 半同步復(fù)制
  • group replication

二、Group Replication原理

MySQL Group Replication有兩種模式,單主模式single-primary mode和多主模式multi-primary mode,在同一個(gè)group內(nèi),不允許兩種模式同時(shí)存在,并且若要切換到不同模式,必須修改配置后重新啟動(dòng)集群。

1、單主模式

在單主模式下,只有一個(gè)節(jié)點(diǎn)可以讀寫,其他節(jié)點(diǎn)提供只讀服務(wù)。單主模式下 ,當(dāng)主節(jié)點(diǎn)宕掉,自動(dòng)會(huì)根據(jù)服務(wù)器的 server_uuid 變量和 group_replication_member_weight 變量值,選擇下一個(gè) slave 誰作為主節(jié)點(diǎn),group_replication_member_weight 的值最高的成員被選為新的主節(jié)點(diǎn),該參數(shù)默認(rèn)為50,建議可以在節(jié)點(diǎn)上設(shè)置不同值;在 group_replication_member_weight 值相同的情況下,group 根據(jù)數(shù)據(jù)字典中 server_uuid排序,排序在最前的被選擇為主節(jié)點(diǎn)。

2、多主模式

在 mysql 多主模式下,在組復(fù)制中通過 Group Replication Protocol 協(xié)議及 Paxos 協(xié)議(一致性算法),形成的整體高可用解決方案,同時(shí)增加了certify(認(rèn)證) 的概念,負(fù)責(zé)檢查事務(wù)是否允許提交,是否與其它事務(wù)存在沖突,Group Replication是由多個(gè)節(jié)點(diǎn)共同組成一個(gè)數(shù)據(jù)庫集群,每個(gè)節(jié)點(diǎn)都可以單獨(dú)執(zhí)行事務(wù),但是 read-write(rw)的操作只有在組內(nèi)驗(yàn)證后才可以commit,Read-only (RO)事務(wù)是不需要驗(yàn)證可以立即執(zhí)行,當(dāng)一個(gè)事務(wù)在一個(gè)節(jié)點(diǎn)上提交之前,會(huì)在組內(nèi)自動(dòng)進(jìn)行原子性的廣播,告知其他節(jié)點(diǎn)變更了什么內(nèi)容/執(zhí)行了什么事務(wù),然后為該事物建立一個(gè)全局的排序,最終,這意味著所有的服務(wù)器都以相同的順序接收相同的事務(wù)集。因此,所有服務(wù)器都按照相同的順序應(yīng)用相同的變更集,因此它們?cè)诮M中保持一致。 在多主模式下,該組的所有成員都設(shè)置為讀寫模式,在多主模式下,不支持 SERIALIZABLE(嚴(yán)格的) 事務(wù)隔離級(jí)別,且不能完全支持級(jí)聯(lián)外鍵約束。

3、事物隔離級(jí)別補(bǔ)充

Read Committed

在Read Committed隔離級(jí)別下,一個(gè)事務(wù)可能會(huì)遇到不可重復(fù)讀(Non Repeatable Read)的問題。不可重復(fù)讀是指,在一個(gè)事務(wù)內(nèi),多次讀同一數(shù)據(jù),在這個(gè)事務(wù)還沒有結(jié)束時(shí),如果另一個(gè)事務(wù)恰好修改了這個(gè)數(shù)據(jù),那么,在第一個(gè)事務(wù)中,兩次讀取的數(shù)據(jù)就可能不一致。
我們先準(zhǔn)備好 students 表的數(shù)據(jù):

mysql> select * from students;
+----+-------+
| id | name  |
+----+-------+
|  1 | Alice |
+----+-------+
1 row in set (0.00 sec)

然后,分別開啟兩個(gè)MySQL客戶端連接,按順序依次執(zhí)行事務(wù)A和事務(wù)B:

時(shí)刻 事務(wù)A 事務(wù)B
1 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
2 BEGIN; BEGIN;
3 SELECT * FROM students WHERE id = 1;
4 UPDATE students SET name = 'Bob' WHERE id = 1;
5 COMMIT;
6 SELECT * FROM students WHERE id = 1;
7 COMMIT;

當(dāng)事務(wù)B第一次執(zhí)行第3步的查詢時(shí),得到的結(jié)果是Alice,隨后,由于事務(wù)A在第4步更新了這條記錄并提交,所以,事務(wù)B在第6步再次執(zhí)行同樣的查詢時(shí),得到的結(jié)果就變成了Bob,因此,在Read Committed隔離級(jí)別下,事務(wù)不可重復(fù)讀同一條記錄,因?yàn)楹芸赡茏x到的結(jié)果不一致。

Serializable

Serializable是最嚴(yán)格的隔離級(jí)別。在Serializable隔離級(jí)別下,所有事務(wù)按照次序依次執(zhí)行,因此,臟讀、不可重復(fù)讀、幻讀都不會(huì)出現(xiàn)。

雖然Serializable隔離級(jí)別下的事務(wù)具有最高的安全性,但是,由于事務(wù)是串行執(zhí)行,所以效率會(huì)大大下降,應(yīng)用程序的性能會(huì)急劇降低。如果沒有特別重要的情景,一般都不會(huì)使用Serializable隔離級(jí)別。

默認(rèn)隔離級(jí)別
如果沒有指定隔離級(jí)別,數(shù)據(jù)庫就會(huì)使用默認(rèn)的隔離級(jí)別。在MySQL中,如果使用InnoDB,默認(rèn)的隔離級(jí)別是Repeatable Read。

Repeatable Read

在Repeatable Read隔離級(jí)別下,一個(gè)事務(wù)可能會(huì)遇到幻讀(Phantom Read)的問題。幻讀是指,在一個(gè)事務(wù)中,第一次查詢某條記錄,發(fā)現(xiàn)沒有,但是,當(dāng)試圖更新這條不存在的記錄時(shí),竟然能成功,并且,再次讀取同一條記錄,它就神奇地出現(xiàn)了。

mysql> select * from students;
+----+-------+
| id | name  |
+----+-------+
|  1 | Alice |
+----+-------+
1 row in set (0.00 sec)

然后,分別開啟兩個(gè)MySQL客戶端連接,按順序依次執(zhí)行事務(wù)A和事務(wù)B:

時(shí)刻 事務(wù)A 事務(wù)B
1 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
2 BEGIN; BEGIN;
3 SELECT * FROM students WHERE id = 99;
4 INSERT INTO students (id, name) VALUES (99, 'Bob');
5 COMMIT;
6 SELECT * FROM students WHERE id = 99;
7 UPDATE students SET name = 'Alice' WHERE id = 99;
8 SELECT * FROM students WHERE id = 99;
9 COMMIT;

事務(wù)B在第3步第一次讀取id=99的記錄時(shí),讀到的記錄為空,說明不存在id=99的記錄。隨后,事務(wù)A在第4步插入了一條id=99的記錄并提交。事務(wù)B在第6步再次讀取id=99的記錄時(shí),讀到的記錄仍然為空,但是,事務(wù)B在第7步試圖更新這條不存在的記錄時(shí),竟然成功了,并且,事務(wù)B在第8步再次讀取id=99的記錄時(shí),記錄出現(xiàn)了。

可見,幻讀就是沒有讀到的記錄,以為不存在,但其實(shí)是可以更新成功的,并且,更新成功后,再次讀取,就出現(xiàn)了。

Read Uncommitted

Read Uncommitted是隔離級(jí)別最低的一種事務(wù)級(jí)別。在這種隔離級(jí)別下,一個(gè)事務(wù)會(huì)讀到另一個(gè)事務(wù)更新后但未提交的數(shù)據(jù),如果另一個(gè)事務(wù)回滾,那么當(dāng)前事務(wù)讀到的數(shù)據(jù)就是臟數(shù)據(jù),這就是臟讀(Dirty Read)。

mysql> select * from students;
+----+-------+
| id | name  |
+----+-------+
|  1 | Alice |
+----+-------+
1 row in set (0.00 sec)

然后,分別開啟兩個(gè)MySQL客戶端連接,按順序依次執(zhí)行事務(wù)A和事務(wù)B:

時(shí)刻 事務(wù)A 事務(wù)B
1 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
2 BEGIN; BEGIN;
3 UPDATE students SET name = 'Bob' WHERE id = 1;
4 SELECT * FROM students WHERE id = 1;
5 ROLLBACK;
6 SELECT * FROM students WHERE id = 1;
7 COMMIT;

當(dāng)事務(wù)A執(zhí)行完第3步時(shí),它更新了id=1的記錄,但并未提交,而事務(wù)B在第4步讀取到的數(shù)據(jù)就是未提交的數(shù)據(jù)。隨后,事務(wù)A在第5步進(jìn)行了回滾,事務(wù)B再次讀取id=1的記錄,發(fā)現(xiàn)和上一次讀取到的數(shù)據(jù)不一致,這就是臟讀??梢?,在Read Uncommitted隔離級(jí)別下,一個(gè)事務(wù)可能讀取到另一個(gè)事務(wù)更新但未提交的數(shù)據(jù),這個(gè)數(shù)據(jù)有可能是臟數(shù)據(jù)。

三、配置要求限制

  • inndb存儲(chǔ)引擎;
  • 每個(gè)表需要定義顯式主鍵;
  • 隔離級(jí)別:官網(wǎng)建議 READ COMMITTED 級(jí)別,不支持 SERIALIZABLE 隔離級(jí)別;
  • 不建議使用級(jí)聯(lián)外鍵;
  • IPv4網(wǎng)絡(luò);
  • auto_increment_increment和auto_increment_offset的配置;
  • log-bin = ROW;
  • log_slave_updates = ON;
  • 開啟GTID;
  • 安裝引擎:group_replication.so;

四、mysql主從可以有多少個(gè)

可以成為一個(gè)復(fù)制組成員的MySQL服務(wù)器的最大數(shù)量為9。如果其他成員嘗試加入該組,則其請(qǐng)求將被拒絕。從測(cè)試和基準(zhǔn)測(cè)試中可以確定此限制是安全的邊界,在此范圍內(nèi),組可以在穩(wěn)定的局域網(wǎng)上可靠地運(yùn)行。

五、auto_increment_increment

在服務(wù)器上啟動(dòng)組復(fù)制時(shí),auto_increment_increment的值將更改為group_replication_auto_increment_increment的值(默認(rèn)值為7),而auto_increment_offset的值將更改為服務(wù)器ID。 停止組復(fù)制時(shí),將還原更改。 這些設(shè)置避免為組成員上的寫入選擇重復(fù)的自動(dòng)增量值,這會(huì)導(dǎo)致事務(wù)回滾。 組復(fù)制的默認(rèn)自動(dòng)增量值為7,表示可用值數(shù)與復(fù)制組的允許最大大?。?個(gè)成員)之間的平衡。

僅當(dāng)auto_increment_increment和auto_increment_offset各自的默認(rèn)值均為1時(shí),才進(jìn)行更改并還原。如果已將其值從默認(rèn)值修改,則組復(fù)制不會(huì)更改它們。 從MySQL 8.0開始,當(dāng)組復(fù)制處于只有一個(gè)服務(wù)器寫入的單主模式下時(shí),系統(tǒng)變量也不會(huì)被修改。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容