一、雙主保證高可用
MySQL數據庫集群常使用一主多從,主從同步,讀寫分離的方式來擴充數據庫的讀性能,保證讀庫的高可用,但此時寫庫仍然是單點。
在一個MySQL數據庫集群中可以設置兩個主庫,並設置雙向同步,以冗余寫庫的方式來保證寫庫的高可用。
二、並發引發不一致
數據冗余會引發數據的一致性問題,因為數據的同步有一個時間差,並發的寫入可能導致數據同步失敗,引起數據丟失:
如上圖所述,假設主庫使用了auto increment來作為自增主鍵:
-
兩個MySQL-master設置雙向同步可以用來保證主庫的高可用
-
數據庫中現存的記錄主鍵是1,2,3
-
主庫1插入了一條記錄,主鍵為4,並向主庫2同步數據
-
數據同步成功之前,主庫2也插入了一條記錄,由於數據還沒有同步成功,插入記錄生成的主鍵也為4,並向主庫1也同步數據
-
主庫1和主庫2都插入了主鍵為4的記錄,雙主同步失敗,數據不一致
三、相同步長免沖突
能否保證兩個主庫生成的主鍵一定不沖突呢?
回答:
-
設置不同的初始值
-
設置相同的增長步長
就能夠做到。
如上圖所示:
-
兩個MySQL-master設置雙向同步可以用來保證主庫的高可用
-
庫1的自增初始值是1,庫2的自增初始值是2,增長步長都為2
-
庫1中插入數據主鍵為1/3/5/7,庫2中插入數據主鍵為2/4/6/8,不沖突
-
數據雙向同步后,兩個主庫會包含全部數據
如上圖所示,兩個主庫最終都將包含1/2/3/4/5/6/7/8所有數據,即使有一個主庫掛了,另一個主庫也能夠保證寫庫的高可用。
四、上游生成ID避沖突
換一個思路,為何要依賴於數據庫的自增ID,來保證數據的一致性呢?
完全可以由業務上游,使用統一的ID生成器,來保證ID的生成不沖突:
如上圖所示,調用方插入數據時,帶入全局唯一ID,而不依賴於數據庫的auto increment,也能解決這個問題。
至於如何生成全局唯一,趨勢遞增的ID,參見文章《分布式ID生成算法》。
五、消除雙寫不治本
使用auto increment兩個主庫並發寫可能導致數據不一致,只使用一個主庫提供服務,另一個主庫作為shadow-master,只用來保證高可用,能否避免一致性問題呢?
如上圖所示:
-
兩個MySQL-master設置雙向同步可以用來保證主庫的高可用
-
只有主庫1對外提供寫入服務
-
兩個主庫設置相同的虛IP,在主庫1掛掉或者網絡異常的時候,虛IP自動漂移,shadow master頂上,保證主庫的高可用
這個切換由於虛IP沒有變化,所以切換過程對調用方是透明的,但在極限的情況下,也可能引發數據的不一致:
如上圖所示:
-
兩個MySQL-master設置雙向同步可以用來保證主庫的高可用,並設置了相同的虛IP
-
網絡抖動前,主庫1對上游提供寫入服務,插入了一條記錄,主鍵為4,並向shadow master主庫2同步數據
-
突然主庫1網絡異常,keepalived檢測出異常后,實施虛IP漂移,主庫2開始提供服務
-
在主鍵4的數據同步成功之前,主庫2插入了一條記錄,也生成了主鍵為4的記錄,結果導致數據不一致
六、內網DNS探測
虛IP漂移,雙主同步延時導致的數據不一致,本質上,需要在雙主同步完數據之后,再實施虛IP偏移,使用內網DNS探測,可以實現shadow master延時高可用:
-
使用內網域名連接數據庫,例如:db.58daojia.org
-
主庫1和主庫2設置雙主同步,不使用相同虛IP,而是分別使用ip1和ip2
-
一開始db.58daojia.org指向ip1
-
用一個小腳本輪詢探測ip1主庫的連通性
-
當ip1主庫發生異常時,小腳本delay一個x秒的延時,等待主庫2同步完數據之后,再將db.58daojia.org解析到ip2
-
程序以內網域名進行重連,即可自動連接到ip2主庫,並保證了數據的一致性
七、總結
主庫高可用,主庫一致性,一些小技巧:
-
雙主同步是一種常見的保證寫庫高可用的方式
-
設置相同步長,不同初始值,可以避免auto increment生成沖突主鍵
-
不依賴數據庫,業務調用方自己生成全局唯一ID是一個好方法
-
shadow master保證寫庫高可用,只有一個寫庫提供服務,並不能完全保證一致性
-
內網DNS探測,可以實現在主庫1出現問題后,延時一個時間,再進行主庫切換,以保證數據一致性