分布式系統(tǒng)面試全集通第一篇
什么是分布式?和微服務(wù)的區(qū)別
什么是分布式
- 一個系統(tǒng)各組件分別部署在不同服務(wù)器。彼此通過網(wǎng)絡(luò)通信和協(xié)調(diào)的系統(tǒng)。
- 也可以指多個不同組件分布在網(wǎng)絡(luò)上互相協(xié)作,比如說電商網(wǎng)站
- 也可以一個組件的多個副本組成集群,互相協(xié)作如同一個組件,比如數(shù)據(jù)存儲服務(wù)中為了數(shù)據(jù)不丟失而采取的多個服務(wù)備份冗余,當(dāng)數(shù)據(jù)修改時也需要通信來復(fù)制數(shù)據(jù)
- 分布式最早出現(xiàn)的目地首先是解決單點(diǎn)問題,避免單點(diǎn)故障,然后解決了性能問題
分布式與微服務(wù)的區(qū)別
分布式和微服的架構(gòu)很相似,只是部署的方式不一樣而已。
- 分布式服務(wù)架構(gòu)與微服務(wù)架構(gòu)概念的區(qū)別與聯(lián)系:
- 分布式:分散壓力。
不同模塊部署在不同服務(wù)器上;
作用:分布式解決網(wǎng)站高并發(fā)帶來問題;
集群:相同的服務(wù);
多臺服務(wù)器部署相同應(yīng)用構(gòu)成一個集群;
作用:通過負(fù)載均衡設(shè)備共同對外提供服務(wù);
業(yè)務(wù)系統(tǒng)分解為多個組件,讓每個組件都獨(dú)立提供離散,自治,可復(fù)用的服務(wù)能力;
通過服務(wù)的組合和編排來實(shí)現(xiàn)上層的業(yè)務(wù)流程;
作用:簡化維護(hù),降低整體風(fēng)險(xiǎn),伸縮靈活; - 微服務(wù):分散能力。
微服務(wù)[找到服務(wù)/微服務(wù)網(wǎng)關(guān)open API];
架構(gòu)設(shè)計(jì)概念:各服務(wù)間隔離(分布式也是隔離),自治(分布式依賴整體組合),其它特性(單一職責(zé),邊界,異步通信,獨(dú)立部署)
是分布式概念更加嚴(yán)格的執(zhí)行;
SOA到微服務(wù)架構(gòu)的演進(jìn)過程;
作用:各服務(wù)可獨(dú)立應(yīng)用,組合服務(wù)也可系統(tǒng)應(yīng)用(巨石應(yīng)用[monolith]的簡化實(shí)現(xiàn)策略-平臺思想).
- 分布式:分散壓力。
- 明確一個問題:分布式主要針對是部署方式,微服務(wù)則是將應(yīng)用才分的一種應(yīng)用架構(gòu)
什么是CAP?為什么不能三者同時擁有
在設(shè)計(jì)一個分布式項(xiàng)目的時候會遇到三個特性:
- 一致性(consistency)
- 可用性(Availability)
- 分區(qū)容錯(partition-tolerance)都需要的情景
輸入/喚起更
CAP定律說的是在一個分布式計(jì)算機(jī)系統(tǒng)中,一致性,可用性和分區(qū)容錯性這三種保證無法同時得到滿足,最多滿足兩個。
分區(qū)容錯性
- 分區(qū)容錯性指“the system continues to operate despite arbitrary message loss or failure of part of the system即分布式系統(tǒng)在遇到某節(jié)點(diǎn)或網(wǎng)絡(luò)分區(qū)故障的時候,仍然能夠?qū)ν馓峁┓?wù)。
- 分布式系統(tǒng)中,盡管部分節(jié)點(diǎn)出現(xiàn)任何消息丟失或者故障,系統(tǒng)應(yīng)繼續(xù)運(yùn)行
- 通常分布式系統(tǒng)的各各結(jié)點(diǎn)部署在不同的子網(wǎng),這就是網(wǎng)絡(luò)分區(qū),不可避免的會出現(xiàn)由于網(wǎng)絡(luò)問題而導(dǎo)致結(jié)點(diǎn)之間通信失敗,此時仍可對外提供服務(wù)。
一致性
- 一致性指"all nodes see the same data at the same即更新操作成功并返回客戶端time完成后,所有節(jié)點(diǎn)在同時間的數(shù)據(jù)完全一致。
- 一旦數(shù)據(jù)更新完成并成功返回客戶端后,那么分布式系統(tǒng)中所有節(jié)點(diǎn)在同一時間的數(shù)據(jù)完全一致。
- 一致性是指寫操作后的讀操作可以讀取到最新的數(shù)據(jù)狀態(tài),當(dāng)數(shù)據(jù)分布在多個節(jié)點(diǎn)上,從任意結(jié)點(diǎn)讀取到的數(shù)據(jù)都是最新的狀態(tài)。
可用性
- 可用性指即服務(wù)一直可用,而且是正常響應(yīng)時間?!癛eads and writes always succeed”
對于可用性的衡量標(biāo)準(zhǔn)如下:
Base理論了解嗎
BASE(Basically Available、Soft state、Eventual consistency)是基于CAP理論逐步演化而來的,核心思想是即便不能達(dá)到強(qiáng)一致性(Strong consistency),也可以根據(jù)應(yīng)用特點(diǎn)采用適當(dāng)?shù)姆绞絹磉_(dá)到最終致性(Eventual consistency)的效果。
基本可用
基本可用本質(zhì)是一種妥協(xié),也就是出現(xiàn)節(jié)點(diǎn)故障或者系統(tǒng)過載時,通過犧牲非核心功能的可用性,保障核心功能的穩(wěn)定運(yùn)行。
實(shí)現(xiàn)基本可用的幾個策略:
- 1、流量削峰(不同地區(qū)售票時間錯峰出售)
以訂票系統(tǒng)設(shè)計(jì)為例,在春運(yùn)期間,開始售票前后會出現(xiàn)及其海量的請求峰值。
可以在不同的時間,出售不同區(qū)域的票,將訪問請求錯開,削弱請求峰值。 - 2、延遲響應(yīng),異步處理(買票排隊(duì),基于隊(duì)列先收到用戶買票請求,排隊(duì)異步處理,延遲響應(yīng))還以訂票系統(tǒng)為例。用戶提交購票請求后,往往會在隊(duì)列中排隊(duì)等待處理,可能幾分鐘或十幾分鐘后,系統(tǒng)才開始處理,然后響應(yīng)處理結(jié)果。
- 3、體驗(yàn)降級(看到非實(shí)時數(shù)據(jù),采用緩存數(shù)據(jù)提供服務(wù))以互聯(lián)網(wǎng)系統(tǒng)為例,若出現(xiàn)網(wǎng)絡(luò)熱點(diǎn)事件,產(chǎn)生了海量的突發(fā)流量,系統(tǒng)過載,大量圖片因?yàn)榫W(wǎng)絡(luò)超時無法顯示那么可以用小圖片代替原始圖片,降低圖片的清晰度和大小,提升系統(tǒng)處理能力。
- 4、過載保護(hù)熔斷/限流,直接拒絕掉一部分請求,或者當(dāng)請求隊(duì)列滿了,移除一部分請求,保證整體系統(tǒng)可用)把接收到的請求放在指定的隊(duì)列中排隊(duì)處理,如果請求等待時間超時,這時直接拒絕超時請求;如果隊(duì)列滿了之后,就清除隊(duì)列中一定數(shù)量的排隊(duì)請求,保護(hù)系統(tǒng)不過載,實(shí)現(xiàn)系統(tǒng)基本可用。
- 5、故障隔離(出現(xiàn)故障,做到故障隔離,避免影響其他服務(wù))
軟狀態(tài)
軟狀態(tài)(弱狀態(tài))->允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認(rèn)為該狀態(tài)不影響系統(tǒng)的整體可用性,即允許系統(tǒng)在多個不同節(jié)點(diǎn)的數(shù)據(jù)副本存在數(shù)據(jù)延遲。
最終一致性
上面說軟狀態(tài),然后不可能一直是軟狀態(tài),必須有個時間期限。在期限過后,應(yīng)當(dāng)保證所有副本保持?jǐn)?shù)據(jù)一致性。
從而達(dá)到數(shù)據(jù)的最終一致性。這個時間期限取決于網(wǎng)絡(luò)延時,系統(tǒng)負(fù)載,數(shù)據(jù)復(fù)制方案設(shè)計(jì)等等因素。
什么是分布式事務(wù)
分布式事務(wù)是相對本地事務(wù)而言的,對于本地事務(wù),利用數(shù)據(jù)庫本身的事務(wù)機(jī)制,就可以保證事務(wù)的ACID
特性。
分布式事務(wù)有哪些常見的實(shí)現(xiàn)方案?
到現(xiàn)在,分布式事務(wù)已經(jīng)有很多的解決方案了,有2PC、3PC、TCC,這一篇博客,我們先來分別講講最早的2PC、3PC這兩種解決方案的模型及理論基礎(chǔ),以后再豐富其他的分布式事務(wù)解決方案。
2PC(Two Phase Commit)
第一階段:執(zhí)行事務(wù)操作
- 事務(wù)詢問。
協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)詢問是否可以執(zhí)行提交操作,并開始等待各參與者節(jié)點(diǎn)的響應(yīng)。 - 執(zhí)行事務(wù)。
參與者節(jié)點(diǎn)執(zhí)行詢問發(fā)起的所有事務(wù)操作,并將Undo信息和Redo信息寫入數(shù)據(jù)庫日志。(若操作成功,這里其實(shí)每個參與者已經(jīng)執(zhí)行了事務(wù)操作) - 各參與者向協(xié)調(diào)者反饋事務(wù)詢問的響應(yīng)。
各參與者節(jié)點(diǎn)響應(yīng)協(xié)調(diào)者節(jié)點(diǎn)發(fā)起的詢問。如果參與者節(jié)點(diǎn)的事務(wù)操作實(shí)際執(zhí)行成功,則反饋一個“同意”消息;如果執(zhí)行失敗,則反饋一個“中止”消息。
第二階段:執(zhí)行事務(wù)提交
當(dāng)所有參與者節(jié)點(diǎn)在第一階段向協(xié)調(diào)者節(jié)點(diǎn)反饋的消息全都是“同意”時:
- 發(fā)送事務(wù)提交請求
協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)發(fā)出“正式提交(commit)”請求。 - 事務(wù)正式提交
參與者節(jié)點(diǎn)正式完成提交操作,并釋放在整個事務(wù)期間占用的資源。 - 反饋事務(wù)提交結(jié)果
參與者節(jié)點(diǎn)向協(xié)調(diào)者節(jié)點(diǎn)發(fā)送“完成”消息。 - 完成事務(wù)
協(xié)調(diào)者節(jié)點(diǎn)收到所有參與者節(jié)點(diǎn)反饋的“完成”消息后,完成分布式事務(wù)。
當(dāng)任一參與者節(jié)點(diǎn)在第一階段反饋的響應(yīng)為“中止”,或者協(xié)調(diào)者在第一階段接收反饋信息超時:
發(fā)送事務(wù)回滾請求
協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)發(fā)出“回滾操作(rollback)”請求。
- 事務(wù)回滾
各參與者節(jié)點(diǎn)收到請求,利用之前寫入的Undo信息執(zhí)行本地事務(wù)回滾操作,并釋放在整個事務(wù)期間占用的資源。 - 反饋事務(wù)回滾結(jié)果
參與者節(jié)點(diǎn)向協(xié)調(diào)者節(jié)點(diǎn)發(fā)送“回滾完成”消息。 - 中斷事務(wù)
協(xié)調(diào)者節(jié)點(diǎn)收到所有參與者節(jié)點(diǎn)反饋的“回滾完成”消息后,取消事務(wù)。
3PC(Three Phase Commit)
3PC沒有解決2PC所有問題,只是降低了災(zāi)難的發(fā)生概率。只是在2PC基礎(chǔ)上,多一個詢問
TCC(Try Commit Cancel)
這個模型有兩個個階段,但是與2PC的三個階段又有所不同。
第一階段:執(zhí)行Try操作
- 事務(wù)發(fā)起。
協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)發(fā)起執(zhí)行業(yè)務(wù)邏輯包含數(shù)據(jù)操作的命令,并開始等待各參與者節(jié)點(diǎn)的響應(yīng)。 - 執(zhí)行數(shù)據(jù)操作。
直接對數(shù)據(jù)庫的數(shù)據(jù)執(zhí)行操作。 - 各參與者向協(xié)調(diào)者反饋執(zhí)行操作的響應(yīng)。
各參與者節(jié)點(diǎn)響應(yīng)協(xié)調(diào)者節(jié)點(diǎn)發(fā)起的數(shù)據(jù)操作。如果參與者節(jié)點(diǎn)的數(shù)據(jù)操作實(shí)際執(zhí)行成功,則反饋一個“同意”消息;如果有一個參與者執(zhí)行失敗,則反饋一個“中止”消息。
第二階段:執(zhí)行Confirm/Cancel操作
根據(jù)階段一各事務(wù)參與者的響應(yīng),如果所有事務(wù)參與者在階段一執(zhí)行成功,那就執(zhí)行Confirm操作,有一個事務(wù)參與者在階段一執(zhí)行失敗,就執(zhí)行Cancel操作,進(jìn)行數(shù)據(jù)庫數(shù)據(jù)恢復(fù)。
Confirm 操作用于執(zhí)行數(shù)據(jù)操作成功之后的業(yè)務(wù)邏輯。
Cancel 操作用于恢復(fù)階段一對數(shù)據(jù)的操作。
2PC、3PC、TCC區(qū)別
1.在2PC的第一階段基礎(chǔ)之上,3PC新加了一個準(zhǔn)備階段(上圖所示),用于詢問所有參與者節(jié)點(diǎn)是否已經(jīng)準(zhǔn)備好要進(jìn)行分布式事務(wù)操作了,這一階段沒有對資源的占用,只是測試數(shù)據(jù)庫是否能獲取鎖即可,只是保證所有參與者都有能力參與事務(wù),如果有網(wǎng)絡(luò)或者其他問題就不用進(jìn)行第二、三階段了。
2. 在3PC的所有階段,都為所有參與者節(jié)點(diǎn)和協(xié)調(diào)者節(jié)點(diǎn)添加了超時機(jī)制,防止因某一節(jié)點(diǎn)宕機(jī)造成的資源無法釋放問題。
3. 2PC中所有階段,只對協(xié)調(diào)者節(jié)點(diǎn)添加了超時機(jī)制。
4. TCC模型主要是在應(yīng)用層做的一個分布式事務(wù),2PC和3PC則是在數(shù)據(jù)庫層做的分布式事務(wù)。
5。 TCC模型可以用于不支持事務(wù)的數(shù)據(jù)庫,但是2PC和3PC要求數(shù)據(jù)庫必須支持事務(wù)。
2PC存在問題
2PC只對協(xié)調(diào)者節(jié)點(diǎn)添加了超時機(jī)制,如果協(xié)調(diào)者這一重要角色宕機(jī),所有參與者的資源就會一直得不到釋放,降低系統(tǒng)的可用性。
2PC中,當(dāng)其中任一節(jié)點(diǎn)宕機(jī)情況出現(xiàn)時,不能保證數(shù)據(jù)的最終一致性。
TCC存在問題
代碼編寫難度高
每個參與者的業(yè)務(wù)都要寫try、confirm、cancel三個操作,并且各個操作的業(yè)務(wù)都有所不同
為滿足一致性,要滿足try、canfirm、cancel三個操作的冪等。
對于冪等性,可參考文章【分布式事務(wù)講解 - Seata分布式事務(wù)框架(AT、TCC兩種模式)】
TCC的優(yōu)點(diǎn)
TCC的優(yōu)點(diǎn)全是因?yàn)閷?shí)現(xiàn)了應(yīng)用層的分布式事務(wù),優(yōu)點(diǎn)如下:
可以降低數(shù)據(jù)庫鎖沖突,提高吞吐量。
可以通過應(yīng)用控制數(shù)據(jù)庫鎖的粒度,而不用像2PC和3PC使數(shù)據(jù)庫阻塞等待。
可以通過部署集群解決單點(diǎn)故障。
對比2PC,3PC有什么優(yōu)點(diǎn)
為所有參與者節(jié)點(diǎn)和協(xié)調(diào)者節(jié)點(diǎn)添加了超時機(jī)制:
1)如果協(xié)調(diào)者等待參與者反饋信息超時,直接給所有參與者發(fā)送中斷分布式事務(wù)請求。
2)如果在第三階段任一參與者等待協(xié)調(diào)者提交事務(wù)信息超時,那就默認(rèn)提交事務(wù)
添加超時機(jī)制,可以防止因某一節(jié)點(diǎn)宕機(jī)造成的資源無法釋放問題以及資源占用時間過長問題。
在第一階段,不鎖定資源,就好像在Synchronized外面加了個if條件,能降低分布式事務(wù)執(zhí)行失敗率。
有哪些分布式鎖的實(shí)現(xiàn)方案?
一、 分布式鎖場景
般需要使用分布式鎖的場景如下:
效率:使用分布式鎖可以避免不同節(jié)點(diǎn)重復(fù)相同的工作,比如避免重復(fù)執(zhí)行定時任務(wù)等;正確性:使用分布式鎖同樣可以避免破壞數(shù)據(jù)正確性,如果兩個節(jié)點(diǎn)在同一條數(shù)據(jù)上面操作,可能會出現(xiàn)并發(fā)問題。
二、分布式鎖特點(diǎn)
一個完善的分布式鎖需要滿足以下特點(diǎn):
·互斥性:互斥是所得基本特性,分布式鎖需要按需求保證線程或節(jié)點(diǎn)級別的互斥?!た芍厝胄?同一個節(jié)點(diǎn)或同一個線程獲取鎖,可以再次重入獲取這個鎖;
·鎖超時:支持鎖超時釋放,防止某個節(jié)點(diǎn)不可用后,持有的鎖無法釋放;
高效性:加鎖和解鎖的效率高,可以支持高并發(fā)
·高可用:需要有高可用機(jī)制預(yù)防鎖服務(wù)不可用的情況,如增加降級;
阻塞性:支持阻塞獲取鎖和非阻塞獲取鎖兩種方式;
·公平性:支持公平鎖和非公平鎖兩種類型的鎖,公平鎖可以保證安裝請求鎖的順序獲取鎖,而非公平鎖
基于緩存實(shí)現(xiàn)分布式鎖,以Redis為例
加鎖
public class RedisTool {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
/**
* 加鎖
* @param stringRedisTemplate Redis客戶端
* @param lockKey 鎖的key
* @param requestId 競爭者id
* @param expireTime 鎖超時時間,超時之后鎖自動釋放
* @return
*/
public static boolean getDistributedLock(StringRedisTemplate stringRedisTemplate, String lockKey, String requestId, int expireTime) {
return stringRedisTemplate.opsForValue().setIfAbsent(lockKey, requestId, 30, TimeUnit.SECONDS);
}
}
這個setIfAbsent()方法一共五個形參:
第一個為key,我們使用key來當(dāng)鎖,因?yàn)閗ey是唯一的。
第二個為value,這里寫的是鎖競爭者的id,在解鎖時,我們需要判斷當(dāng)前解鎖的競爭者id是否為鎖持有者。
第三個為expx,這個參數(shù)我們傳的是PX,意思是我們要給這個key加一個過期時間的設(shè)置,具體時間由第五個參數(shù)決定;
第四個參數(shù)為time,與第四個參數(shù)相呼應(yīng),代表key的過期時間。
總的來說,執(zhí)行上面的setIfAbsent()方法就只會導(dǎo)致兩種結(jié)果:
1.當(dāng)前沒有鎖(key不存在),那么就進(jìn)行加鎖操作,并對鎖設(shè)置一個有效期,同時value表示加鎖的客戶端。
2.已經(jīng)有鎖存在,不做任何操作。上述解鎖請求中,緩存超時機(jī)制保證了即使一個競爭者加鎖之后掛了,也不會產(chǎn)生死鎖問題:超時之后其他競爭者依然可以獲取鎖。通過設(shè)置value為競爭者的id,保證了只有鎖的持有者才能來解鎖,否則任何競爭者都能解鎖,那豈不是亂套了。
解鎖
public class RedisTool {
private static final Long RELEASE_SUCCESS = 1L;
/**
* 釋放分布式鎖
* @param stringRedisTemplate Redis客戶端
* @param lockKey 鎖
* @param requestId 鎖持有者id
* @return 是否釋放成功
*/
public static boolean releaseDistributedLock(StringRedisTemplate stringRedisTemplate, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Long result = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Collections.singletonList(lockKey), requestId);
return RELEASE_SUCCESS.equals(result);
}
}
解鎖的步驟:
1、判斷當(dāng)前解鎖的競爭者id是否為鎖的持有者,如果不是直接返回失敗,如果是則進(jìn)入第2步。
2、刪除key,如果刪除成功,返回解鎖成功,否則解鎖失敗。
注意到這里解鎖其實(shí)是分為2個步驟,涉及到解鎖操作的一個原子性操作問題。這也是為什么我們解鎖的時候用Lua腳本來實(shí)現(xiàn),因?yàn)長ua腳本可以保證操作的原子性。那么這里為什么需要保證這兩個步驟的操作是原子操作呢?
設(shè)想:假設(shè)當(dāng)前鎖的持有者是競爭者1,競爭者1來解鎖,成功執(zhí)行第1步,判斷自己就是鎖持有者,這是還未執(zhí)行第2步。這是鎖過期了,然后競爭者2對這個key進(jìn)行了加鎖。加鎖完成后,競爭者1又來執(zhí)行第2步,此時錯誤產(chǎn)生了:競爭者1解鎖了不屬于自己持有的鎖??赡軙腥藛枮槭裁锤偁幷?執(zhí)行完第1步之后突然停止了呢?這個問題其實(shí)很好回答,例如競爭者1所在的JVM發(fā)生了GC停頓,導(dǎo)致競爭者1的線程停頓。這樣的情況發(fā)生的概率很低,但是請記住即使只有萬分之一的概率,在線上環(huán)境中完全可能發(fā)生。因此必須保證這兩個步驟的操作是原子操作。
分析
是否可重入:以上實(shí)現(xiàn)的鎖是不可重入的,如果需要實(shí)現(xiàn)可重入,在SET_IF_NOT_EXIST之后,再判斷key對應(yīng)的value是否為當(dāng)前競爭者id,如果是返回加鎖成功,否則失敗。
鎖釋放時機(jī):加鎖時我們設(shè)置了key的超時,當(dāng)超時后,如果還未解鎖,則自動刪除key達(dá)到解鎖的目的。如果一個競爭者獲取鎖之后掛了,我們的鎖服務(wù)最多也就在超時時間的這段時間之內(nèi)不可用。
Redis單點(diǎn)問題:如果需要保證鎖服務(wù)的高可用,可以對Redis做高可用方案:Redis集群+主從切換。目前都有比較成熟的解決方案。文章來源:http://www.zghlxwxcb.cn/news/detail-847169.html
感謝閱讀
感謝您閱讀本篇分布式系統(tǒng)面試博客分享!如果您有任何問題或建議,請隨時在評論中告訴我們。謝謝!文章來源地址http://www.zghlxwxcb.cn/news/detail-847169.html
到了這里,關(guān)于分布式系統(tǒng)面試全集通第一篇(dubbo+redis+zookeeper----分布式+CAP+BASE+分布式事務(wù)+分布式鎖)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!