MySQL 主從,一定會不一致!
之前聊了《數(shù)據(jù)庫雙主一致性問題解決方案》,今天聊聊數(shù)據(jù)庫主庫與從庫的一致性問題。
問:常見的數(shù)據(jù)庫集群架構(gòu)如何?
一主多從,主從同步,讀寫分離。
如上圖:
- 一個主庫提供寫服務(wù);
- 多個從庫提供讀服務(wù),提升讀性能;
- 主從之間同步數(shù)據(jù);
問:為什么會出現(xiàn)不一致?
主從同步有時延,時延期間讀從庫,主從同步未完成,可能讀到臟數(shù)據(jù)。
圖片
任何數(shù)據(jù)冗余,必將引發(fā)一致性問題。
問:如何避免這種主從延時導(dǎo)致的不一致?
常見的方法有4種。
方案一:忽略。
任何脫離業(yè)務(wù)的架構(gòu)設(shè)計都是耍流氓,絕大部分業(yè)務(wù),例如:百度搜索,淘寶訂單,QQ消息,58帖子都允許短時間不一致。
如果業(yè)務(wù)能夠接受,別把系統(tǒng)架構(gòu)搞得太復(fù)雜。
方案二:半同步復(fù)制
不一致是因為主從同步有一個時間差,是否能做到,等主從同步完成之后,主庫上的寫請求再返回呢?
這就是大家常說的半同步復(fù)制semi-sync。
- 1. 主庫先執(zhí)行寫操作;
- 2. 等主從同步完成,寫請求才返回;
- 3. 讀從庫,就能讀到最新的數(shù)據(jù);
這個方案的優(yōu)點是,利用數(shù)據(jù)庫原生功能,比較簡單。不足是,主庫的寫請求時延會增加,吞吐量會降低。
方案三:強制讀主。
如上圖:
- 使用一個高可用主庫提供數(shù)據(jù)庫服務(wù);
- 讀和寫都落到主庫上;
- 采用緩存來提升系統(tǒng)讀性能;
這是很常見的微服務(wù)架構(gòu),可以避免數(shù)據(jù)庫主從一致性問題。
方案四:選擇性讀主。
強制讀主過于粗暴,畢竟只有少量寫請求,很短時間,可能讀取到臟數(shù)據(jù)。
有沒有可能實現(xiàn),只有這一段時間,可能讀到從庫臟數(shù)據(jù)的讀請求讀主,平時讀從呢?
可以利用一個緩存記錄必須讀主的數(shù)據(jù)。
如上圖,當寫請求發(fā)生時:
- 寫主庫;
- 將哪個庫,哪個表,哪個主鍵三個信息拼裝一個key設(shè)置到cache里,這條記錄的超時時間,設(shè)置為“主從同步時延”;
畫外音:key的格式為“db:table:PK”,假設(shè)主從延時為1s,這個key的cache超時時間也為1s。
如上圖,當讀請求發(fā)生時,這是要讀哪個庫,哪個表,哪個主鍵的數(shù)據(jù)呢,也將這三個信息拼裝一個key,到cache里去查詢,如果:
- cache里有這個key,說明1s內(nèi)剛發(fā)生過寫請求,數(shù)據(jù)庫主從同步可能還沒有完成,此時就應(yīng)該去主庫查詢;
- cache里沒有這個key,說明最近沒有發(fā)生過寫請求,此時就可以去從庫查詢;
以此,保證讀到的一定不是不一致的臟數(shù)據(jù)。
總結(jié)
數(shù)據(jù)庫主從不一致,四種常見優(yōu)化方案:
- 忽略:業(yè)務(wù)可以接受,系統(tǒng)不優(yōu)化;
- 半同步復(fù)制:復(fù)用原生能力,犧牲部分性能;
- 強制讀主:高可用主庫,用緩存提高讀性能;
- 選擇性讀主:在cache里記錄哪些記錄發(fā)生過寫請求,來路由讀主還是讀從;
知其然,知其所以然。
思路比結(jié)論更重要。