三高Mysql - 搭建“三高”架構之擴充套件與切換

lazytimes發表於2022-04-17

引言

​ 內容為慕課網的《高併發 高效能 高可用 Mysql 實戰》視訊的學習筆記內容和個人整理擴充套件之後的筆記,這一節講述三高架構的另外兩個部分切換和擴充套件,擴充套件指的是分庫分表減輕資料庫的壓力,同時因為分庫分表需要針對節點當機問題引入了一些優化手段,而切換部分就是講述節點當機的切換問題的,最後我們結合複製的主從切換講述如何搭建一個三高的架構。

​ 如果內容比較難可以跟隨《Mysql是怎麼樣執行》個人讀書筆記專欄補補課:

​ 地址如下:從零開始學Mysql

擴充套件

分割槽表

​ Innodb的分割槽表是指將一個表拆分為多個表但是注意這個概念和分庫分表的物理分表有差別,在Innodb中雖然已經在儲存引擎進行了劃分,實際上分割槽表在Server層上還是被當成一個表看待。

​ 分割槽表的構建可以看下面的案例:

​ 為了驗證Sever層把它當做一個表看待這裡可以進入命令列通過下面的命令檢視,在截圖中可以看到雖然表面上是一個表然而實際上Innodb儲存引擎把它們拆分為四個表:

 InnoDB分割槽存在下面的幾種方式:
  1. 範圍分割槽:通過資料的儲存範圍進行劃分分割槽。
  2. 雜湊分割槽:通過雜湊值進行分割槽。
  3. List分割槽:針對欄位取值的方式進行分割槽。

分割槽表有下面的特點:

  1. 降低Btree樹層級,提高搜尋查詢的效率。
  2. 第一次訪問需要訪問所有分割槽。
  3. 所有分割槽表共同使用一個MDL鎖,這意味著對於分割槽表的鎖表會同步處理
  4. 因為對於server層來說分割槽表只是一張表,所以分割槽實際上沒有提高效能。

分庫分表

​ 分庫分表按照嚴格來說應該分為分庫和分表,分庫的處理情況一般比較少更多的是根據業務進行分表的操作,分表通常分為下面幾種方式:

垂直分表:垂直分表指的是根據某表的資料按照某種規則冷熱進行劃分。

水平分表:水平分表通常按照資料行拆表,這種方式類似把真實的資料行拆分到多個表裡面,防止單表資料過大,同時內部使用範圍值或者雜湊值進行水平分表的資料查詢,其中水平分表最為常用

注意本部分講述的分表和上面的分割槽表是有區別的,在Server層這種分庫分表會當作實際的拆分看待而不是同一個表。

而分庫的概念現在使用的情況不是特別多了,在分庫概念中分為下面的內容:

垂直分庫:資料分散在多個資料庫或者分到多個節點。

水平分庫:將資料表按照特殊業務規則劃分,是每一個庫負責各自的主要業務。同時資料庫的基本結構配置相同。水平分庫通常還有一種場景是較為新的資料和較為老的資料放到不同的庫中進行檢視,同樣和下面的結構圖類似。

分庫分表有哪些優缺點呢?

優點:

  • 增加隔離性
  • 增加併發和隔離性:因為資料結構在server層被看作不同的庫和塊,
  • 和分割槽表雖然很像,但是本質上完全不一樣。

缺點:

  • 對於部分失效的特徵會成倍的增加和出現。
  • 單點事務不可以實現,需要引入分散式的鎖進行控制。
  • 垂直分庫分表之後不能夠join查詢,會多寫很多SQL。
  • 對於範圍查詢的SQL會存在問題

Dble和Mycat

簡介:這兩款中介軟體都是用於Mysql進行分庫分表的市面上使用非常多的主流中介軟體,Mycat可能更為人熟知而Dble則是在Mycat的基礎上更進一步優化和擴充套件。

