MySQL主從資料不一致,怎麼辦?
先給大家說個身邊的故事。
小夥伴二狗最近面宇宙廠,前面被問MySQL索引、鎖、主從複製原理時答的都很開心。
當面試官問到 :“你們遇到主從不一致的問題怎麼解決呢?你有什麼更好的方案嗎?”
二狗懵了。不就是讀寫時候走主,純讀走從嗎。。難道還有什麼別的辦法?
面試官:emmm……有。那我們換個問題,主從複製的方式有幾種,你能講講嗎?
二狗:…… 問到盲點了
面試官:答不上來沒關係,您的情況我基本瞭解了。感謝您參加本次面試,後續結果HR會聯絡你。
如果你也有類似上述疑惑,那麼這篇文章拿好了!
點選上方“後端開發技術”,選擇“設為星標” ,優質資源及時送達
主從資料不一致問題
先介紹下問題產生的背景。
在MySQL 一主多從的架構中,主要有兩種,一種是透過客戶端直連,一種是透過代理 prxoy 間接連線。
客戶端直連模式下一般會把資料庫的連線資訊放在客戶端的連線層,客戶端做負載均衡,由客戶端來選擇後端資料庫進行查詢。透過代理的模式下 MySQL 和客戶端之間有一箇中間代理層 proxy,客戶端直連線 proxy, 由 proxy 根據請求型別和上下文決定請求的分發路由。
客戶端直連和帶 proxy 的讀寫分離架構,各有哪些特點。
客戶端直連方案,整體架構簡單,排查問題方便。但是這種方案,由於要了解後端部署細節,所以在出現主備切換、庫遷移等操作的時候,處理起來比較麻煩,對開發人員要求高。 直連 proxy 的架構,對客戶端比較友好。客戶端不需要關注後端細節,但是 proxy 也需要有高可用架構,架構更復雜,對運維團隊要求更高。
目前趨勢是直連 proxy 的方向發展,具體取捨取決於自身情況。
帶來的問題
無論哪種架構,都會遇到主從資料不一致的問題:由於主從同步可能存在延遲,客戶端執行完一個更新事務後馬上發起查詢,如果查詢選擇的是從庫的話,就有可能讀到剛剛的事務更新之前的狀態。如何解決呢?
在進行讀寫分離的同時,解決主從同步中資料不一致的問題,主要有幾種思路,一是從業務層面解決,二是從檢測主從同步的差異上解決,三也是最根本的方式——從主從之間資料複製方式解決。按照這三種指導思想,我總結了一下有以下幾種方案。
全部走主庫方案
先說一種最為廣泛使用的方案,也就是二狗的回答。
如果是在同一資料庫中對資料進行更新的時候,可以對記錄加寫鎖,這樣在讀取的時候就不會發生資料不一致的情況。所以我們可以根據業務場景來做區分。如果是需要寫完之後必須讀區到準確資料的場景,可以直接全部走主庫,比如訂單支付、金融業務等強一致性場景;如果業務允許讀到舊資料,可以在讀的時候查詢從庫。
這樣的話你可能覺得並沒有真正解決主從不一致的問題,但其實在實際生產中,大多數情況下都這麼解決的。優點是簡單成本低,不需要複雜架構。缺點也很明顯,如果業務一致性要求很高,很多讀都會在主庫進行,並沒有真正的讀寫分離減輕主庫壓力,讀寫分離成了擺設。
延遲查詢方案
比如主庫更新一條資料以後,查詢從庫資料的時候後端介面可以線sleep一段時間,比如絕大多數主從同步都可以在1s內完成,那就可以sleep一秒鐘的時間。或者也可以延遲查詢邏輯放在前端,比如訂單支付完成後,可以前端延遲一秒再發起Ajax請求。
缺點是並不能資料保證完全準確,如果資料同步延遲大於一秒則主從依舊不一致;另一個是造成介面響應時間變長,甚至造成服務的吞吐量降低,對於不需要等待1s的場景,也必須等待夠1s。
判斷主備無延遲方案
在構建MySQL主從架構的文章裡提過一些關於主從搭建以及狀態檢視的具體操作,具體請看下面這篇文章?
快速入門Mycat及主從搭建指南
後文將要提到的關於判斷主備延遲的關鍵引數便是從 status 的結果中獲得的。
1.判斷 Seconds_Behind_Master
透過 show slave status
可以拿到 Seconds_Behind_Master
的值,表示主備延遲的時間長短。判斷 Seconds_Behind_Master
是否為 0,如果不等於0,就等到這個引數為0時再執行查詢。但是這個延遲時間的單位為秒,所以可能產生一秒內的誤差。
2.判斷同步binlog 位置
在同步時透過檔名+檔案位置就可以定位到binlog檔案正在同步的位置。Master_Log_File 和 Read_Master_Log_Pos,表示的是讀到的主庫的最新位點;Relay_Master_Log_File 和 Exec_Master_Log_Pos,表示的是備庫執行的最新位點。
3.判斷GTID相同
GITD在全域性唯一,並且可以動過GTID來定位binlog位置,所以也可以用來判斷主備是否有延遲
什麼是GTID?
GTID特性是5.6加入的一個強大的特性,全稱是Global Transaction Identifier。MySQL會為每一個DML/DDL操作增加一個唯一標記叫做GTID,這個標記在整個複製環境中都是唯一的。主從環境中主庫的DUMP執行緒可以直接透過GTID定位到需要傳送的binary log位置,而不再需要指定binary log的檔名和位置,因此切換極為方便。關於DUMP執行緒是如何透過GTID定位到binary log位置的,我們將在第17節進行討論。
Auto_Position=1 ,表示這對主備關係使用了 GTID 協議。Retrieved_Gtid_Set,是備庫收到的所有日誌的 GTID 集合;Executed_Gtid_Set,是備庫所有已經執行完成的 GTID 集合。對比這兩個集合對應的GTID相同就表示主備之間無延遲。
但是需要說明的是,這裡的無延遲,指的其實是從庫收到主庫的資料已經全部執行結束。但可能有種情況,客戶端已經收到資料,而對應的binlog並沒有收到,這種情況下從庫是不知道的。
如何解決這個問題呢?
我們現在的困境是不知道主庫到底有沒有新執行的資料,從庫有沒有把最新binlog收到並且執行,那如果主庫執行完SQL我就拿到最新binlog位點呢?還有另一種思路,之所以產生這種情況,是因為5.7版本mysql預設採用了非同步複製的方式。如果想要資料更精確,就有必要在複製方式上做出改變。
對於這兩種思路又產生了後面幾種解決方案。
從庫等指定位點或GTID方案
對於前面提到的思路,剛好MySQL有這樣一個命令。
select master_pos_wait(file, pos[, timeout]);
這條命令是在從庫執行的,引數 file 和 pos 指的是主庫上的檔名和位置,timeout 可選,設定為正整數 N 表示這個函式最多等待 N 秒。這個命令正常返回的結果是一個正整數 M,表示從命令開始執行,到應用完 file 和 pos 表示的 binlog 位置,執行了多少事務。
這樣就產生了一個方案。
主庫事務更新完成後,馬上執行 show master status 得到當前主庫執行到的 File 和 Position。 選定一個從庫執行查詢語句。 在從庫上執行 select master_pos_wait(File, Position, 1)。 如果返回值是 >=0 的正整數,則在這個從庫執行查詢語句,否則,到主庫執行查詢語句。
同樣的對於判斷位點,可有一套判斷GTID的方案。
select wait_for_executed_gtid_set(gtid_set, 1);
邏輯與前者相同,只需要等待GTID到指定數字即可,這裡大家舉一反三,不做贅述。
複製方式
下面就開始介紹關於複製方式方面的思路,從這些複製方式中,你會找到關於解決主備延遲問題的更優思路。先介紹一下非同步複製模式。
非同步複製
非同步模式就是客戶端提交 COMMIT 之後不需要等從庫返回任何結果,而是直接將結果返回給客戶端,這樣做的好處是不會影響主庫寫的效率,但可能會存在主庫當機,而 Binlog 還沒有同步到從庫的情況,也就是此時的主庫和從庫資料不一致。這時候從從庫中選擇一個作為新主,那麼新主則可能缺少原來主伺服器中已提交的事務。所以,這種複製模式下的資料一致性是最弱的。
預設情況下,MySQL就是非同步複製的模式。
半同步複製(增強半同步複製)
在MySQL5.5中加入了半同步複製(semisynchronous replication),主庫上的事務在儲存引擎層提交之後,需要等待從庫返回ACK訊號。並且在接收到從庫返回ACK訊號或者等待超時才會返回給客戶端一個提交結果。但是這樣會造成其他會話可以讀取到這些記錄,因為此時事務已經提交,這就造成了幻讀。
在MySQL5.7中進一步對半同步複製做了增強,將等待從庫返回ACK訊號的時間點提前了,新特性中主庫上的事務會在儲存引擎層提交之前一直等待從庫返回ACK訊號。這就意味著,在主庫crash的情況下,所有在主庫上已經提交的事務已經被複制到至少一個從庫上,這就解決了幻讀的問題,資料的一致性獲得了極大提升。
但是缺點也很明顯,會造成同步過程多了一次網路連線,降低主庫的寫吞吐量。在 MySQL5.7 版本中還增加了rpl_semi_sync_master_wait_for_slave_count
引數 ,可以對從庫的應答數量進行設定,預設為 1,也就是說只要有 1 個從庫進行了響應,就可以返回給客戶端。在1主1從情況下,這接近同步複製,如果使用semi-sync+位點判斷方案,這樣我們前面提到的主從資料不一致問題引刃而解,但是如果多從還是有可能出現不一致的情況。
MGR 組複製
MySQL在5.7.17 版本中引入了組複製技術,簡稱 MGR(MySQL Group Replication),這種複製技術是基於 分散式一致性協議Paxos 協議的,實現了分散式下資料的最終一致性。
A transaction received by Source 1 is executed. Source 1 then sends a message to the replication group, consisting of itself, Source 2, and Source 3. When all three members have reached consensus, they certify the transaction. Source 1 then writes the transaction to its binary log, commits it, and sends a response to the client application. Sources 2 and 3 write the transaction to their relay logs, then apply it, write it to the binary log, and commit it.
MGR 由若干個節點共同組成一個複製組,一個寫事務的提交,必須經過組內大多數節點(N / 2 + 1)決議並透過,才能得以提交。如上圖所示,由3個節點組成一個複製組,Consensus層為一致性協議層,在事務提交過程中,發生組間通訊,由2個節點決議(certify)透過這個事務,事務才能夠最終得以提交併響應,其實就是過半投票。
而針對只讀(RO)事務則不需要經過組內同意,直接 COMMIT 即可。在一個複製組內有多個節點組成,它們各自維護了自己的資料副本,並且在一致性協議層實現了原子訊息和全域性有序訊息,從而保證組內資料的一致性。雖然半同步複製部分解決了一致性問題,但只能在簡單架構下比如一主一從,MGR才真正解決了這個問題,並且MGR可以在多主的複雜情況下有效保證資料的一致性。
總結
總結一下,解決主從複製延遲一共可以有如下7種思路:
讀寫走主庫方案 延遲查詢方案 判斷主備無延遲方案 判斷同步位點方案 等待同步位點方案 半同步複製方案+等待位點 組複製MGR方案
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024923/viewspace-2928720/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 資料庫主從不一致,怎麼解?資料庫
- mysql雙寫造成主從資料不一致的實驗MySql
- 資料庫同步 Elasticsearch 後資料不一致,怎麼辦?資料庫Elasticsearch
- 如何解決MySQL 主從複製資料不一致問題MySql
- 【mysql】mysql的資料庫主從(一主一從)MySql資料庫
- MySQL 資料主從同步MySql主從同步
- MySQL主從資料庫同步延遲問題怎麼解決MySql資料庫
- MYSQL 主從不一致的原因分析MySql
- mysql主從資料庫配置MySql資料庫
- [資料庫]MYSQL主從同步資料庫MySql主從同步
- MySQL-主從複製之同步主從資料MySql
- mysql無法建立資料庫怎麼辦MySql資料庫
- 《MySQL主從不一致情形與解決方法》MySql
- MySQL主從不一致情形與解決方法MySql
- 8、MySQL主從資料庫配置MySql資料庫
- mysql建立資料庫報錯了怎麼辦MySql資料庫
- 資料庫mysql儲存遇到禁用怎麼辦?資料庫MySql
- 怎麼在linux完成MySQL主從熱備?LinuxMySql
- MySQL 主從 AUTO_INCREMENT 不一致問題分析MySqlREM
- Mysql(Mariadb)資料庫主從複製MySql資料庫
- MySQL-主從複製之搭建主資料庫MySql資料庫
- MySQL-主從複製之搭建從資料庫MySql資料庫
- 為什麼mysql會經常出現主從同步不一致的情況MySql主從同步
- mysql資料庫實現主從複製MySql資料庫
- MacOS使用Docker建立MySQL主從資料庫MacDockerMySql資料庫
- Linux實現MySql資料庫的主從複製(一主一從)LinuxMySql資料庫
- MySQL主從延時這麼長,要怎麼最佳化?MySql
- Jtti:redis主從延遲資料不一致問題如何解決JttiRedis
- mysql資料庫的主從複製和主主複製實踐MySql資料庫
- mysql伺服器主從資料庫同步配置MySql伺服器資料庫
- mysql資料庫互為主從配置方法分享MySql資料庫
- 什麼?MySQL在從庫讀到了比主庫更加新的資料?MySql
- MySQL怎麼實現主從同步和Django實現MySQL讀寫分離MySql主從同步Django
- 私人資料不想要怎麼辦?
- 報表從資料庫中採集相關資料生成報表,資料太少怎麼辦?資料庫
- mysql資料庫怎麼連線MySql資料庫
- linux下mysql主從複製,實現資料庫同步LinuxMySql資料庫
- mysql密碼忘了怎麼辦MySql密碼