本文將接著前文?1w5字詳細(xì)介紹分布式系統(tǒng)的那些技術(shù)方案?文章基礎(chǔ)上,進行實際的案例解析?
高可用對于當(dāng)下的系統(tǒng)而言,可以說是一個硬指標(biāo),常年專注于業(yè)務(wù)開發(fā)的我們,對于高可用最直觀的感覺可能就是祈禱應(yīng)用不要出問題,不要報錯;即便有問題,也最好不是我們的業(yè)務(wù)代碼邏輯導(dǎo)致的,如果是服務(wù)器、DB、中間件(如注冊中心、配置中心等)的異常那就拋給對應(yīng)的sre, dba;然而常在河邊走,哪有不濕鞋,為了保障服務(wù)的高可用,我們可以從哪些方面進行努力呢?
本文將作為高可用的開篇,通過簡述一些常用的系統(tǒng)的高可用方案,給大家介紹一下我們可以從哪些方面努力讓我們的系統(tǒng)達到高可用,主要設(shè)計到的系統(tǒng)如下
-
緩存:Redis
-
數(shù)據(jù)庫:MySql
-
消息隊列:RabbitMQ
-
搜索: ElasticSearch
1 redis高可用策略
redis廣泛應(yīng)用于緩存的業(yè)務(wù)場景,當(dāng)然也有將其當(dāng)做持久化存儲的nosql數(shù)據(jù)庫使用,這些都不重要,重點是redis在提供服務(wù)的時候,是如何支持高可用的呢?
redis官方支持了四種策略:
-
數(shù)據(jù)持久化
-
主從同步
-
哨兵模式
-
集群
除以上姿勢之外,我們自己在使用時還可以選擇根據(jù)業(yè)務(wù)場景使用不同的redis實例(即傳說中的不把所有雞蛋放在一個籃子里)
接下來將針對redis的幾種高可用策略進行簡述說明
1.1 數(shù)據(jù)持久化
持久化是在高可用、一致性的場景中經(jīng)常會看到的一種技術(shù)手段;
在高可用的場景中,數(shù)據(jù)的持久化主要是為了解決在服務(wù)出現(xiàn)問題(如宕機)之后,可以快速恢復(fù)并對外繼續(xù)提供服務(wù)能力;
redis官方提供了兩種持久化策略
-
AOF: 將更新的操作命令記錄在對應(yīng)的日志文件中,在重啟的時候采用“回放”策略,將所有的命令重新執(zhí)行一遍來實現(xiàn)場景恢復(fù)
-
RDB: 定時存儲redis中的數(shù)據(jù)快照到數(shù)據(jù)文件中,在重啟的時候,加載rdb文件,恢復(fù)所有的數(shù)據(jù)
簡單來講AOF記錄的是操作動作,采用回放執(zhí)行的機制進行恢復(fù);RDB則相當(dāng)于數(shù)據(jù)落盤,重新讀取加載的機制進行恢復(fù)
注:AOF RDB可以一起工作,沒有排他性
1.2 主從方式
雖然redis性能爆炸,但是單機依然存在性能瓶頸;當(dāng)我們遇到單機的性能瓶頸的時候,一般怎么做?
沒錯,加機器
redis也支持多機服務(wù),比如常見的一主多從策略:
-
主機:提供讀寫能力
-
從機:只提供讀
針對絕大多數(shù)讀多寫少的場景,我們可以起多個redis實例,其中一個設(shè)置為主,提供所有的寫請求;其他的實例則設(shè)置為從,客戶端通過負(fù)載策略路由到不同的從redis,從而實現(xiàn)流量分?jǐn)偅?/p>
同時也因為有多個實例,所以單臺或幾臺實例下線,對整個服務(wù)的可用性影響并不會太大(及時摘除故障機器,其他的實例依然可以正常提供服務(wù);當(dāng)然前提是流量所示太大把其他的實例也打掛,那就gg了)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?redis主從模式
主從模式還有一個變種,叫做從從模式,主要是為了解決主redis的同步壓力,改成主 -> 從,然后由一個從同步給其他的從實例,具體架構(gòu)圖如下
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? redis主從從模式?
使用主從、主從從模式實現(xiàn)高可用可算是分布式系統(tǒng)的經(jīng)典策略,其主要思想在于:
-
多實例提供服務(wù),實現(xiàn)負(fù)載均衡
-
每個實例冗余一份全量數(shù)據(jù)
1.3 哨兵模式
哨兵模式主要是為了解決主從模式中,主機宕機的場景,由于主機本身存在單點,所以主節(jié)點對成了高可用的關(guān)鍵因素了;那么如果實現(xiàn)主節(jié)點宕機之后,自動選擇一個新的主節(jié)點,這樣不就可以提高系統(tǒng)的可用性了么;redis官方提供的機制就是 - 哨兵模式
主要工作原理:
-
哨兵:監(jiān)聽redis實例,判斷是否存活(不太對外提供服務(wù)能力)
-
通過 PING 命令,檢查與主從服務(wù)器之間的連接情況,若正常相應(yīng),則認(rèn)為存活;否則認(rèn)為
主觀下線
-
當(dāng)?
n/2 + 1
半數(shù)以上哨兵認(rèn)為主節(jié)點下線,則認(rèn)為主節(jié)點客觀下線
,嘗試選新的主節(jié)點 -
從所有從節(jié)點中,選擇與之前主庫相似度最高的從節(jié)點作為新的主庫
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?哨兵模式
?哨兵模式,可以理解為探活 + 選主,而這也常見于各大分布式系統(tǒng)的技術(shù)方案中
1.4 集群模式
相比于主從模式的全量冗余,redis的集群策略在在于數(shù)據(jù)分片,每個實例上存儲部分的數(shù)據(jù);而不是全量數(shù)據(jù),從而解決數(shù)據(jù)量大的場景下,對于redis服務(wù)本身以及數(shù)據(jù)同步的壓力
集群模式的特點在于多個實例,構(gòu)建成一個實例,每個實例上存儲部分的數(shù)據(jù);redis并沒有采用一致性hash來做數(shù)據(jù)分布,而是使用特有的slots插槽機制,來實現(xiàn)數(shù)據(jù)的hash映射
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?集群模式
集群模式,主要特點在于數(shù)據(jù)分片,每個實例存部分?jǐn)?shù)據(jù),其思路在于拆分
從上面的圖中也可以看出,集群一般與主從搭配使用,集群中的每個分片對應(yīng)的是主從模式的redis服務(wù),從而加強高可用
1.5 小結(jié)
這一節(jié)主要介紹的是redis的高可用策略,從中也可以看到很多經(jīng)典的技術(shù)方案
-
持久化:RDB數(shù)據(jù)落盤加載方式 + AOF記錄操作命令用于回放策略
-
主從,主從從:全量數(shù)據(jù)冗余、讀寫請求分離,負(fù)載均衡的思想;核心問題在于主節(jié)點掛掉之后需要人工參與手動指定主庫
-
哨兵機制:PING/PONG的探活機制,監(jiān)聽主節(jié)點,宕機之后自動選主,確保高可用;核心問題在于所有的實例冗余相同的一份數(shù)據(jù),數(shù)據(jù)量大時不友好
-
集群:數(shù)據(jù)分片,每個實例提供部分服務(wù)能力
2 MySql高可用策略
MySql數(shù)據(jù)庫的高可用策略就比較多了,同樣也非常的經(jīng)典;僅僅主節(jié)點的保活策略就非常多了;在這里將主要的重心放在MySql的高可用架構(gòu)主備、主從、一主多從,多主多從上,至于主節(jié)點故障時轉(zhuǎn)移策略則放在后續(xù)詳細(xì)的文章中進行介紹
2.1 數(shù)據(jù)持久化
對于每個開發(fā)者而言,大多都聽說過數(shù)據(jù)庫的ACID特性,其中的D對應(yīng)的就是這里說到的持久化;區(qū)別于redis的持久化,以MySql的InnoDB引擎為例,其持久化涉及到多個日志文件(undo log,redo log,binlog),緩存區(qū)(buffer),磁盤(idb文件)
接下來看一下完整的數(shù)據(jù)更新/插入的流程
接下來描述一下核心思想:
-
數(shù)據(jù)更新策略:總是更新緩存的內(nèi)容(緩存未命中,則從磁盤加載到緩存)
-
先寫undolog日志文件:記錄之前的數(shù)據(jù),支持mvcc、支持回滾就靠它
-
redolog記錄的兩階段提交:(先是prepare,待binlog寫完之后,再次更新狀態(tài)為commit)
-
最后異步刷新緩存數(shù)據(jù)到磁盤
雖然上面的描述比較簡單,但是這里的知識點非常多,如
-
為什么先更新緩存,最后異步刷磁盤?
-
核心在于操作內(nèi)存的速度 >> 操作磁盤
-
-
undolog作用是什么,怎么支持mvcc,實現(xiàn)事務(wù)回滾的?
-
保障事務(wù)原子性的關(guān)鍵所在,數(shù)據(jù)行非主鍵變更時,記錄修改前的數(shù)據(jù)到undolog,并指向它,其他sql讀這個undolog中的副本數(shù)據(jù)從而支持mvcc,回滾時則是根據(jù)undo log進行邏輯恢復(fù)
-
-
redolog作用是什么,為什么兩階段方案?
-
主要保障事務(wù)的持久性,當(dāng)數(shù)據(jù)庫異常宕機之后,可以通過重新執(zhí)行redo log來恢復(fù)未及時落盤的數(shù)據(jù);兩階段的主要目的是為了解決redolog與binlog的一致性問題,避免出現(xiàn)redolog第一階段成功,但是binlog失敗導(dǎo)致不一致問題
-
redolog屬于innodb引擎,固定大小,環(huán)形結(jié)構(gòu)覆蓋寫策略;內(nèi)部同樣是先寫緩存,再刷磁盤的策略
-
2.2 主備架構(gòu)
保證高可用的一個最簡單策略就是“冗余”,也就是我們這里說到的主備架構(gòu),對mysql而言,就是我啟動兩個實例;一個主庫對外提供讀寫服務(wù),一個備庫,冗余主庫的所有數(shù)據(jù)內(nèi)容,并不對外提供服務(wù);
當(dāng)主庫gg之后,然后備庫升級,切換為主庫
話說這個思想和古代的儲君制非常像了,平時都是皇帝總領(lǐng)朝堂,太子就當(dāng)吉祥物;皇帝駕崩之后,太子就晉升為皇帝(論備胎的重要性)
?文章來源地址http://www.zghlxwxcb.cn/news/detail-778967.html
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MySql主備?
主備的最大特點就是多備一臺實例,在出問題時頂上,當(dāng)然缺點就很明顯了,嚴(yán)重的資源浪費
2.3 主從架構(gòu)
主從和前面mysql的思路差不多,主從模式一般又叫做讀寫分離,即寫主庫,讀從庫;相比于主備而言,最主要的突破點在于另外一個mysql實例不會干放著,而是尤其來承擔(dān)讀請求
主從的核心思想在于讀寫分離
2.4 一主多從
在前面主從的基礎(chǔ)上多掛幾個從庫,主要出發(fā)點在于當(dāng)前的互聯(lián)網(wǎng)場景下,絕大多數(shù)的應(yīng)用都是讀多寫少,通過掛多個從庫,可以有效提供整體服務(wù)的性能指標(biāo)
同樣一主多從的模式,也會區(qū)分為主從 + 主從從兩種,后者則主要是為了減少主庫的同步壓力,下圖為核心4架構(gòu)模型
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?MySql主從
2.5 多主多從
一主多從可以解決讀多寫少的場景,但總會出現(xiàn)寫瓶頸的場景;在不考慮分庫分表的業(yè)務(wù)手段之前(這種方式也可以理解為數(shù)據(jù)分片,類似上面說到的redis集群模式),僅僅從mysql的架構(gòu)模式出發(fā),自然會想到的策略就是多個主庫提供寫能力,這就是我們說的多主多從的架構(gòu)了
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?MySql主從
多主多從,其中每個主庫都可以獨立對外提供寫請求;從庫則對外提供讀請求
需要注意的是主庫之間的數(shù)據(jù)同步,即一個寫請求落到一個任意一個主庫之后,所有的主庫都會同步這個寫操作
2.6 主庫切換策略、主從同步策略
前面介紹的是幾種不同的主從架構(gòu)特點,主要通過主、備/從來新增實例來提高可用性;但是還有兩個非常重要的點沒有細(xì)說,一個是故障之后,如何確定新的主庫;另外一個則是主從/主主之間的數(shù)據(jù)如何同步,如何保證數(shù)據(jù)的一致性;
接下來我們將簡單的介紹下mysql中常見的一些做法(更詳細(xì)的當(dāng)然留在后面的專題)
主庫切換策略
VIP + KeepAlived
-
vip: 即virtual ip虛擬ip
-
KeepAlived: 保活腳本
其主要思路在于外部通過VIP訪問mysql實例(主從/主主),而KeepAlived用于檢測主庫是否存活,當(dāng)掛掉之后,VIP偏移到另外一個主庫(或者選一個從庫作為主庫)上,從而實現(xiàn)自動的切主流程
缺點:
-
級聯(lián)復(fù)制(主->從->從這種復(fù)制模式叫做級聯(lián)復(fù)制)或者一主多從在切換之后,其他從實例需要重新配置連接新主
MHA
Master High Avaliable 主庫高可用機制,也是當(dāng)下很多公司采用的策略;其包含一套完整的工具,在檢測到主庫不可用后,會自動將同步到最接近主庫的slave提升為master,然后將其他的slave指向新的master
其優(yōu)點非常明顯,通??梢詫崿F(xiàn)十秒內(nèi)的主從切換,擴展MySql節(jié)點也非常方便;而缺點則在于主要監(jiān)控主庫
MXC
PXC(Percona XtraDB Cluster)是一個完全開源的 MySQL 高可用解決方案。它將 Percona Server、Percona XtraBackup 與 Galera 庫集成在一起,以實現(xiàn)多主復(fù)制的 MySQL 集群
其核心特點在于寫請求會自動同步到其他節(jié)點,要求在所有的節(jié)點都驗證之后才會提交,保證數(shù)據(jù)的強一致性
因此缺點就在于木桶效應(yīng),性能取決于最差的那個節(jié)點
MGR/InnoDB Cluste
MySQL 5.7 推出了 MGR(MySQL Group Replication),與 PXC 類似,也實現(xiàn)了多節(jié)點數(shù)據(jù)寫入和強一致性的特點。MGR 采用 GCS(Group Communication System)協(xié)議同步數(shù)據(jù),GCS 可保證消息的原子性
外部連接通過 MySql router與一組mysql實例進行交互,當(dāng)主庫切換時,mysql router會自動切換到新的主節(jié)點
Xenon
給予Raft協(xié)議的MySql高可用和復(fù)制性管理工具,無中心化選主,支持秒級切換
主從同步策略
當(dāng)存在主從庫時,必然會存在同步問題,如何保障主庫與從庫數(shù)據(jù)的一致性呢?
主從同步流程
主從同步主要借助Binlog來實現(xiàn),這個在前面的圖中有簡單的體現(xiàn),下面則是相對完整的同步流程
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MySql主從數(shù)據(jù)同步
-
主庫生成binlog日志文件
-
statement:記錄具體引起改動的操作語句,比如insert xxxxx,缺點是某些函數(shù)會導(dǎo)致數(shù)據(jù)不一致(如now())
-
row:基于數(shù)據(jù)行的,原來數(shù)據(jù)行是xx值改為了yy 值,缺點是數(shù)據(jù)量大
-
mixed: 上面兩個混用
-
-
從庫的io線程拉主庫的binlog日志,寫入自己的relaylog(中繼日志),然后由sql線程讀取relaylog日志進行回放,實現(xiàn)數(shù)據(jù)同步
主從同步策略
使用主從之后,在實際的業(yè)務(wù)開發(fā)中,最最常遇到的問題就是主從延遲,即主庫數(shù)據(jù)已經(jīng)寫入了,但是讀從庫卻讀不到對應(yīng)的數(shù)據(jù),這個就是主從延遲了,它直接導(dǎo)致數(shù)據(jù)的不一致;當(dāng)然一般這種影響還好,但是如果因為主從延遲,現(xiàn)在主庫掛了,所有的從庫都沒有最新的記錄,這不就導(dǎo)致數(shù)據(jù)丟失了么,會導(dǎo)致嚴(yán)重的數(shù)據(jù)一致性問題
所以在主從同步的策略上,有下面幾種
case1:異步復(fù)制
主庫完成寫請求之后,理解返回結(jié)果,并不關(guān)心從庫是否同步接收處理,此時就可能出現(xiàn)上面說的,主庫掛了之后,所有從庫還存在未同步的數(shù)據(jù),導(dǎo)致數(shù)據(jù)丟失
case2:半同步復(fù)制
為了避免出現(xiàn)上面的問題,我們要求最少有一個從庫同步完之后,才響應(yīng)用戶端請求,這樣表明主庫宕機之后還有個兜底的
case3:全同步復(fù)制
這個更激進一點,要求所有的從庫都同步完,才算真正的ok,保證強一致性,缺點則在于性能會受到影響
2.7 小結(jié)
這一小節(jié)主要介紹的是MySql的高可用策略,從架構(gòu)方面出發(fā),有主備,主從,一主多從,多主多從,同時也簡單的介紹了下如何實現(xiàn)主庫的自動切換(MHA,MXC,MGR等)、主從數(shù)據(jù)同步流程,同步策略;如果想了解更詳細(xì)的內(nèi)容,請移步到mysql的高可用專題
下面小結(jié)一下保持高可用的主要思路
-
通過冗余來實現(xiàn)高可用:如主備
-
讀寫分離,實現(xiàn)負(fù)載均衡:主從、主從從模式
-
數(shù)據(jù)持久化策略:操作內(nèi)存(buffer),異步刷盤,兩階段提交保障一致性
3. RabbitMq高可用方案
消息中間件也是大家或多或少會接觸的一類系統(tǒng),接下來將以RabbitMq來看一下它的高可用是如何實現(xiàn)的
3.1 數(shù)據(jù)持久化
不同于前面MySql必然會持久化,RabbitMq的數(shù)據(jù)持久化是可選的,當(dāng)我們對數(shù)據(jù)的完整性要求高時,最好開啟持久化
首先簡單看一下rabbitmq的模型
?文章來源:http://www.zghlxwxcb.cn/news/detail-778967.html
我們這里說的持久化主要指
-
exchange持久化: 即exchange本身不會因為rabbitmq宕機而被刪除,需要手動指定durable=true
-
topic持久化:消費者通過topic從exchange中讀取消息,需要指定durable=true,避免出現(xiàn)宕機后隊列中的消息丟失
-
msg消息持久化:即生產(chǎn)者投遞到echange的消息,需要持久化到磁盤
注意rabbitmq的消息持久化也是先寫到buffer,然后再定時刷新到磁盤;
當(dāng)我們?yōu)榱吮U蠑?shù)據(jù)的完整性時,一般會開啟消息的確認(rèn)機制/事務(wù)機制,每次投遞等到mq回復(fù)一個確認(rèn)ack之后,才表示真正的投遞成功,而mq的應(yīng)答則是在消息的持久化之后進行
3.2 主備模式
同前面的MySql的主備,主節(jié)點提供讀寫,備節(jié)點同步主節(jié)點的數(shù)據(jù),不對外提供服務(wù)能力;當(dāng)主節(jié)點掛了之后,啟用備節(jié)點對外服務(wù),原主節(jié)點恢復(fù)之后則作為備節(jié)點存在
3.3 Shovel遠(yuǎn)程模式
遠(yuǎn)程模式可以實現(xiàn)雙活的一種模式,簡稱 shovel 模式,所謂的 shovel 就是把消息進行不同數(shù)據(jù)中心的復(fù)制工作,可以跨地域的讓兩個 MQ 集群互聯(lián),遠(yuǎn)距離通信和復(fù)制。
-
Shovel 就是我們可以把消息進行數(shù)據(jù)中心的復(fù)制工作,我們可以跨地域的讓兩個 MQ 集群互聯(lián)。
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? RabbitMq遠(yuǎn)程模式
如上圖,有兩個異地的 MQ 集群(可以是更多的集群),當(dāng)用戶在地區(qū) 1 這里下單了,系統(tǒng)發(fā)消息到 1 區(qū)的 MQ 服務(wù)器,發(fā)現(xiàn) MQ 服務(wù)已超過設(shè)定的閾值,負(fù)載過高,這條消息就會被轉(zhuǎn)到 地區(qū) 2 的 MQ 服務(wù)器上,由 2 區(qū)的去執(zhí)行后面的業(yè)務(wù)邏輯,相當(dāng)于分?jǐn)偽覀兊姆?wù)壓力。
3.4 鏡像模式
如下圖,用 KeepAlived 做了 HA-Proxy 的高可用,然后有 3 個節(jié)點的 MQ 服務(wù),消息發(fā)送到主節(jié)點上,主節(jié)點通過 mirror 隊列把數(shù)據(jù)同步到其他的 MQ 節(jié)點,這樣來實現(xiàn)其高可靠
鏡像模式的主要特點在于每個mq實例都包含一份完整的數(shù)據(jù)鏡像,內(nèi)部有一個master選舉算法,通過VIP對外提供連接
-
consumer,任意連接一個節(jié)點,若連上的不是master,請求會轉(zhuǎn)發(fā)給master,為了保證消息的可靠性,consumer回復(fù)ack給master后,master刪除消息并廣播所有的slaver去刪除。
-
publisher ,任意連接一個節(jié)點,若連上的不是master,則轉(zhuǎn)發(fā)給master,由master存儲并轉(zhuǎn)發(fā)給其他的slaver存儲。如果master掛掉,則從slaver中選擇消息隊列最長的為master,
3.5 普通集群模式
exchange,buindling再所有的節(jié)點上都會保存一份,但是queue只會存儲在其中的一個節(jié)點上,但是所有的節(jié)點都會存儲一份queue的meta信息
如果生產(chǎn)者連接的是另外一個節(jié)點,將會把消息轉(zhuǎn)發(fā)到存儲該隊列的節(jié)點上。如果消費者連接了非存儲隊列的節(jié)點取數(shù)據(jù),則從存儲消息的節(jié)點拉取數(shù)據(jù)。
其核心特點在于:
-
數(shù)據(jù)拆分存儲,若純消息的節(jié)點掛了,則只能等待它恢復(fù)之后才能正常工作
3.6 多活模式
rabbitMQ 部署架構(gòu)采用雙中心模式(多中心),那么在兩套(或多套)數(shù)據(jù)中心各部署一套 rabbitMQ 集群,各中心的rabbitMQ 服務(wù)除了需要為業(yè)務(wù)提供正常的消息服務(wù)外,中心之間還需要實現(xiàn)部分隊列消息共享
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?RabbitMq鏡像模式
federation 插件是一個不需要構(gòu)建 cluster ,而在 brokers 之間傳輸消息的高性能插件,federation 插件可以在 brokers 或者 cluster 之間傳輸消息,連接的雙方可以使用不同的 users 和 virtual hosts,雙方也可以使用不同版本的 rabbitMQ 和 erlang。
federation 插件使用 AMQP 協(xié)議通信,可以接受不連續(xù)的傳輸。federation 不是建立在集群上的,而是建立在單個節(jié)點上的,如圖上黃色的 rabbit node 3 可以與綠色的 node1、node2、node3 中的任意一個利用 federation 插件進行數(shù)據(jù)同步。
3.7 小結(jié)
rabbitmq的高可用機制的方案也比較好理解
-
主備模式
-
鏡像模式:全量冗余一份數(shù)據(jù),主對外提供服務(wù),可以實現(xiàn)自動切主
-
普通集群模式:數(shù)據(jù)拆分到集群的實例中,consumer/publisher連接到實例之后,會從具體持有exchange/topic的實例上拉數(shù)據(jù)
-
遠(yuǎn)程模式:適用于多中心的場景,將消息轉(zhuǎn)發(fā)給其他中心的實例
這里采用的高可用思路也無外乎常見的幾種:持久化 + 數(shù)據(jù)冗余 + 拆分
4. ElasticSearch高可用方案
接下來我們再看一下現(xiàn)在非常流行的分布式搜索引擎ElasticSearch是如何保證高可用的
4.1 集群
對于es而言,通常都是集群方式對外提供服務(wù),每啟動一個實例叫做一個節(jié)點(Node),每個節(jié)點會定義一個節(jié)點名(Node Name),集群名(Cluster Name),相同集群名的節(jié)點會構(gòu)建為一個集群;
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ES集群??
上圖包含了es集群的核心要素:
-
每個節(jié)點包含集群名 + 節(jié)點名兩個屬性,相同集群名的節(jié)點掛在一個集群內(nèi)
-
節(jié)點啟動之后,開始PING其他節(jié)點(連接上后會得到對應(yīng)節(jié)點所在集群的所有信息)
-
節(jié)點發(fā)現(xiàn)主要靠Zen Discover來實現(xiàn),選舉也是靠它來實現(xiàn)
選舉主要流程如下
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?ES選舉
-
選舉同樣也是依賴Zen Discover來實現(xiàn)
-
每個節(jié)點上報自己任務(wù)的主節(jié)點,然后票數(shù)最多的就是主節(jié)點;票數(shù)相同的情況下,根據(jù)ID排序,選第一個
上面就是es集群的構(gòu)建與主節(jié)點的選舉過程;es支持任意節(jié)點數(shù)目的集群(1- N),無法完全依賴投票的機制來選主,而是通過一個規(guī)則。
只要所有的節(jié)點都遵循同樣的規(guī)則,得到的信息都是對等的,選出來的主節(jié)點肯定是一致的。
但分布式系統(tǒng)的問題就出在信息不對等的情況,這時候很容易出現(xiàn)腦裂(Split-Brain)的問題。
大多數(shù)解決方案就是設(shè)置一個 Quorum 值,要求可用節(jié)點必須大于 Quorum(一般是超過半數(shù)節(jié)點),才能對外提供服務(wù)。而 Elasticsearch 中,這個 Quorum 的配置就是?discovery.zen.minimum_master_nodes
,當(dāng)候選主節(jié)點的個數(shù)超過這個參數(shù)值時,開始選舉,選主完成之后對外提供服務(wù)
ES作為分布式、近實時搜索系統(tǒng),天然支持集群的服務(wù)能力,通過Zen Discover來實現(xiàn)節(jié)點通信、集群管理、選主
4.2 腦裂問題
上面提到了腦裂,接下來簡單看一下ES是如何解決腦裂問題的
腦裂:由于網(wǎng)絡(luò)或者集群健康監(jiān)測問題,導(dǎo)致整個集群出現(xiàn)多個master節(jié)點,這種現(xiàn)象就是腦裂
es對節(jié)點進行了角色劃分
-
數(shù)據(jù)節(jié)點:負(fù)責(zé)數(shù)據(jù)的存儲和相關(guān)的操作(CURD,聚合)等,因此對機器性能要求較高
-
候選主節(jié)點:擁有選舉權(quán)和被選舉權(quán),主節(jié)點在候選主節(jié)點中評選出來,負(fù)責(zé)創(chuàng)建索引、刪除索引、跟蹤哪些節(jié)點是群集的一部分,并決定哪些分片分配給哪些的節(jié)點、追蹤集群中節(jié)點的狀態(tài)等
一個節(jié)點,可以即是數(shù)據(jù)節(jié)點,又是候選主節(jié)點,但是注意它們兩者的定位,主節(jié)點對機器性能要求沒有數(shù)據(jù)節(jié)點高,當(dāng)一臺機器既是數(shù)據(jù)節(jié)點又是主節(jié)點時,可能出現(xiàn)長耗時、耗資源的請求導(dǎo)致主節(jié)點服務(wù)異常;
通常更推薦的方案是使用性能低一點的作為候選主節(jié)點,性能高的作為數(shù)據(jù)節(jié)點
?
接下來看下腦裂出現(xiàn)的情況
-
網(wǎng)絡(luò)問題,導(dǎo)致分區(qū):即部分節(jié)點連接不到主節(jié)點,認(rèn)為它掛了,然后選舉出現(xiàn)的主節(jié)點
-
主節(jié)點負(fù)載、響應(yīng)延遲:主節(jié)點由于負(fù)載過高、或者響應(yīng)超時,導(dǎo)致重新選舉新的主節(jié)點
解決方案:
-
適當(dāng)調(diào)大ping timeout響應(yīng)時間,避免因為網(wǎng)絡(luò)、主節(jié)點性能問題導(dǎo)致的選舉
-
設(shè)置最少選舉節(jié)點數(shù)大于候選主節(jié)點的半數(shù),這樣只要有半數(shù)以上的候選節(jié)點存活,則可以選舉出一個主節(jié)點;而當(dāng)可用節(jié)點數(shù)小于半數(shù)時,不參與選舉,集群無法使用,也不會出現(xiàn)狀態(tài)異常的情況
-
角色分離:數(shù)據(jù)節(jié)點 + 候選主節(jié)點不放在一臺機器上;
在有主節(jié)點的系統(tǒng)中,一般都需要考慮腦裂問題,常見的策略無非是:
-
半數(shù)節(jié)點以上的投票才算有效
-
es額外提供了節(jié)點的角色定位,數(shù)據(jù)節(jié)點和候選主節(jié)點,其中只有候選主節(jié)點才有選舉權(quán)和被選舉權(quán),提供一種角色分離的可選方案,來避免主節(jié)點被其他數(shù)據(jù)服務(wù)影響
4.3 數(shù)據(jù)分片
當(dāng)數(shù)據(jù)量過大時,es支持自動拆分,將一個索引的上數(shù)據(jù)水平拆分到不同的數(shù)據(jù)塊--分片(Shards),為了提供可用性,每個索引在定義時除了分片之外,還會定義副本數(shù)量,這里的副本可以理解為數(shù)據(jù)冗余,其中副本和分片必然不在一個節(jié)點上,在主節(jié)點異常時,副本可以提供數(shù)據(jù)查詢能力
es默認(rèn)在創(chuàng)建索引時,分片數(shù)為5,每個分片對應(yīng)一個副本
?
ES通過分片,將索引數(shù)據(jù)水平拆分,分片數(shù)越多,每個分片上的數(shù)據(jù)量就越少;而副本則是對應(yīng)的每個分片的冗余,可以理解為主備,副本越多,消耗則越大
兩點小說明
-
對應(yīng)副本的概念,上面的分片也叫做主分片
-
當(dāng)一個數(shù)據(jù)寫入/更新到分片時,只有所有的副本都更新完畢之后,才算完成(可以MySql的全同步)
4.4 數(shù)據(jù)持久化
最后再說一下es的持久化機制,與前面先說持久化不同,es這里則需要先了解上面的基本流程,索引數(shù)據(jù)需要保存到主分片上,最終落盤,接下來看一下完整的流程
主分片數(shù)據(jù)更新流程
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ES數(shù)據(jù)更新流程
簡述一下上面的流程
-
首先請求隨機連一個es節(jié)點(這個節(jié)點叫做協(xié)調(diào)節(jié)點),然后通過路由算法,確定數(shù)據(jù)對應(yīng)的主分片
-
寫數(shù)據(jù)到主分片,然后同步到副本(多個副本時采用并發(fā)同步,樂觀鎖控制)
-
所有副本同步完成之后,主分片節(jié)點告訴協(xié)調(diào)節(jié)點最終結(jié)果,然后協(xié)調(diào)節(jié)點告訴調(diào)用者響應(yīng)
當(dāng)數(shù)據(jù)寫入到主分片上之后,接下來再看一下這個數(shù)據(jù)時如何刷新到磁盤上的
分段存儲
索引文檔以段的形式存儲磁盤,即一個索引文件會劃分為很多個子文件,這里的子文件就是段
每一個段本身都是一個倒排索引,并且段具有不變性,一旦索引的數(shù)據(jù)被寫入硬盤,就不可再修改;段被寫入到磁盤后會生成一個提交點,提交點是一個用來記錄所有提交后段信息的文件
段的特性,有下面幾個有點
-
分段存儲,可以有效避免讀寫時加鎖的問題
-
不變性,數(shù)據(jù)只讀可以高效緩存,無需考慮更新
-
一個段一旦擁有了提交點,就說明這個段只有讀的權(quán)限,失去了寫的權(quán)限。相反,當(dāng)段在內(nèi)存中時,就只有寫的權(quán)限,而不具備讀數(shù)據(jù)的權(quán)限,意味著不能被檢索
由于段不可變,所以在更新時需要額外處理
-
新增:當(dāng)前文檔新增一個段
-
刪除:新增一個.del文件,記錄被刪除的文檔信息;被標(biāo)記刪除的文檔仍然可以被檢索到,只是最終返回時被移除
-
更新:刪除文件中標(biāo)記舊的文檔刪除,插入新的段
延遲寫
ES并不會實時將內(nèi)存中的數(shù)據(jù)寫入段,而是采用延遲寫的策略(類似前面的寫buffer,然后異步定時刷盤)
es先將內(nèi)存數(shù)據(jù),寫入文件緩存系統(tǒng)(操作系統(tǒng)內(nèi)存),
注意幾個事項
-
寫入文件緩存系統(tǒng),之后異步落盤,可能導(dǎo)致丟數(shù)據(jù),es采用事務(wù)日志的方式來處理恢復(fù)策略(即mysql的先寫日志,崩潰之后做回放恢復(fù))
-
es對外服務(wù)時,檢索文件緩存系統(tǒng) + 段中的文檔,而內(nèi)存中的數(shù)據(jù)不會被檢索到(所以所es是近實時搜索引擎,因為最新寫入的數(shù)據(jù)還在內(nèi)存中,沒有提交,立馬查就查不到)
-
為了避免段過多,es會定時做合并,將很多小的段合并成大的段(合并過程中會自動移除被標(biāo)記刪除的文檔)
最后小結(jié)一下 es 的持久化
-
索引分段存儲,段生成 checkpoint 之后,則只讀,因此可以全量緩存,不用考慮更新修改
-
延遲寫策略:先更新內(nèi)存數(shù)據(jù),異步提交文件緩存系統(tǒng),最后再由操作系統(tǒng)刷盤
內(nèi)存中的數(shù)據(jù)不能被檢索;文件緩存 + 段中的數(shù)據(jù)提供查詢聚合,最終的結(jié)果會過濾已標(biāo)記刪除的文檔
4.5 小結(jié)
這一小節(jié)主要介紹的是ES的高可用機制,包括ES的集群工作原理,選舉策略;采用數(shù)據(jù)分片支持大數(shù)據(jù)場景的支持,借助副本來提高可用性;
ES原生支持集群
-
角色劃分:候選主節(jié)點 + 數(shù)據(jù)節(jié)點
-
數(shù)據(jù)節(jié)點:負(fù)責(zé)數(shù)據(jù)的存儲和相關(guān)的操作(CURD,聚合)等,因此對機器性能要求較高
-
候選主節(jié)點:擁有選舉權(quán)和被選舉權(quán),主節(jié)點在候選主節(jié)點中評選出來,負(fù)責(zé)創(chuàng)建索引、刪除索引、跟蹤哪些節(jié)點是群集的一部分,并決定哪些分片分配給哪些的節(jié)點、追蹤集群中節(jié)點的狀態(tài)等
ES數(shù)據(jù)持久化策略
-
索引分段存儲,段生成checkpoint之后,則只讀,因此可以全量緩存,不用考慮更新修改;當(dāng)出現(xiàn)修改時,標(biāo)記原來段中文檔刪除,在新的段寫入數(shù)據(jù)
-
延遲寫策略:先更新內(nèi)存數(shù)據(jù),異步提交文件緩存系統(tǒng),最后再由操作系統(tǒng)刷盤
-
內(nèi)存中的數(shù)據(jù)不能被檢索;文件緩存 + 段中的數(shù)據(jù)提供查詢聚合,最終的結(jié)果會過濾已標(biāo)記刪除的文檔
5.總結(jié)
5.1 綜述
本片文章主要是分析當(dāng)下不同應(yīng)用場景下的幾個主流系統(tǒng)的高可用策略,來看一下如何來保障的系統(tǒng)的高可用
常見的高可用思路
-
冗余 (如數(shù)據(jù)副本、主備服務(wù)等)
-
拆分 (數(shù)據(jù)拆分、服務(wù)能力拆分等)
-
持久化
redis
-
持久化:RDB數(shù)據(jù)落盤加載方式 + AOF記錄操作命令用于回放策略
-
主從,主從從:全量數(shù)據(jù)冗余、讀寫請求分離,負(fù)載均衡的思想;核心問題在于主節(jié)點掛掉之后需要人工參與手動指定主庫
-
哨兵機制:PING/PONG的探活機制,監(jiān)聽主節(jié)點,宕機之后自動選主,確保高可用;核心問題在于所有的實例冗余相同的一份數(shù)據(jù),數(shù)據(jù)量大時不友好
-
集群:數(shù)據(jù)分片,每個實例提供部分服務(wù)能力
mysql
-
通過冗余來實現(xiàn)高可用:如主備
-
讀寫分離,實現(xiàn)負(fù)載均衡:主從、主從從模式
-
數(shù)據(jù)持久化策略:操作內(nèi)存(buffer),異步刷盤,兩階段提交保障一致性
rabbitmq
-
主備模式
-
鏡像模式:全量冗余一份數(shù)據(jù),主對外提供服務(wù),可以實現(xiàn)自動切主
-
普通集群模式:數(shù)據(jù)拆分到集群的實例中,consumer/publisher連接到實例之后,會從具體持有exchange/topic的實例上拉數(shù)據(jù)
-
遠(yuǎn)程模式:適用于多中心的場景,將消息轉(zhuǎn)發(fā)給其他中心的實例
ElasticSearch
-
ES集群:數(shù)據(jù)節(jié)點 + 候選主節(jié)點
-
ES持久化:
-
延遲寫策略,先更新內(nèi)存,然后提交操作系統(tǒng)緩存,最后異步刷新到磁盤;
-
索引分段存儲:段生成checkpoint之后,則只讀,因此可以全量緩存,不用考慮更新修改;當(dāng)出現(xiàn)修改時,標(biāo)記原來段中文檔刪除,在新的段寫入數(shù)據(jù)
-
?
?
?
到了這里,關(guān)于基于MySql,Redis,Mq,ES的高可用方案解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!