基礎執行原理:

  • 分析查詢的SQL語句。
  • 把SQL的查詢按照中介軟體演算法分發到多個庫和多個表進行查詢,同時傳送到資料節點
  • 將資料節點的資料進行聚集合並,最後返回給客戶端。

Dble:高效能的Mysql分庫分表中介軟體,由國內一家叫做愛可生的公司進行開發,可以說是國產之光,專案完全開源同時基於另一個開源專案Mycat進行優化和改良,同時這款工具主要是由JAVA編寫,對於一些實際使用的問題可以由大部分的開發人員嘗試解決。

Dble的設計結構如下,對於客戶端來說和平時連線Mysql的分片沒有區別然而實際上這是因為Dble內部做了一系列的優化操作:

Dble的基礎概念:

  • Schema:虛擬資料庫(和傳統資料庫的Schema不同)。
  • ShardingTable:虛擬表,通過虛擬表把資料進行演算法劃分。
  • ShardingNode:虛擬節點,存在資料庫的Database中,可以認為一個DB就是一個節點。
  • dbGroup:實際的Mysql叢集。
  • Database:表示實際的Database。

最後我們通過一個簡單的分表案例來看看Dble做了哪些操作:

Dble的分庫分表特點是無論分庫還是分表都是使用分表來實現的。

在上面的圖中可以看到,首先我們的物理表被Dble當作一個shariding table看待,這裡的虛擬表在Dble內部首先會被分發到兩個Mysql節點,對於Mysql1和Mysql2來說他們之間是沒有任何關係的雙方不知道對方存在的(和上一篇提到的主主架構是不一樣的),而Dble則在這兩個節點當中的實際db建立了虛擬機器節點進行水平分庫,內部通過演算法分發到不同的庫中進行查詢,這裡的表看起來很小是因為內部實際上有可能還存在其他的虛擬節點,而對於Dble來說是拆分合併到不同的Mysql中管理,這些虛擬節點對於Mysql1和Mysql來說是分開保管的資料,對於Mysql本身來說和普通的資料沒有明顯感知和區別,真正的資料合併則由Dble完成。

Dble安裝搭建和使用

關於具體的操作使用可以參考官方所寫的文件:Introduction · Dble manual (actiontech.github.io),安裝過程這裡就略過了我們重點從Dble的配置開始:

首先Dble有幾個重要的配置檔案:

注意這些檔案在安裝好的Dble目錄裡面都是模板,除開部分需要根據自己的Mysql情況修改配置之外,只需要直接改名去掉_template即可。

接下來是修改db.xml檔案,在這個檔案中需要根據自己的資料庫節點情況進行相關配置的修改,比如下方截圖中的框線部分需要進行改動為自己的Mysql節點配置。

如果截圖看不清也可以參考官方給的一個樣板進行修改,需要改的地方都有相關的標識,比較好理解。

<?xml version="1.0"?>
<Dble:db xmlns:Dble="http://Dble.cloud/">

    <dbGroup name="dbGroup1" rwSplitMode="1" delayThreshold="100">
        <heartbeat errorRetryCount="1" timeout="10">show slave status</heartbeat>
        <dbInstance name="instanceM1" url="ip4:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" primary="true">
            <property name="testOnCreate">false</property>
            <property name="testOnBorrow">false</property>
            <property name="testOnReturn">false</property>
            <property name="testWhileIdle">true</property>
            <property name="connectionTimeout">30000</property>
            <property name="connectionHeartbeatTimeout">20</property>
            <property name="timeBetweenEvictionRunsMillis">30000</property>
            <property name="idleTimeout">600000</property>
            <property name="heartbeatPeriodMillis">10000</property>
            <property name="evictorShutdownTimeoutMillis">10000</property>
        </dbInstance>

        <!-- can have multi read instances -->
        <dbInstance name="instanceS1" url="ip5:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" primary="false">
            <property name="heartbeatPeriodMillis">60000</property>
        </dbInstance>
    </dbGroup>
</Dble:db>

