mysql主从数据一致性问题及MHA和MGR的架构及底层原理
MySQL的傳統主從復制機制
MySQL傳統的高可用解決方案是通過binlog復制來搭建主從或一主多從的數據庫集群。主從之間的復制模式支持異步模式(async replication)和半同步模式(semi-sync replication)。無論哪種模式下,都是主庫master提供讀寫事務的能力,而slave只能提供只讀事務的能力。在master上執行的更新事務通過binlog復制的方式傳送給slave,slave收到后將事務先寫入relay log,然后重放事務,即在slave上重新執行一次事務,從而達到主從機事務一致的效果。
異步復制(Async replication):在master將事務寫入binlog后,將新寫入的binlog事務日志傳送給slave節點,但并不等待傳送的結果,就會在存儲引擎中提交事務。
數據丟失的原因:當master將事務寫入binlog,然后復制給slave后并不等待slave返回結果即進行提交,若slave因網絡延遲或其它問題尚未收到binlog日志,而此時master故障,應用切換到slave時,本來在master上已經提交的事務就會丟失,因其尚未傳送到slave,從而導致主從之間事務不一致。
半同步復制(Semi-sync replication):在master將事務寫入binlog后,將新寫入的binlog事務日志傳送給slave節點,但需要等待slave返回傳送的結果;slave收到binlog事務后,將其寫入relay log中,然后向master返回傳送成功ACK;master收到ACK后,再在存儲引擎中提交事務。 MySQL基于兩種復制模式都可以搭建高可用數據庫集群,也能滿足大部分高可用系統的要求,但在對事務一致性要求很高的系統中,還是存在一些不足,主要的不足就是主從之間的事務不能保證時刻完全一致。
數據丟失的原因:當master將事務寫入binlog,尚未傳送給slave時master故障,此時應用切換到slave,雖然此時slave的事務與master故障前是一致的,但當主機恢復后,因最后的事務已經寫入到binlog,所以在master上會恢復成已提交狀態,從而導致主從之間的事務不一致。
MHA工作組件
MHA(Master High Availability)是一種MySQL高可用解決方案,主要用于在故障切換和主從提升時進行快速切換,并最大程度保證數據一致性。
MHA主要由兩部分組成:
1、MHA Manager(管理節點),可以單獨部署在一臺獨立的機器上管理多個master-slave集群,也可以部署在一臺slave節點上。
MHA Manager會定時探測集群中的node節點,當發現master出現故障的時候,它可以自動將具有最新數據的slave提升為新的master,然后將所有其它的slave導向新的master上,整個故障轉移過程對應用程序是透明的。
2、MHA Node(數據節點),數據節點部署在每個集群節點上,負責在主從切換時對比和應用差異日志。
MHA主要特性
MHA切換不依賴實例使用存儲引擎和BINLOG格式;
MHA不會增加MySQL服務器性能開銷,除MHA管理節點外無需增加額外服務器;
在MySQL服務器上部署MHA數據節點不會影響當前實例運行;
MHA實現自動故障切換,也可以手動觸發在線切換;
MHA可以實現秒級的故障切換;
MHA可以將任意slave提升master,也可以在切換時指定master候選節點;
MHA提供擴展接口,允許在MHA切換過程中的特定時間點執行用戶自定義腳本。
MHA可擴展性:
A)seconary_check_script
當檢測到master節點連接失敗時調用,從多個網絡路徑判斷master是否發生宕機。
B)shutdown_script
在故障轉移前調用,可以通過SSH登錄到master節點進行數據庫關閉和服務器關機等操作。
C)master_ip_failover_script
在故障轉移前和轉移到新master節點后調用,用于切換群集使用的VIP或域名或其他操作。
D)report_script
在故障切換完成后被調用,用于通知故障切換的執行結果。
MHA支持與限制
1、只支持BINLOG V4版本,要求MySQL 5.0或更高版本。
2、候選master節點必須開啟log-bin參數,如果所有從節點都為開啟,則不進行故障轉移。
3、在MHA 0.52版本前不支持多master模式
4、MHA默認不支持多級主從復制,通過修改配置文件和設置multi_tier_slave參數
(參考文章:https://www.cnblogs.com/gaogao67/p/11105996.html)
在MHA自動故障切換過程中,MHA試圖從宕機的主服務器上保存二進制日志,最大程度的保證數據的不丟失,但這并不總是可行的。
例如,如果主服務器硬件故障或無法通過ssh訪問,MHA沒法保存二進制日志,只進行故障轉移而丟失了最新的數據。
如果master宕機,如何保證主從庫的一致?
使用MySQL 5.5或者以后的版本的半同步復制,可以大大降低數據丟失的風險。MHA可以與半同步復制結合起來。
如果只有一個slave已經收到了最新的二進制日志,MHA可以將最新的二進制日志應用于其他所有的slave服務器上,因此可以保證所有節點的數據一致性。
具體的工作原理如下:
相較于其它HA軟件,MHA的目的在于維持MySQL Replication中Master庫的高可用性,其最大特點是可以修復多個Slave之間的差異日志,最終使所有Slave保持數據一致,然后從中選擇一個充當新的Master,并將其它Slave指向它。
MHA插件負責監控mysql主節點的健康情況。在主節點宕機后,MHA把binlog通過ssh傳到從節點進行重做補齊。并提升其中一個從節點為主節點。如:A>B ,A>C 。A宕機后。B,C補齊日志。并將故障轉移后的架構變為B>C。
工作流程主要如下:
1、從出現故障的主節點A拉取binlog日志到B、C節點。
2、識別有最近Relay_Master_Log_File,Exec_Master_Log_Pos 更新的slave節點。假設是B
3、應用差異的中繼日志(relay log)到其他slave節點。如C
4、提升slave (B)為新的主節點。
5、其他的節點(C)連接到新的主節點。
MHA 切換完了之后并沒有其他的操作了。如服務發現,重新注冊。但是MHA提供了腳本接口。可以手動指定切換完了MHA執行指定的腳本。如注冊虛擬ip到新的主節點。或者調用接口注冊新的服務域名。發告警郵件 等。
mha的架構如下:
當master出現故障時,通過對比slave之間I/O線程讀取master binlog的位置,選取最接近的slave做為latest slave。其它slave通過與latest slave對比生成差異中繼日志。
在latest slave上應用從master保存的binlog,同時將latest slave提升為master。最后在其它slave上應用相應的差異中繼日志并開始從新的master開始復制。
在MHA實現Master故障切換過程中,MHA Node會試圖訪問故障的master(通過SSH),如果可以訪問(不是硬件故障,比如InnoDB數據文件損壞等),會保存二進制文件,以最大程度保證數據不丟失。
MHA和半同步復制一起使用會大大降低數據丟失的危險。
優勢
1)故障切換快
在主從復制集群中,只要從庫在復制上沒有延遲,MHA通常可以在數秒內實現故障切換。9-10秒內檢查到master故障,可以選擇在7-10秒關閉master以避免出現裂腦,幾秒鐘內,將差異中繼日志(relay log)應用到新的master上,因此總的宕機時間通常為10-30秒。恢復新的master后,MHA并行的恢復其余的slave。即使在有數萬臺slave,也不會影響master的恢復時間。
DeNA在超過150個MySQL(主要5.0/5.1版本)主從環境下使用了MHA。當mater故障后,MHA在4秒內就完成了故障切換。在傳統的主動/被動集群解決方案中,4秒內完成故障切換是不可能的。
2)master故障不會導致數據不一致
當目前的master出現故障時,MHA自動識別slave之間中繼日志(relay log)的不同,并應用到所有的slave中。這樣所有的salve能夠保持同步,只要所有的slave處于存活狀態。和半同步復制一起使用,(幾乎)可以保證沒有數據丟失。
3)無需修改當前的MySQL設置
MHA并不需要改變MySQL的部署環境,MHA適用于異步和半同步的主從復制。
啟動/停止/升級/降級/安裝/卸載MHA不需要改變(包擴啟動/停止)MySQL復制。當需要升級MHA到新的版本,不需要停止MySQL,僅僅替換到新版本的MHA,然后重啟MHA Manager就好了。
4)無需增加大量的服務器
MHA由MHA Manager和MHA Node組成。MHA Node運行在需要故障切換/恢復的MySQL服務器上,因此并不需要額外增加服務器。MHA Manager運行在特定的服務器上,因此需要增加一臺(實現高可用需要2臺),但是MHA Manager可以監控大量(甚至上百臺)單獨的master,因此,并不需要增加大量的服務器。即使在一臺slave上運行MHA Manager也是可以的。
5)無性能下降
MHA適用與異步或半同步的MySQL復制。監控master時,MHA僅僅是每隔幾秒(默認是3秒)發送一個ping包,并不發送重查詢。可以得到像原生MySQL復制一樣快的性能。
6)適用于任何存儲引擎
MHA可以運行在只要MySQL復制運行的存儲引擎上,并不僅限制于InnoDB,即使在不易遷移的傳統的MyISAM引擎環境,一樣可以使用MHA。
MHA如何保持數據的一致性呢?
主要通過MHA node的以下幾個工具實現,但是這些工具由MHA manager觸發:
save_binary_logs :如果master的二進制日志可以存取的話,保存復制master的二進制日志,最大程度保證數據不丟失。
apply_diff_relay_logs:相對于最新的slave,生成差異的中繼日志并將所有差異事件應用到其他所有的slave。
對比的是relay log,relay log越新就越接近于master,才能保證數據是最新的。
purge_relay_logs:刪除中繼日志而不阻塞sql線程
MGR架構原理簡介:(全稱:MySQL Group Replication),Mysql組復制
1.狀態機復制
MGR本質上一個狀態機復制的集群。在狀態機復制的架構中,數據庫被當做一個狀態機。每一次寫操作都會導致數據庫的狀態變化。為了創建一個高可用的數據庫集群,有一個組件,即事務分發器,將這些操作按照同樣的順序發送到多個初始狀態一致的數據庫上,讓這些數據庫執行同樣的操作。因為初始狀態相同,每次執行的操作也相同,所以每次狀態變化后各個數據庫上的數據保持一致。
2.分布式的狀態機復制
事務分發器是一個單點,為了避免單點故障,可以采用分布式的狀態機復制。在分布式的狀態機復制中,有多個事務分發器,它們彼此互相通信。事務分發器可以同時接收事務請求,就像單個事務分發器同時接收事務請求一樣。從應用層來說,并發的事務發到同一個事務分發器和發到不同的事務分發器上效果是一樣的。事務分發器之間會互相通信,把所有的事務匯總、排序。最終,每個事務分發器上都有一份完整的排好序的事務請求。每個事務分發器只連接到一個數據庫上,并負責把事務請求依次發送到相連的數據庫上去執行,其就是一個分布式狀態機復制的模型了。
3.分布式的高可用數據庫
將分布式的事務分發模塊集成到數據庫系統中,就變成了一個分布式的高可用數據庫系統。用戶通過數據庫的用戶接口執行事務。數據庫收到事務請求后,首先交由事務分發模塊處理。事務分發模塊將事務匯總排序,然后依次交由數據處理模塊去執行這些事務。
用戶——>請求數據庫用戶接口——>數據庫——>事務分發器——>將事務匯總排序——>執行
Group Replication的實現原理
Group Replication由至少3個或更多個節點共同組成一個數據庫集群,事務的提交必須經過半數以上節點同意方可提交,在集群中每個節點上都維護一個數據庫狀態機,保證節點間事務的一致性。Group Replication基于分布式一致性算法Paxos實現,允許部分節點故障,只要保證半數以上節點存活,就不影響對外提供數據庫服務,是一個真正可用的高可用數據庫集群技術。 Group Replication支持兩種模式,單主模式和多主模式。在同一個group內,不允許兩種模式同時存在,并且若要切換到不同模式,必須修改配置后重新啟動集群。 在單主模式下,只有一個節點可以對外提供讀寫事務的服務,而其它所有節點只能提供只讀事務的服務。
MySQL Group Replication是建立在已有MySQL復制框架的基礎之上,通過新增Group Replication Protocol協議及Paxos協議的實現,形成的整體高可用解決方案。與原有復制方式相比,主要增加了certify的概念,如下圖所示:
certify模塊主要負責檢查事務是否允許提交,是否與其它事務存在沖突,如兩個事務可能修改同一行數據。在單機系統中,兩個事務的沖突可以通過封鎖來避免,但在多主模式下,不同節點間沒有分布式鎖,所以無法使用封鎖來避免。為提高性能,Group Replication樂觀地來對待不同事務間的沖突,樂觀的認為多數事務在執行時是沒有并發沖突的。事務分別在不同節點上執行,直到準備提交時才去判斷事務之間是否存在沖突。
核心組件XCOM的特性
MySQL Group Replication是建立在基于Paxos的XCom之上的,正因為有了XCom基礎設施,保證數據庫狀態機在節點間的事務一致性,才能在理論和實踐中保證數據庫系統在不同節點間的事務一致性。 Group Replication在通訊層曾經歷過一次比較大的變動,早期通訊層采用是的Corosync,而后來才改為XCom。
xcom特性:
閉環(closed group):只有組內成員才能給組成員發送消息,不接受組外成員的消息。
消息全局有序(total order):所有XCOM傳遞的消息是全局有序(在多主集群中或是偏序),這是構建MySQL 一致性狀態機的基礎。
消息的安全送達(Safe Delivery):發送的消息必須傳送給所有非故障節點,必須在多數節點確認收到后方可通知上層應用。
視圖同步(View Synchrony):在成員視圖變化之前,每個節點都以相同的順序傳遞消息,這保證在節點恢復時有一個同步點。實際上,組復制并不強制要求消息傳遞必須在同一個節點視圖中。
(參考文章:https://blog.csdn.net/weixin_32175667/article/details/113330358)
MGR 適用的場景包括:
彈性復制:復制架構下,服務器的數量動態增加或縮減時,使影響降到最低。
分片的高可用:用戶可以利用MGR實現單一分片的高可用,每個分片都具有一個復制組。
主從復制的替代選擇:可以使用單主模式避免發生沖突檢測,以替代傳統的主從復制。
MGR使用上的限制
盡量使用單主模式,表必須有主鍵,必須啟用GTID,必須使用InnoDB引擎,在多主模式下DML和DDL對同一個表的操作,必須在同一個節點進行,否則會導致集群會crash。使用奇數個節點:3,5,7,9 最多9個成員。
網絡穩定,延遲低,盡量避免WAN部署;禁止使用外鍵;不支持GAP LOCK ,MGR工作在RC模式;不支持serializable事務模式;MGR成員間不支持復制過濾規則。
BINLOG_FORMAT=ROW。
在多主模式使用select for update可能會導致整個集群死鎖。
如果配合mysqlshell使用MySQL版本需要8.0.20及以上。
從MySQL 5.6.5 開始新增了一種基于 GTID 的復制方式。通過 GTID 保證了每個在主庫上提交的事務在集群中有一個唯一的ID。這種方式強化了數據庫的主備一致性,故障恢復以及容錯能力。GTID (Global Transaction ID)是全局事務ID,當在主庫上提交事務或者被從庫應用時,可以定位和追蹤每一個事務。
從架構設計的角度,GTID是一種很好的分布式ID實踐方式,通常來說,分布式ID有兩個基本要求:
1)全局唯一性
2)趨勢遞增
這個ID因為是全局唯一,所以在分布式環境中很容易識別,因為趨勢遞增,所以ID是具有相應的趨勢規律,在必要的時候方便進行順序提取,行業內適用較多的是基于Twitter的ID生成算法snowflake,所以換一個角度來理解GTID,其實是一種優雅的分布式設計。
分布式ID使用背景:
業務數據量不大的時候,單庫單表完全可以支撐現有業務,數據再大一點搞個MySQL主從同步讀寫分離也能對付。
但隨著數據日漸增長,主從同步也扛不住了,就需要對數據庫進行分庫分表,但分庫分表后需要有一個唯一ID來標識一條數據,數據庫的自增ID顯然不能滿足需求;特別一點的如訂單、優惠券也都需要有唯一ID做標識。此時一個能夠生成全局唯一ID的系統是非常必要的。那么這個全局唯一ID就叫分布式ID。
項目中一個表中的數據主鍵id都是自增的,解決分布式id的方案有哪些?
1、數據庫自增ID
可以在某個庫中專門維護一張表,然后每次無論哪個表需要自增id的時候都去查這個表的記錄,然后用for update鎖表,然后取到的值加一,然后返回以后把再把值記錄到表中,但是這個方法適合并發量比較小的項目,因此每次都得鎖表。
優點:實現簡單,ID單調自增,數值類型查詢速度快
缺點:DB單點存在宕機風險,無法扛住高并發場景
2、基于數據庫集群模式
單點數據庫方式不可取,換成主從模式集群。害怕一個主節點掛掉沒法用,那就做雙主模式集群,也就是兩個Mysql實例都能單獨的生產自增ID。兩個MySQL實例的自增ID都從1開始,會生成重復的ID怎么辦?設置起始值和自增步長
優點:解決數據庫單點問題
缺點:不利于后續擴容,而且實際上單個數據庫自身壓力還是大,依舊無法滿足高并發場景。
3、基于數據庫的號段模式
號段模式是當下分布式ID生成器的主流實現方式之一,號段模式可以理解為**從數據庫批量的獲取自增ID,每次從數據庫取出一個號段范圍,**例如 (1,1000] 代表1000個ID,具體的業務服務將本號段,生成1~1000的自增ID并加載到內存。等這批號段ID用完,再次向數據庫申請新號段,由于多業務端可能同時操作,所以采用版本號version樂觀鎖方式更新,這種分布式ID生成方式不強依賴于數據庫,不會頻繁的訪問數據庫,對數據庫的壓力小很多。
4、redis
因為redis是單線程的,可以在redis中維護一個鍵值對,然后哪個表需要直接去redis中取值然后加一,但是這個跟上面一樣由于單線程都是對高并發的支持不高,只適合并發量小的項目。
用redis實現需要注意一點,要考慮到redis持久化的問題。redis有兩種持久化方式RDB和AOF。RDB會定時打一個快照進行持久化,假如連續自增但redis沒及時持久化,而這會Redis掛掉了,重啟Redis后會出現ID重復的情況。AOF會對每條寫命令進行持久化,即使Redis掛掉了也不會出現ID重復的情況,但由于incr命令的特殊性,會導致Redis重啟恢復的數據時間過長。
5、uuid
可以使用uuid作為不重復主鍵id,但是uuid有個問題就是其是無序的字符串,如果使用uuid當做主鍵,那么主鍵索引就會失效。
優點:生成足夠簡單,本地生成無網絡消耗,具有唯一性
缺點:
無序的字符串,不具備趨勢自增特性;沒有具體的業務含義;存儲以及查詢對MySQL的性能消耗較大,作為數據庫主鍵 UUID 的無序性會導致數據位置頻繁變動,嚴重影響性能。
6、雪花算法
雪花算法是解決分布式id的一個高效的方案,大部分互聯網公司都在使用雪花算法,當然還有公司自己實現其他的方案,比如百度(uid-generator)、美團(Leaf)、滴滴(Tinyid)
雪花算法的原理:
雪花算法就是使用64位long類型的數據存儲id,最高位一位存儲0或者1,0代表整數,1代表負數,一般都是0,所以最高位不變,41位存儲毫秒級時間戳,10位存儲機器碼(包括5位datacenterId和5位workerId),12存儲序列號。這樣最大2的10次方的機器,也就是1024臺機器,最多每毫秒每臺機器產生2的12次方也就是4096個id。
總結
以上是生活随笔為你收集整理的mysql主从数据一致性问题及MHA和MGR的架构及底层原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AMOLED原理介紹
- 下一篇: Database_数据库基础笔记整理