我C,MySQL雙主架構,原來能這麼玩
經常有朋友問,MySQL雙主的一致性問題,今天簡單聊一聊。
MySQL為什麼要使用雙主架構?
MySQL最常見的叢集架構,是一主多從,主從同步,讀寫分離的架構。通過這種方式,能夠擴充資料庫的讀效能,保證讀庫的高可用,但此時寫庫仍然是單點。
為了保證MySQL寫庫的高可用,可以在一個MySQL資料庫叢集中可以設定兩個主庫,並設定雙向同步,以冗餘寫庫的方式,來保證寫庫的高可用。
MySQL雙主架構,會存在什麼問題?
如果MySQL雙主架構,同時提供服務,可能會引發資料的一致性問題。因為資料的同步有一個時間差,併發的寫入可能導致資料同步失敗,引起資料丟失。
舉個栗子:
如上圖所述,假設主庫使用了auto increment來作為自增主鍵:
(2)資料庫中現存的記錄主鍵是1,2,3;
(3)主庫1插入了一條記錄,主鍵為4,並向主庫2同步資料;
(4)資料同步成功之前,主庫2也插入了一條記錄,由於資料還沒有同步成功,插入記錄生成的主鍵也為4,並向主庫1也同步資料;
(5)主庫1和主庫2都插入了主鍵為4的記錄,雙主同步失敗,資料不一致;
能否在MySQL層面,保證兩個主庫生成的主鍵一定不衝突呢?
可以的,只需要為兩個主庫的自增ID:
(1)設定不同的初始值;
(2)設定相同的增長步長;
如上圖所示:
(1)兩個MySQL主庫設定雙向同步可以用來保證主庫的高可用;
(2)庫1的自增初始值是1,庫2的自增初始值是2,增長步長都為2;
(4)資料雙向同步後,兩個主庫會包含全部資料;
如上圖所示,兩個主庫最終都將包含1/2/3/4/5/6/7/8所有資料,即使有一個主庫掛了,另一個主庫也能夠保證寫庫的高可用。
上述方案,依賴與資料庫的配置,能不能由應用程式,來保證資料的一致性呢?
答案是肯定的,應用程式使用統一的ID生成器,可以保證ID的生成不衝突。
如上圖所示,呼叫方插入資料時,帶入全域性唯一ID,而不依賴於資料庫的auto increment,也能解決這個問題。
畫外音:如何生成全域性唯一趨勢遞增的ID,不展開。
引發不一致的根本原因,是保證高可用的兩個主庫都對外提供服務,如果只有一個主庫對外提供服務,另一個主庫平時不提供服務,僅僅在主庫掛了的時候提供服務,能否消除上述資料不一致呢?
使用虛IP+keepalived的方式保證資料庫主庫的高可用,平時只有一臺主庫提供服務,也可能出現數據不一致。
如上圖所示:
(1)兩個MySQL主庫設定雙向同步可以用來保證主庫的高可用;
(2)只有主庫1對外提供寫入服務;
(3)兩個主庫設定相同的虛IP,在主庫1掛掉或者網路異常的時候,虛IP自動漂移,備用主庫頂上,保證主庫的高可用;
切換過程中,由於虛IP沒有變化,所以切換過程對呼叫方是透明的,但在極限的情況下,仍可能引發資料不一致。
如上圖所示:
(1)兩個MySQL主庫設定雙向同步,可以用來保證主庫的高可用,並設定了相同的虛IP;
(2)網路抖動前,主庫1對上游提供寫入服務,插入了一條記錄,主鍵為4,並向備用主庫2同步資料;
(3)突然主庫1網路異常,keepalived檢測出異常後,實施虛IP漂移,備用主庫2開始提供服務;
(4)在主鍵4的資料同步成功之前,主庫2插入了一條記錄,也生成了主鍵為4的記錄,結果導致資料不一致;
有沒有辦法緩解上述問題呢?
虛IP漂移,雙主同步延時導致的資料不一致,本質上,需要在雙主同步完資料之後,再實施虛IP偏移。
使用內網DNS探測,緩解上述問題:
(1)使用內網域名連線資料庫,例如:db.kg.org;
(2)主庫1和主庫2設定雙主同步,不使用相同虛IP,而是分別使用ip1和ip2;
(3)一開始db.kg.org指向ip1;
(4)用一個小指令碼輪詢探測ip1主庫的連通性;
(5)當ip1主庫發生異常時,指令碼delay一個x秒的延時,等待主庫2同步完資料之後,再將db.kg.org解析到ip2;
(6)應用程式以內網域名進行重連,即可自動連線到ip2主庫,並保證了資料的一致性;
畫外音:本質上,這是一個可用性與一致性的折衷。
總結
MySQL主庫高可用,主庫一致性,一些小技巧:
(1)雙主同步是一種常見的保證寫庫高可用的方式;
(2)設定相同步長,不同初始值,可以避免auto increment生成衝突主鍵;
(3)不依賴資料庫,業務呼叫方自己生成全域性唯一ID是一個好方法;
(4)雙主保證寫庫高可用,只有一個寫庫提供服務,並不能完全保證一致性;
(5)內網DNS探測,可以實現在主庫1出現問題後,延時一個時間,再進行主庫切換,以保證資料一致性,但犧牲了幾秒鐘的高可用;
希望大家有收穫,謝轉。
原創功能恢復了,“可喜可賀”。
《賬號被罰了,有點不開心》
《賬號被罰了,申訴的結果出來了,果然》