接下來是修改user.xml部分,這部分需要注意有managerUsershardingUser兩個角色,一個是管理員負責管理Dble的使用者,另一個sharingUser則需要建表許可權對於客戶端請求進行分庫分表。

<?xml version="1.0" encoding="UTF-8"?>
<Dble:user xmlns:Dble="http://Dble.cloud/">
    <managerUser name="man1" password="654321" whiteIPs="127.0.0.1,0:0:0:0:0:0:0:1" readOnly="false"/>
    <managerUser name="user" usingDecrypt="true" readOnly="true" password="AqEkFEuIFAX6g2TJQnp4cJ2r7Yc0Z4/KBsZqKhT8qSz18Aj91e8lxO49BKQElC6OFfW4c38pCYa8QGFTub7pnw==" />

    <shardingUser name="root" password="123456" schemas="testdb" readOnly="false" blacklist="blacklist1" maxCon="20"/>
    <shardingUser name="root2" password="123456" schemas="testdb,testdb2" maxCon="20" tenant="tenant1">
        <privileges check="true">
            <schema name="testdb" dml="0110">
                <table name="tb01" dml="0000"/>
                <table name="tb02" dml="1111"/>
            </schema>
        </privileges>
    </shardingUser>
    <!--rwSplitUser not work for now-->
    <rwSplitUser name="rwsu1" password="123456" dbGroup="dbGroup1" blacklist="blacklist1"
                 maxCon="20"/>
    <blacklist name="blacklist1">
        <property name="selectAllow">true</property>
    </blacklist>
</Dble:user>

最後我們來看看Dble的核心配置sharing.xml,根據官方的介紹他有下面的三個部分的主要內容。

  • schema (虛擬schema,可配置多個)
  • shardingNode (虛擬分片,可配置多個)
  • function (拆分演算法,可配置多個)

支援的分割槽演算法: 目前已支援的分割槽演算法有: hash, stringhash, enum, numberrange, patternrange, date,jumpstringhash,具體的分割槽演算法細節可以閱讀文件相關內容介紹,這裡就不過多介紹了。

目前國內使用的案例比較少這裡實戰部分直接找了一篇部落格,這裡就不做演示Dble的分庫分表了,有需要的時候再回來看看即可:

Dble分庫分表實戰_李如磊的技術部落格_51CTO部落格

如何提高分庫分表效能?

提高分庫分表效能問題首先想到的是搭建多個主備節點將主備複製和Dble進行結合。

其次可以在Dble上配置讀寫分離,配置讀寫分離同樣可以參考官方文件。

分庫分表存在問題

dble自動管理分庫分表實際上也是存在下面的問題的,而dble是基於mycat進行處理的,下面的規則對於分庫分表來說都會有類似的問題:

查詢語句中需要儘可能的帶有拆分欄位:

  • dble 根據拆分欄位判斷資料節點的位置。
  • 無法判斷資料節點只能遍歷所有的節點。這一點會導致分庫分表查詢的負優化

插入的語句同樣必須帶有拆分的欄位:

  • Dble 根據拆分的欄位,判斷資料在那個點 。

拆分儘量使用等值條件:

  • 範圍拆分欄位會導致過多節點掃描。
  • 使用IN語句縮減IN子句點值的數量。

減少表搜尋遍歷:

下面這些動作都會對於效能造成影響

  • 不帶拆分欄位。
  • Distinct,group by,order by。

減小結果集:

  • 資料互動會導致查詢效能受到影響。
  • 分散式系統導致節點大量的資料互動。

跨節點連表:

  • 對於經常join的表需要按照固定的規則拆分。
  • 使用拆分欄位作為join條件。
  • 儘量對於驅動表增加更多過濾條件。
  • 儘量減少資料的分頁。
  • 複雜語句拆分為簡單語句。

上面的內容小結如下:

  • 減少資料互動。
  • 資料增刪改查需要增加拆分欄位。
  • 連線鍵進行拆分處理。

切換

