本次專題是 MySQL高可用方案選型,這個專題想必有不少同窗感興趣。html
高可用的意義以及各類不一樣高可用等級相應的停機時間我就沒必要多說了,直接進入主題。前端
MySQL的各類高可用方案,大可能是基於如下幾種基礎來部署的:node
基於主從複製;mysql
基於Galera協議;linux
基於NDB引擎;web
基於中間件/proxy;sql
基於共享存儲;數據庫
基於主機高可用;vim
在這些可選項中,最多見的就是基於主從複製的方案,其次是基於Galera的方案,咱們重點說說這兩種方案。其他幾種方案在生產上用的並很少,咱們只簡單說下。centos
通常來講,中小型規模的時候,採用這種架構是最省事的。
兩個節點能夠採用簡單的一主一從模式,或者雙主模式,而且放置於同一個VLAN中,在master節點發生故障後,利用keepalived/heartbeat的高可用機制實現快速切換到slave節點。
在這個方案裏,有幾個須要注意的地方:
採用keepalived做爲高可用方案時,兩個節點最好都設置成BACKUP模式,避免由於意外狀況下(好比腦裂)相互搶佔致使往兩個節點寫入相同數據而引起衝突;
把兩個節點的auto_increment_increment(自增起始值)和auto_increment_offset(自增步長)設成不一樣值。其目的是爲了不master節點意外宕機時,可能會有部分binlog未能及時複製到slave上被應用,從而會致使slave新寫入數據的自增值和原先master上衝突了,所以一開始就使其錯開;固然了,若是有合適的容錯機制能解決主從自增ID衝突的話,也能夠不這麼作;
slave節點服務器配置不要太差,不然更容易致使複製延遲。做爲熱備節點的slave服務器,硬件配置不能低於master節點;
若是對延遲問題很敏感的話,可考慮使用MariaDB分支版本,或者直接上線MySQL 5.7最新版本,利用多線程複製的方式能夠很大程度下降複製延遲;
對複製延遲特別敏感的另外一個備選方案,是採用semi sync replication(就是所謂的半同步複製)或者後面會提到的PXC方案,基本上無延遲,不過事務併發性能會有不小程度的損失,須要綜合評估再決定;
keepalived的檢測機制須要適當完善,不能僅僅只是檢查mysqld進程是否存活,或者MySQL服務端口是否可通,還應該進一步作數據寫入或者運算的探測,判斷響應時間,若是超過設定的閾值,就能夠啓動切換機制;
keepalived最終肯定進行切換時,還須要判斷slave的延遲程度。須要事先定好規則,以便決定在延遲狀況下,採起直接切換或等待何種策略。直接切換可能由於複製延遲有些數據沒法查詢到而重複寫入;
keepalived或heartbeat自身都沒法解決腦裂的問題,所以在進行服務異常判斷時,能夠調整判斷腳本,經過對第三方節點補充檢測來決定是否進行切換,可下降腦裂問題產生的風險。
雙節點主從+keepalived/heartbeat方案架構示意圖見下:
圖解:MySQL雙節點(單向/雙向主從複製),採用keepalived實現高可用架構。
多節點主從,能夠採用一主多從,或者雙主多從的模式。
這種模式下,能夠採用MHA或MMM來管理整個集羣,目前MHA應用的最多,優先推薦MHA,最新的MHA也已支持MySQL 5.6的GTID模式了,是個好消息。
MHA的優點很明顯:
開源,用Perl開發,代碼結構清晰,二次開發容易;
方案成熟,故障切換時,MHA會作到較嚴格的判斷,儘可能減小數據丟失,保證數據一致性;
提供一個通用框架,可根據本身的狀況作自定義開發,尤爲是判斷和切換操做步驟;
支持binlog server,可提升binlog傳送效率,進一步減小數據丟失風險。
不過MHA也有些限制:
須要在各個節點間打通ssh信任,這對某些公司安全制度來講是個挑戰,由於若是某個節點被黑客攻破的話,其餘節點也會跟着遭殃;
自帶提供的腳本還須要進一步補充完善,固然了,通常的使用仍是夠用的。
在大規模節點環境下,採用keepalived或者MHA做爲MySQL的高可用管理仍是有些複雜或麻煩。
首先,這麼多節點若是沒有采用配置服務來管理,必然雜亂無章,線上切換時很容易誤操做。
在較大規模環境下,建議採用etcd/zookeeper管理集羣,可實現快速檢測切換,以及便捷的節點管理。
Galera是Codership提供的多主數據同步複製機制,能夠實現多個節點間的數據同步複製以及讀寫,而且可保障數據庫的服務高可用及數據一致性。
基於Galera的高可用方案主要有MariaDB Galera Cluster和Percona XtraDB Cluster(簡稱PXC),目前PXC用的會比較多一些。
PXC的架構示意圖見下:
(圖片源自網絡),圖解:在底層採用wsrep接口實現數據在多節點間的同步複製。
(圖片源自網絡),圖解:在PXC中,一次數據寫入在各個節點間的驗證/回滾流程。
PXC的優勢
服務高可用;
數據同步複製(併發複製),幾乎無延遲;
多個可同時讀寫節點,可實現寫擴展,不過最好事先進行分庫分表,讓各個節點分別寫不一樣的表或者庫,避免讓galera解決數據衝突;
新節點能夠自動部署,部署操做簡單;
數據嚴格一致性,尤爲適合電商類應用;
徹底兼容MySQL;
雖然有這麼多好處,但也有些侷限性:
只支持InnoDB引擎;
全部表都要有主鍵;
不支持LOCK TABLE等顯式鎖操做;
鎖衝突、死鎖問題相對更多;
不支持XA;
集羣吞吐量/性能取決於短板;
新加入節點採用SST時代價高;
存在寫擴大問題;
若是併發事務量很大的話,建議採用InfiniBand網絡,下降網絡延遲;
事實上,採用PXC的主要目的是解決數據的一致性問題,高可用是順帶實現的。由於PXC存在寫擴大以及短板效應,併發效率會有較大損失,相似semi sync replication機制。
基於NDB Cluster,因爲NDB目前仍有很多缺陷和限制,不建議在生產環境上使用;
基於共享存儲,一方面須要不太差的存儲設備,另外共享存儲可也會成爲新的單點,除非採用基於高速網絡的分佈式存儲,相似RDS的應用場景,架構方案就更復雜了,成本也可能更高;
基於中間件(Proxy),如今可靠的Proxy選擇並很少,並且沒有通用的Proxy,都有有所針對,好比有的專一解決讀寫分離,有的專一分庫分表等等,真正好用的Proxy通常要自行開發;
基於主機高可用,是指採用相似RHCS構建一個高可用集羣后,再部署MySQL應用的方案。老實說,我沒實際用過,但從側面瞭解到這種方案生產上用的並很少,可能也有些侷限性所致吧;
以DBA們的聰明才智,確定還有其餘我不知道的方案,也歡迎同行們間多多交流。
不多有事情比推出高可用性(HA)系統以後便常常看到的系統崩潰更糟糕。對於咱們這個Rails運行機的團隊來講,這個失效的HA系統是MySQL多主複製管理器(MMM)。
咱們已經找尋MMM的替代品有一段時間了,幾個月以前,咱們轉換到了MariaDB + Galera Cluster以尋求高可用的Mysql。
MMM怎麼了,Galera Cluster又有什麼特別之處呢?繼續閱讀!
MySQL MMM 是如何工做的:一臺安裝了MySQL MMM的服務器每十秒種(默認間隔)輪詢一次MySQL節點, 來檢查其狀態。僅其中的一臺服務器接收到寫入器角色 - 其餘的能夠擁有閱讀器角色。 MMM 維護了一個虛擬IP,這個IP指向擁有寫入器角色的節點。
問題在於輪詢:若是MySQL每十分鐘輪詢,那麼若是寫入器節點在檢查的間歇出現故障怎麼辦?若是你設置了HA你可能正處理着許多事務 - 在MMM檢測到寫入器節點不正常以前,可能已經有成千上萬的事務失敗了。更糟糕的是,若是存在一種內部問題:複製失敗在先,事務失敗在後,那麼你要把寫入器角色轉到其餘節點上嗎?可是其餘節點不必定符合原始的寫入器節點。
減小輪詢間隔到1秒也不能修正這個問題-大型數據庫可能在每秒內運行許多事務。
所以輪詢是根本問題,並且超出了根本問題範圍。沒法控制的MySQL MMM常常產生難以恢復的問題。Baron Swartz在Percona的MySQL大神上對MMM的缺陷有以下描述:
簡要地來講,MMM產生的宕機時間比它要防止的宕機時間更長。所以它是一個低可靠性的工具,不是高可靠性的工具。它可讓你連續幾天以7X24小時的工做方式從宕機的機器裏提取數據,並放回到服務器上,這隻會致使系統真正的很是嚴重的一塌糊塗。所以,MMM賦予詞語"cluset-f__k"新的意義。
儘管MMM存在缺陷,然而它至少是對MySQL進行高可靠性的一次突破。然而時間改變了一切。甚至MySQL MMM的建立者也說到了要更改的時候了。Baron有關MMM的博客日誌有Alexey's的以下評論:
我是MMM的最初的做者,我徹底贊成你的意見。每次我試圖給集羣添加HA的時候,我都會想起MMM,並且須要親自去嘗試,由於我只是不肯定這個工具的我所作的配置。並且市場上沒有其餘軟件能夠可靠地作這項工做。
咱們的Galera Cluster設置仍然使用輪詢來作健康檢測——這比MMM好在哪裏呢?
答案在於主從複製怎樣是運做的。對於標準版的MySQL,對master的寫操做被記錄於一個二進制的日誌。Slave會在以後複製二進制日誌中的查詢。查詢在寫服務器上運行與在其它節點上運行時刻之間,老是會有一個延遲。它是異步的。
MySQL異步複製有下面的問題:
slave服務器的數據集老是落後於master服務器。
MySQL複製很慢——它從二進制日誌回訪事務。
對於Galera,事務是在它們被提交以前被全部節點確認。若是一個事務在一個節點失敗了,那個節點將馬上從羣集中移除。換句話說,Galera主從複製是同步的。你 永遠也不會丟失事務——沒有延遲 (並且Galera的 基於行的複製大約要快5倍速)。
MySQL MMM 是一個局外者—— 對於服務器上實際在發生的事情它是「啞的」。它只作一種檢測,並且那就是它所知道的所有該如何反應的事情。
Galera集羣是一個「局內人」,所以對每一個節點的內部狀態要更機靈,而且不須要人工干預就能夠作正確的事情(例如,一個節點同步或未同步,成爲一個donor(節點處於爲新節點準備或傳輸集羣全量數據狀態,對客戶端不可用),等等——所有都是自動的)。
因爲用一個Galera集羣能夠寫進任意節點,咱們仍是選擇儘可能減小潛在的死鎖和只在一個節點寫入。爲此,咱們使用HAProxy:咱們擁有一個前端供「寫入者」節點,另外一個前端供讀出以供全部節點實現餘額查詢。「寫入者」經過單個節點發送請求,而其餘的節點做爲備份。
若是HAProxy檢測到「寫入者」節點不正常,它當即提拔備份節點中的一個做爲「寫入者」。MySQL的MMM在這種狀況下一般會關掉全部節點之間的通話——HAProxy不會如此。當「寫入者」後臺更新的時候,咱們可能會丟失一部分請求,但它不會致使不一致的數據集經過服務器,這比癱瘓更糟糕。
咱們不會自動修復失敗的節點,不過這沒有關係。我主要關注點是確保一個正常的節點在執行寫入,HAProxy是作這個的。
當一個節點在標準的MySQL複製的時候失效,你將在再次進行復制的時候把大量的負載集中在一臺服務器上(這臺服務器不只僅要進行讀和寫,並且還要承接來自innodbbackupex的負載)。
使用Galera,你可讓其中一個節點離線(所以你至少須要三個節點)。這時這個節點就成爲供給者節點-對它的寫操做將被阻塞。這個節點就經過rsync傳輸自身的數據給失效的節點(或者新的節點)。而後,供給者節點和失效節點經過輔助隊列運行查詢而與其餘節點保持同步。
一旦這兩個節點回歸到同步狀態,HAProxy將自動的標記它們爲啓動狀態,而後把它們添回道前端。
切換到MariaDB的理由既有技術緣由也有政治緣由:
易於移植:首先,MariaDB是MySQL的隨手可得的替代品。從MySQL 5.1移植到MariaDB,只有Galera服務器5.6能夠運行。
性能:咱們有幾個包含索引的在性能方面存在問題的查詢,後面經過使人驚訝的移植來」修補「這方面的問題。MariaDB彷佛更適合於複雜查詢和鏈接,而Rails上的Ruby也因處理複雜的查詢和鏈接而揚名。MariaDB更適合作查找索引的整個工做,並且正如我前面所說,許多使人煩惱的查詢如今已經提速了。咱們彷佛看不到兩者在內存使用上有任何使人吃驚的區別。我指望Galera能更多的使用內存,不過若是這麼作了,那麼Galera就沒有任何值得關注的地方了。
社團:MariaDB有很大的驅動力,並且與MySQL相比增長了更多的功能。Oracle對MySQL將來傾注了大量的心血,而MariaDB看起來也存活了好長時間-甚至谷歌正在切換到MariaDB。
絕對地。咱們沒有看到有什麼緣由不切換到 MariaDB 和 Galera Cluster。
監控 Galera 的一件偉大的事情是它是分層的 - 咱們能夠很容易地監視棧的每一部分。咱們使用 Scout 來監視,那意味着咱們僅僅須要去使用下列插件:
MariaDB Galera Cluster - 安裝在每個 Galera Cluster 結點上去獲取關鍵指標(本地狀態,連通性,等)。
HAProxy - 爲每個代理安裝(寫入器一次,讀取器一次)。
URL Monitoring - 檢測和 HAProxy 檢測的相同的狀態URL來決定結點的健康。
直到最近, MySQL MMM 是添加高可用性到 MySQL 的最好的(但壞了的)途徑。Galera Cluster 最終爲 MySQL 增長了真實的高可用性,主要多虧同步複製。
MariaDB做爲Mysql的一個分支,在開源項目中已經普遍使用,例如大熱的openstack,因此,爲了保證服務的高可用性,同時提升系統的負載能力,集羣部署是必不可少的。
MariaDB集羣是MariaDB同步多主機集羣。它僅支持XtraDB/ InnoDB存儲引擎(雖然有對MyISAM實驗支持 - 看wsrep_replicate_myisam系統變量)。
主要功能:
同步複製
真正的multi-master,即全部節點能夠同時讀寫數據庫
自動的節點成員控制,失效節點自動被清除
新節點加入數據自動複製
真正的並行複製,行級
用戶能夠直接鏈接集羣,使用感覺上與MySQL徹底一致
優點:
由於是多主,因此不存在Slavelag(延遲)
不存在丟失事務的狀況
同時具備讀和寫的擴展能力
更小的客戶端延遲
節點間數據是同步的,而Master/Slave模式是異步的,不一樣slave上的binlog多是不一樣的
技術:
Galera集羣的複製功能基於Galeralibrary實現,爲了讓MySQL與Galera library通信,特別針對MySQL開發了wsrep API。
Galera插件保證集羣同步數據,保持數據的一致性,靠的就是可認證的複製,工做原理以下圖:
當客戶端發出一個commit的指令,在事務被提交以前,全部對數據庫的更改都會被 write-set 收集起來,而且將write-set 紀錄的內容發送給其餘節點。
write-set 將在每一個節點進行認證測試,測試結果決定着節點是否應用write-set更改數據。
若是認證測試失敗,節點將丟棄 write-set ;若是認證測試成功,則事務提交。
安裝MariaDB集羣至少須要3臺服務器(若是隻有兩臺的話須要特殊配置,請參照官方文檔)
在這裏,我列出試驗機器的配置:
操做系統版本:centos7
node4:10.128.20.16 node5:10.128.20.17 node6:10.128.20.18
以第一行爲例,node4爲 hostname ,10.128.20.16爲 ip ,在三臺機器修改 /etc/hosts 文件,個人文件以下:
10.128.20.16 node4 10.128.20.17 node5 10.128.20.18 node6
爲了保證節點間相互通訊,須要禁用防火牆設置(若是須要防火牆,則參照官方網站增長防火牆信息設置)
在三個節點分別執行命令:
systemctl stop firewalld
而後將 /etc/sysconfig/selinux 的 selinux 設置成 disabled ,這樣初始化環境就完成了。
[root@node4 ~]# yum install -y mariadb mariadb-galera-server mariadb-galera-common galera rsync
[root@node5 ~]# yum install -y mariadb mariadb-galera-server mariadb-galera-common galera rsync
[root@node6 ~]# yum install -y mariadb mariadb-galera-server mariadb-galera-common galera rsync
初始化數據庫服務,只在一個節點進行
[root@node4 mariadb]# systemctl start mariadb [root@node4 mariadb]# mysql_secure_installation NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY! In order to log into MariaDB to secure it, we'll need the current password for the root user. If you've just installed MariaDB, and you haven't set the root password yet, the password will be blank, so you should just press enter here. Enter current password for root (enter for none): OK, successfully used password, moving on... Setting the root password ensures that nobody can log into the MariaDB root user without the proper authorisation. Set root password? [Y/n] New password: Re-enter new password: Password updated successfully! Reloading privilege tables.. ... Success! By default, a MariaDB installation has an anonymous user, allowing anyone to log into MariaDB without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] n ... skipping. Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] y ... Success! By default, MariaDB comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] n ... skipping. Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] y ... Success! Cleaning up... All done! If you've completed all of the above steps, your MariaDB installation should now be secure. Thanks for using MariaDB!
關閉數據庫,修改 /etc/my.cnf.d/galera.cnf
[root@node4 mariadb]# systemctl stop mariadb
[root@node4 ~]# vim /etc/my.cnf.d/galera.cnf
修改如下內容:
[mysqld] ...... wsrep_provider = /usr/lib64/galera/libgalera_smm.so wsrep_cluster_address = "gcomm://node4,node5,node6" wsrep_node_name = node4 wsrep_node_address=10.128.20.16 #wsrep_provider_options="socket.ssl_key=/etc/pki/galera/galera.key; socket.ssl_cert=/etc/pki/galera/galera.crt;"
提示:若是不用ssl的方式認證的話,請把 wsrep_provider_options 註釋掉。
將此文件複製到node五、node6,注意要把 wsrep_node_name 和 wsrep_node_address 改爲相應節點的 hostname 和ip。
[root@node4 ~]# /usr/libexec/mysqld --wsrep-new-cluster --user=root &
觀察日誌:
[root@node4 ~]# tail -f /var/log/mariadb/mariadb.log 150701 19:54:17 [Note] WSREP: wsrep_load(): loading provider library 'none' 150701 19:54:17 [Note] /usr/libexec/mysqld: ready for connections. Version: '5.5.40-MariaDB-wsrep' socket: '/var/lib/mysql/mysql.sock' port: 3306 MariaDB Server, wsrep_25.11.r4026
出現 ready for connections ,證實咱們啓動成功,繼續啓動其餘節點:
[root@node5 ~]# systemctl start mariadb
[root@node6 ~]# systemctl start mariadb
能夠查看 /var/log/mariadb/mariadb.log,在日誌能夠看到節點均加入了集羣中。
警告:--wsrep-new-cluster 這個參數只能在初始化集羣使用,且只能在一個節點使用。
咱們能夠關注幾個關鍵的參數:
wsrep_connected = on 連接已開啓
wsrep_local_index = 1 在集羣中的索引值
wsrep_cluster_size =3 集羣中節點的數量
wsrep_incoming_addresses = 10.128.20.17:3306,10.128.20.16:3306,10.128.20.18:3306 集羣中節點的訪問地址
咱們在 node4 上新建數據庫 galera_test ,而後在 node5 和 node6 上查詢,若是能夠查詢到 galera_test 這個庫,說明數據同步成功,集羣運行正常。
[root@node4 ~]# mysql -uroot -proot -e "create database galera_test"
[root@node5 ~]# mysql -uroot -proot -e "show databases" +--------------------+ | Database | +--------------------+ | information_schema | | galera_test | | mysql | | performance_schema | +--------------------+
[root@node6 ~]# mysql -uroot -proot -e "show databases" +--------------------+ | Database | +--------------------+ | information_schema | | galera_test | | mysql | | performance_schema | +--------------------+
至此,咱們的 MariaDB Galera Cluster 已經成功部署。