切換的核心是保業務還是保資料

如何進行身份切換:

  • 停止備庫同步
  • 配置主庫複製從庫。
  • 複製是一種平級的關係,可以獨立。

切換策略:

單純從切換策略卡率我們可以看到存在下面的兩種方式:

  • 可靠優先策略:意味著seconds\_behind\_master引數不能過大不能落後庫太大。需要把A庫切換為只讀的形式,這時候業務只能讀取不新增資料,當seconds\_behind\_master=0的時候意味著兩個庫同步。此時A庫停止,B庫停止複製A,A庫開始複製B庫。這個可靠說明的是資料可靠,但是不保證業務不受影響,因為最大的問題來自於停機。
  • 可用性策略:取消等待資料的一致過程,A庫只讀B庫關閉只讀,B庫停止複製A庫,A庫開始複製B庫,優點是系統沒有不可寫時間,缺點是切換的時候如果有沒有及時重放的relay log容易導致資料不一致。

​ 對於大多數普通業務執行儘量選用可靠優先策略,但是如果對於業務高可用嚴格建議可用性策略,比如日誌流水同樣需要可用性,對於一些資料要求強一致性的比較低允許一定資料丟失的業務則可以考慮使用可用性策略。

業務如何切換?

  • 預留介面,通知連線到新的資料庫地址。
  • 微服務框架通知業務,比如註冊中心。
  • 內部使用DNS,域名連線,切換之後重新整理DNS處理。

    • K8S使用了這種方式實現處理。
  • keepalived 進行VIP漂移。通過檢測處理優先順序處理。
  • 代理的方式切換:加一層代理負載均衡處理。
  • Dble的時候主備切換

自動主從切換

keepalived 如何主備切換?

keepalive是經常被使用的中介軟體,在自動主從切換中它擔任了身份切換和VIP飄移的角色,VIP即Virtual IP Address,是實現HA(高可用)系統的一種方案,高可用的目的是通過技術手段避免因為系統出現故障而導致停止對外服務,一般實現方式是部署備用伺服器,在主伺服器出現故障時接管業務。 VIP用於向客戶端提供一個固定的“虛擬”訪問地址,以避免後端伺服器發生切換時對客戶端的影響。

Keepalived的設計目的即是為了管理VIP,因此使用Keepalived實現VIP的配置非常簡單。Keepalived採用了Virtual Router Redundancy Protocol (VRRP)協議來進行實現主備伺服器之間的通訊以及選舉。

keepalive的主從切換類似下面的對方式,當比如當MysqlA服務當機會自動切換到下一個A`的伺服器提供服務,內部通過一定的選舉演算法選舉出新節點。

Mha(master high availability) 如何進行主備切換?

Mha也是常用的Mysql高可用元件,它通過自研主從切換的概念完成主備切換,這個元件由facebook工程師進行開發,同時支援GTID的方式,最大特點:在當機的時候第一時間登陸當機伺服器下載binlog日誌。但是Mha最大的問題是無法進行VIP漂移。

根據下面的圖可以看到,在Mha的工作機制當中,如果發現A節點的服務當機此時會立刻登陸到A節點的伺服器把檔案進行搶救,但是這裡存在複製的資料同步問題,在半同步複製中會有 脫扣時間導致binlog傳送轉變為非同步傳送有可能會出現binlog沒有傳遞過來的情況,這種情況下有可能會導致其他資料的不完整導致資料不同步。

值得一提的是Mha的並不是直接通過客戶端訪問當機節點而是需要等待SLAVE節點的資料落庫之後再通過從庫訪問主庫搶救binlog,這些操作基本都是來自於設計者日常工作經驗中發現的一些問題針對的特殊處理所以十分受到廣大開發者的青睞。

當搶救binlog任務完成之後,Mha 的下一步是重新選去Master,注意當機的節點不會用指令碼嘗試重啟恢復,因為這種情況下不通過人為干預通常已經沒有太大的效果了,即使重啟也有可能會有資料不一致的問題。

三高系統搭建

在搭建三高之前,我們需要思考為什麼有時候叢集搭建起來了為什麼還會掛?原因是任何一個成熟的單一系統都不會單純依賴某一個開源元件而是在中間層加入大量的容錯機制防止某一元件崩盤造成大面積的損失,這裡涉及到DRDS的概念,DRDS表示(Distributed Relational Database Service)分散式的Mysql叢集,而Mysql的叢集通常不會是本身的叢集,而是通過一系列的中介軟體維持三高的基本特徵。

接下來我們一步步來看下三高系統是如何搭建的:

分庫分表有一個問題點:我們發現當dble出現問題的時候會導致整個服務不可用,Dble的單點問題這裡我們後續進討論,這裡出現了Mha和Dble聯動來解決Mysql節點當機的問題。

對於開發人員來說日常實踐過程基本碰不到這個東西這裡同樣找了一篇在需要的時候進行學習大致的搭建流程和一些基本配置即可:

愛可生DBLE Mha-dble高可用聯動例項

下面是Mha結合DBLE對於整個架構的增強結構圖:

通過Mha和dble的搭配,當節點出現當機的時候可以通過Mha進行節點的切換保證分庫分表的正常工作。

但是我們還發現一個問題那就是dble本身也是單點的,所以dble也需要做叢集的負載均衡防止整個節點不可用,而對於dble的負載分發可以通過Haproxy結合zookeeper進行處理。

HAProxy 是一款提供高可用性、負載均衡以及基於TCP(第四層)和HTTP(第七層)應用的代理軟體,支援虛擬主機,它是免費、快速並且可靠的一種解決方案。 HAProxy特別適用於那些負載特大的web站點,這些站點通常又需要會話保持或七層處理。HAProxy執行在時下的硬體上,完全可以支援數以萬計的 併發連線。並且它的執行模式使得它可以很簡單安全的整合進您當前的架構中, 同時可以保護你的web伺服器不被暴露到網路上。

ZooKeeper是一個集中式服務,用於維護配置資訊、命名、提供分散式同步和提供組服務。所有這些型別的服務都以某種形式被分散式應用使用。每次實現這些服務時,都有大量的工作用於修復不可避免的錯誤和競爭條件。由於實現這類服務的難度,應用程式最初通常會忽略它們,這使得它們在變化的情況下變得很脆弱而且難以管理。即使做得正確這些服務的不同實現也會導致應用程式部署時的管理複雜性。

最後客戶端通過keepalive的VIP飄移尋找閘道器的入口,經過選舉分發之後找到對應的dble,dble再進行分庫分表查詢相關的資料進行處理,最後找到相關的Mysql節點彙總資料之後返回給客戶端,當Mysql節點出現問題的時候,Mha則會通過一系列的指令碼搶救binlog檔案之後重新選舉主從節點。

至此一個三高架構的分散式Mysql叢集的完整結構完成,我們把上面的文字用結構圖表示可以看到還是十分複雜的:

總結

​ 本部分內容講述了Mysql分割槽表特性,以及一個國產開源的分庫分表外掛,其實分庫分表對於大部分的中小專案基本都是不需要的,它通常出現在比較大的系統架構當中,dble作為一款國產開源元件有著不錯的表現,在Mycat的基礎上改進的同時使用JAVA語言編寫十分貼合WEB開發人員的喜好。

​ 在切換的部分我們講述了另外兩個元件:MHA和Keepalive,這兩個元件由大量的資源和案例參考,所以這裡簡單拿來介紹它們是如何和Mysql進行組合增強叢集架構的高可用特性的,

寫到最後

​ 三高架構看起來十分複雜並且高大上,然而實際上我們把元件拆分完成之後發現各個元件的角色分工非常明確,作用也比較明顯。當然這些內容可能更多是運維會接觸到和使用到,對於開發人員來說這些內容只需要簡單瞭解流程和理論即可。

相關文章