- 微服务架构
>> 微服務(wù)架構(gòu)基礎(chǔ)
~ 微服務(wù)概念
微服務(wù)架構(gòu)是一種架構(gòu)概念,旨在通過將功能分解到各個離散的服務(wù)中,以實現(xiàn)對解決方案的解耦;它的主要作用是將功能分解離散到各個服務(wù)中,從而降低系統(tǒng)的耦合性,并添加更靈活的服務(wù)支持;
把一個大型的單體應(yīng)用和服務(wù)拆分成數(shù)個微服務(wù);
~ 微服務(wù)架構(gòu)與傳統(tǒng)架構(gòu)的區(qū)別
1、系統(tǒng)架構(gòu)需要遵循3個標(biāo)準(zhǔn):
- 提高敏捷性:及時響應(yīng)業(yè)務(wù)需求;
- 提升用戶體驗:減少用戶流失;
- 降低成本:降低增加產(chǎn)品、客戶、業(yè)務(wù)方案的成本;
2、傳統(tǒng)式開發(fā)(單體式開發(fā)):將所有的功能打包在一個war包里,基本沒有外部依賴(除了容器),部署在一個JavaEE容器(Tomcat、JBoss、Weblogic)里面,包含MVC的所有邏輯;
優(yōu)點:
- 開發(fā)簡單,集中式管理;
- 基本不會重復(fù)開發(fā);
- 功能都在本地(整個應(yīng)用程序部署在一臺服務(wù)器),沒有分布式的管理和調(diào)用的消耗;
缺點:
- 效率低:開發(fā)都在同一個項目里改代碼,相互等待,沖突不斷;
- 維護難:代碼功能耦合在一起;
- 不靈活:構(gòu)建時間長,任何小修改都要重構(gòu)整個項目,耗時間;
- 穩(wěn)定性差:一個微小的問題都可能導(dǎo)致整個應(yīng)用掛掉;
- 擴展性不夠:無法滿足高并發(fā)下的業(yè)務(wù)需求;
3、微服務(wù)架構(gòu):有效的拆分應(yīng)用,將應(yīng)用拆分成多個微服務(wù),實現(xiàn)敏捷開發(fā)和部署;
微服務(wù)特征:
- 一系列的獨立的服務(wù)共同組成系統(tǒng);
- 單獨部署;
- 每個服務(wù)為獨立的業(yè)務(wù)開發(fā);
- 分布式管理;
- 非常強調(diào)隔離性;
>> 微服務(wù)實戰(zhàn) - 怎么實現(xiàn)微服務(wù)
要實際的應(yīng)用微服務(wù),需要解決一下問題:
- 客戶端如何訪問這些服務(wù);
- 每個服務(wù)之間如何通信;
- 如此多的服務(wù),怎么實現(xiàn);
- 服務(wù)掛了,怎么解決;(備份方案,應(yīng)急處理機制)
1、客戶端如何訪問這些服務(wù)
通過API網(wǎng)關(guān)的模式來訪問
傳統(tǒng)的單體開發(fā),所有的服務(wù)都是在本地的,UI可以直接調(diào)用;現(xiàn)在按照功能拆分成獨立的服務(wù),每個服務(wù)都跑在獨立的虛擬機上的Java進程里;UI要怎么去訪問服務(wù)?
一個服務(wù),一個應(yīng)用,一個容器;每個服務(wù)都是一個獨立的計算機,這就表示每個計算機都有一個獨立的IP和端口;
后臺有N個服務(wù),前臺就要去記住管理N個服務(wù);用戶去訪問UI,UI去管理這么多服務(wù),怎么管理是個問題;一個服務(wù)下線、更新、升級,前臺就要重新部署;這不符合拆分的理念,特別是前臺是移動應(yīng)用的時候:PC訪問的話,后臺服務(wù)變了,把JSP頁面改改,重啟服務(wù),重新部署一下,用戶再次訪問PC的時候,就自動變了;移動應(yīng)用訪問的話,后臺服務(wù)變了,就得下載新的安裝包,麻煩;
一般微服務(wù)在系統(tǒng)的內(nèi)部,通常是無狀態(tài)的,也就是說各個微服務(wù)之間的互相調(diào)用是無狀態(tài)的,不知道是誰在調(diào)用;用戶登錄信息和權(quán)限管理最好有一個統(tǒng)一的地方維護管理(OAuth),這樣就不用在每個服務(wù)都登錄一次;當(dāng)用戶去訪問UI的時候,都應(yīng)該去訪問OAuth服務(wù)器(授權(quán)服務(wù)器),OAuth再去訪問服務(wù);這樣就由OAuth服務(wù)器統(tǒng)一管理后面微服務(wù)的授權(quán)(用戶的登錄狀態(tài));
無狀態(tài):Http的請求時無狀態(tài)的,不會記錄是誰來請求的;web應(yīng)用為了實現(xiàn)有狀態(tài)的效果,才有了會話,用session來記錄狀態(tài),而http請求本身是無狀態(tài)的;
一般在后臺N個服務(wù)和UI之間會有一個API Gateway,由網(wǎng)關(guān)實現(xiàn)OAuth的功能,它的作用包括:
- 提供統(tǒng)一的服務(wù)入口,讓服務(wù)對前臺透明;
- 聚合后臺的服務(wù),節(jié)省流量,提升性能;
- 提供安全,過濾,流量控制等API管理功能;
既然微服務(wù)內(nèi)部是無狀態(tài)的,我們就需要有一個東西讓它有狀態(tài),這個東西就是授權(quán)服務(wù)器,這個東西又稱為SSO(單點登錄);
單點登錄:單點就是一個點(一個地方),在一個地方登錄了,就相當(dāng)于在所有地方登錄了;
用戶訪問UI,UI訪問API網(wǎng)關(guān),API網(wǎng)關(guān)也是一個服務(wù),這個服務(wù)去聚合后面的微服務(wù);API網(wǎng)關(guān)又相當(dāng)于后面服務(wù)的防火墻,因為API一個服務(wù),把后面整個隔離了,所有安全的東西都可以在API網(wǎng)關(guān)這里來做;
不使用API網(wǎng)關(guān)的時候,UI的PC端需要記錄所有后臺服務(wù)的IP地址和端口,移動應(yīng)用也需要記錄一份IP地址,這時候如果后臺有一個服務(wù)的IP改了一下,PC端在后臺改一下代碼配置就可以了,但是移動應(yīng)用就需要更新一個整個的安裝包,就為了后臺服務(wù)改了一個IP,不現(xiàn)實;
有了API網(wǎng)關(guān),解決了這個問題;UI的PC和移動應(yīng)用上只需要記錄一個API網(wǎng)關(guān)的地址,后臺服務(wù)的IP地址由API網(wǎng)關(guān)來管理,只要API網(wǎng)關(guān)的地址不變,后臺服務(wù)的IP隨便怎么改,怎么增加,怎么減少都無所謂,因為只需要修改API網(wǎng)關(guān)管理的服務(wù)IP列表即可;這時候安卓端的每次后臺修改就要更新整個安裝包的尷尬問題就沒有了;
用戶訪問某個服務(wù)的時候,只需要通過UI去訪問API網(wǎng)關(guān),然后由網(wǎng)關(guān)去調(diào)用不同的服務(wù);
API網(wǎng)關(guān)有很多實現(xiàn)辦法,可以是一個軟硬一體的盒子,可以是一個簡單的MVC框架,可以是一個Node.js的服務(wù)端;它最重要的作用是為UI提供后臺服務(wù)的聚合,提供統(tǒng)一的服務(wù)出口,解除它們之間的耦合;但是API網(wǎng)關(guān)可能成為單點故障,或性能的瓶頸;
單點故障:網(wǎng)關(guān)掛掉了,所有后臺服務(wù)都不能訪問了,即使后臺服務(wù)都能正常運行;
性能瓶頸:API網(wǎng)關(guān)只有一個服務(wù)器,所有流量都要經(jīng)由這個網(wǎng)關(guān)服務(wù)器,然后由它分發(fā)到后臺服務(wù)上面去;
2、每個服務(wù)之間如何通信
所有的微服務(wù)都是獨立的Java進程運行在獨立的虛擬機/容器上,所以服務(wù)間的通信就是IPC(Inter Process Communication 進程間通信);
解決服務(wù)間通信,有兩種方案:
(1)同步調(diào)用:
- REST(Spring Boot、SpringMVC):就是Http通信;
- RPC(Thrift,Dubbo):遠(yuǎn)程過程調(diào)用;使用的時候就和調(diào)用本地應(yīng)用一樣;
對外REST,對內(nèi)RPC;
對內(nèi)RPC因為RPC在內(nèi)網(wǎng)中調(diào)用的速度非常快;而對外REST是因為有防火墻,防火墻只能接收字符串,REST提供的是json格式數(shù)據(jù),這個格式是由字符串組成的;網(wǎng)絡(luò)中只有字符串可以穿透防火墻,RPC是遠(yuǎn)程過程調(diào)用,是穿透不了防火墻的;
同步調(diào)用比較簡單,一致性強,但是容易出現(xiàn)調(diào)用問題: 同步調(diào)用會出現(xiàn)阻塞,出現(xiàn)阻塞就會出現(xiàn)單點故障; 性能體驗也會差一些,特別是調(diào)用層次多的時候;
一般REST基于HTTP,更容易實現(xiàn),服務(wù)端的實現(xiàn)技術(shù)也更靈活些,各種語言都支持,同時也能跨客戶端,對客戶端沒有特殊的要求,只要支持HTTP請求,就能拿到字符串,拿到字符串就能在自己的程序里想怎么樣就怎么樣;
(2)異步消息調(diào)用:
- kafka
- Notify
- MessageQueue
異步消息的方式在分布式系統(tǒng)中有特別廣泛的應(yīng)用,它既能降低調(diào)用服務(wù)之間的耦合,又能成為調(diào)用之間的緩沖,確保消息積壓不會沖垮被調(diào)用方,同時能保證調(diào)用方的服務(wù)體驗,繼續(xù)干自己該干的活,不至于被后臺性能拖慢;不過需要付出的代價是一致性的減弱,需要接受數(shù)據(jù) 最終一致性;還有就是后臺服務(wù)一般要實現(xiàn) 冪等性,因為消息送出于性能的考慮一般會有重復(fù)(保證消息的被收到且僅收到一次對性能是很大的考驗);最后就是必須引入一個獨立的 Broker;
-
調(diào)用服務(wù)之間的耦合:用戶服務(wù)與產(chǎn)品服務(wù)之間存在調(diào)用,若RPC的方式,用戶服務(wù)就得依賴產(chǎn)品服務(wù),產(chǎn)品服務(wù)在線,用戶服務(wù)才能上線;產(chǎn)品服務(wù)不在線,用戶服務(wù)無法啟動,因為用戶服務(wù)無法遠(yuǎn)程調(diào)用到產(chǎn)品服務(wù),相當(dāng)于沒有添加需要的依賴;這就形成了耦合度;將RPC換成Broker能降低耦合;
-
Broker是一個服務(wù)器,它能成為用戶服務(wù)和產(chǎn)品服務(wù)之間的緩沖,用戶服務(wù)調(diào)用產(chǎn)品服務(wù)會傳遞消息過來,Broker是一個服務(wù)器,形成一個緩沖的效果,這樣就不會因為用戶服務(wù)而導(dǎo)致產(chǎn)品服務(wù)掛掉;
-
用戶服務(wù)調(diào)用產(chǎn)品服務(wù)的時候,會有大量的請求過來,這就已經(jīng)在拖產(chǎn)品服務(wù)的速度、內(nèi)存消耗、CPU等;以此同時用戶也在通過UI調(diào)用網(wǎng)關(guān),在單獨的獨立的請求產(chǎn)品服務(wù),這就分成了兩個業(yè)務(wù)線在調(diào)用產(chǎn)品服務(wù):別的用戶在調(diào)用產(chǎn)品服務(wù),用戶服務(wù)在調(diào)用產(chǎn)品服務(wù);這時有Broker服務(wù)器緩沖一些后臺服務(wù)的調(diào)用,能降低一些壓力;
-
一致性的減弱:比如用戶通過UI調(diào)用API網(wǎng)關(guān)下了一個訂單,這個時候是用HTTP請求,是同步的,下完訂單馬上就有反饋;這個時候如果是異步,有一個緩沖,下完訂單,可能不會立刻處理,這樣也就不會立刻得到反饋;這就是一致性的減弱;
-
最終一致性:不是實時反饋,但是最終的結(jié)果是正確的就可以了;
-
冪等性:無論多少次請求,返回的結(jié)果都是一樣的;
-
獨立的Broker:稱之為消息隊列的中間服務(wù)器;
消息隊列:就是一個設(shè)計模式 - 生產(chǎn)者消費者模式:生產(chǎn)者只管生產(chǎn),消費者只管消費;
消息隊列分兩種:
-
有Broker的:
Broker是對消息的持久化;
有Broker就說明有個服務(wù)器 ,做兩個服務(wù)之間的中間緩沖;
有Broker是為了做消息的持久化, -
無Broker的:
無Broker的就是兩個服務(wù)之間直連;
無Broker就是在對消息的完整型要求不高的情況下使用,kafka是代表;
kafka:全球最快消息隊列;一般拿來做日志;
比如創(chuàng)建一個訂單,由生產(chǎn)者進行生產(chǎn),然后傳遞給消費者;生產(chǎn)者這個服務(wù)只管生產(chǎn),而不管消費者服務(wù)怎么處理、什么時候處理這個訂單,只是一直生產(chǎn)一直發(fā),這就會導(dǎo)致消費者服務(wù)被拖垮;所以生產(chǎn)者和消費者這個兩個服務(wù)之間要有一個稱為Broker的緩沖地帶;
生產(chǎn)者不管消費者什么時候消費、怎么消費,消費者可能不能處理那么大的信息,這就會形成消息積壓;消費者發(fā)送的請求都發(fā)送都Broker,Broker先存著,然后由Broker一條一條發(fā)送給消費者,消費者性能跟不上了,Broker就會等待,等消費者能處理了再發(fā)送請求給消費者;
生產(chǎn)者往消費者發(fā)消息,若消費者掛掉了,而生產(chǎn)者還在一直發(fā),若沒有緩沖地帶,這些消息就會消失,影響一致性;中間有一個Broker,對消息做了持久化,當(dāng)消費者下線以后,再次上線,消息還在Broker中;
若消息很重要,不能丟失,就不可以在兩個服務(wù)之間直連,必須要有Broker來做消息的持久化;但有些消息可以丟失,要的是異步、速度,對數(shù)據(jù)的完整性(一致性)不考慮,比如日志傳輸,日志不需要完整,丟幾條也沒有問題;這時候就可以使用kafka;
3、如此多的服務(wù),如何實現(xiàn)
在微服務(wù)架構(gòu)中,一般每個服務(wù)都有多個拷貝,來做負(fù)載均衡;一個服務(wù)隨時可能下線,也可能應(yīng)對臨時訪問壓力增加新的服務(wù)節(jié)點;
一個容器一個服務(wù),一個容器是一個節(jié)點;一個服務(wù)有N個節(jié)點的時候,用戶請求的時候,每個節(jié)點都有可能去,多個用戶請求這個服務(wù),就把請求的壓力分散開了,這就叫負(fù)載均衡;一個服務(wù)下線了,還有其他服務(wù)節(jié)點繼續(xù)提供服務(wù),這個效果就稱為高可用;
服務(wù)之間如何相互感知?服務(wù)如何管理?這就是服務(wù)發(fā)現(xiàn)的問題了;
服務(wù)發(fā)現(xiàn):API網(wǎng)關(guān)怎么知道服務(wù)的IP和端口?這些服務(wù)下線了怎么辦?新增了一個服務(wù)節(jié)點06,網(wǎng)關(guān)怎么知道06節(jié)點的存在?
服務(wù)發(fā)現(xiàn)一般有2種做法,基本都是通過Zookeeper等類似技術(shù)做服務(wù)注冊信息的分布式管理;當(dāng)服務(wù)上線時,服務(wù)提供者將自己的服務(wù)信息注冊到ZK(或類似框架),并通過心跳維持長鏈接(Tcp長鏈接),實時更新鏈接信息;調(diào)用者通過ZK尋址,根據(jù)可指定算法,找到一個服務(wù),還可以將一個服務(wù)信息緩存在本地以提高性能;當(dāng)服務(wù)下線時,ZK會通知給服務(wù)客戶端;
Zookeeper是一個框架,主要用來做 服務(wù)的注冊與發(fā)現(xiàn);
(1)基于客戶端的服務(wù)注冊與發(fā)現(xiàn):
- 優(yōu)點是架構(gòu)簡單,擴展靈活,只對服務(wù)注冊器依賴;
- 缺點是客戶端要維護所有調(diào)用服務(wù)的地址,有技術(shù)難度,一般大公司都有成熟的內(nèi)部框架支持,比如 Dubbo;
Dubbo是RPC遠(yuǎn)程調(diào)用框架,Zookeeper是服務(wù)注冊與發(fā)現(xiàn)框架,兩者結(jié)合使用完成微服務(wù)的實現(xiàn);
客戶端服務(wù)自己注冊到服務(wù)注冊中心(ZK)去,ZK維護這個IP列表,訂單服務(wù)要調(diào)用產(chǎn)品服務(wù),就去注冊中心查找產(chǎn)品服務(wù)的IP、端口、服務(wù)名稱;
客戶端服務(wù)器啟動的時候,需要把自己的IP、端口、服務(wù)名稱告訴 服務(wù)注冊與發(fā)現(xiàn) 服務(wù)器,API網(wǎng)關(guān)想要調(diào)用什么服務(wù),就告訴服務(wù)注冊中心服務(wù)名稱,注冊中心反饋回一個對應(yīng)的服務(wù)的IP與端口,網(wǎng)關(guān)就能直接調(diào)用這個服務(wù)了;
原來是由網(wǎng)關(guān)管理后臺服務(wù)的IP列表,現(xiàn)在由注冊中心來管理,服務(wù)器的信息,由服務(wù)自己注冊到服務(wù)中心;
(2)基于服務(wù)端的服務(wù)注冊與發(fā)現(xiàn):
優(yōu)點是簡單,所有服務(wù)對于前臺調(diào)用方透明,一般在小公司在云服務(wù)上部署的應(yīng)用采用的比較多;
由服務(wù)調(diào)用者去調(diào)用負(fù)載均衡服務(wù)器,負(fù)載均衡服務(wù)器去調(diào)用注冊中心,再去調(diào)用對應(yīng)的服務(wù);比基于客戶端的方式多個一個LB服務(wù)器;
UI調(diào)用負(fù)載均衡服務(wù)器,再由LB調(diào)用API網(wǎng)關(guān),因為網(wǎng)關(guān)也需要開辟多個節(jié)點,做負(fù)載均衡,以避免單點故障的出現(xiàn),從而實現(xiàn)高可用;服務(wù)注冊中心也要做負(fù)載均衡;
所有的服務(wù)都要經(jīng)過注冊服務(wù)注冊中心,有服務(wù)注冊中心統(tǒng)一管理IP、端口、服務(wù)名稱;
4、服務(wù)掛了怎么辦
分布式最大的特性就是網(wǎng)絡(luò)是不可靠的:ping的時候偶爾會有丟包;
解決辦法:
-
重試機制:一次沒請求成功,再請求一次; ZK去請求后臺服務(wù)的時候,由于網(wǎng)絡(luò)原因,沒有連接上服務(wù),那就在超時之后再試一次;
-
限流:同時有一萬個并發(fā)過來請求訪問服務(wù)器2,壓力很大,因為是同步請求,就會阻塞,阻塞就可能掛掉,就會出現(xiàn)單點故障;這時候就可以在客戶端調(diào)用ZK那里進行限流,讓一部分請求停止在客戶端那里,不會發(fā)送到后臺服務(wù)器上;
-
熔斷機制:客戶端的請求全部通過ZK發(fā)送到了后臺,流量一上來,就開啟熔斷機制,在真正到達處理請求的服務(wù)器之前被阻斷,阻止請求發(fā)送到處理服務(wù)器;同時返回客戶端服務(wù)無法響應(yīng)的提示;
-
負(fù)載均衡:
-
降級(本地緩存):把服務(wù)下線,以保障系統(tǒng)最基本的功能能使用,表面看整個系統(tǒng)依然是高可用的;
當(dāng)大量請求發(fā)送到后臺的時候,沒有限流也沒有啟動熔斷機制,因為確實需要提供服務(wù),但是因為流量過大,計算機承載不了這些流量以后,就要停止部分服務(wù),以保障數(shù)據(jù)一致性問題;比如:訂單服務(wù),訂單服務(wù)后面又要去訪問其他服務(wù),這時如訂單服務(wù)承載不了那么大的壓力了,一旦再往下傳遞請求,就可能出現(xiàn)數(shù)據(jù)不一致了,這時候若沒有更好的解決方案,那就停掉訂單服務(wù)器,讓整個訂單服務(wù)下線,不要再產(chǎn)生新的訂單了;但是網(wǎng)站的其他服務(wù)還可以繼續(xù)使用;
微服務(wù)實現(xiàn)總結(jié):
單體應(yīng)用拆分成多個獨立的服務(wù),每一個服務(wù)是一個應(yīng)用程序,使用Docker的容器化部署將所有這些服務(wù)進行隔離;
服務(wù)與服務(wù)之間有一個通信問題要解決,有兩種方式:同步請求方式和異步請求方式;同步請求方式有2種方式:REST和RPC方式;異步請求方式只有一種方式:消息隊列方式;
這個時候因為由一個API Gateway來統(tǒng)一的存儲所有服務(wù)的IP與端口,對維護起來就增加了難度,于是就要使用另一個機制:服務(wù)注冊與發(fā)現(xiàn)機制;由統(tǒng)一的調(diào)度中心(API網(wǎng)關(guān))去請求服務(wù)注冊與發(fā)現(xiàn)機制 ,去獲取所需要的服務(wù)的對應(yīng)的IP和端口;由服務(wù)注冊中心來保障下面服務(wù)的高可用與一致性;
服務(wù)掛了之后可以使用”重試機制“、”限流“、”熔斷機制“、”負(fù)載均衡“、”服務(wù)降級“等方式以保障整個服務(wù)還處于高可用狀態(tài);
>> 單點故障與分布式鎖
- 單點故障:通俗講就是 由一個服務(wù)阻塞或掛機了,導(dǎo)致后面的服務(wù)都不可以使用了,這時候就稱為單點故障;
解決單點故障:使用分布式鎖;
Zookeeper:是一個服務(wù)注冊與發(fā)現(xiàn)的框架,同時也是一個分布式協(xié)調(diào)技術(shù); 最厲害的地方是它實現(xiàn)了分布式鎖的問題;
-
分布式鎖:為了防止分布式系統(tǒng)中多個進程之間相互干擾,就需要一種分布式協(xié)調(diào)技術(shù),來對這些進程進行協(xié)調(diào),而分布式協(xié)調(diào)的核心就是來實現(xiàn)分布式鎖;ZK就是這樣的一個實現(xiàn)了分布式鎖的分布式協(xié)調(diào)技術(shù);
-
分布式系統(tǒng)中的單點故障:
在分布式鎖服務(wù)中,有一種典型的應(yīng)用場景,就是通過對集群進行master選舉,來解決分布式系統(tǒng)中的單點故障問題;通常分布式系統(tǒng)采用主從模式,就是一個主機控制多個處理節(jié)點,主節(jié)點負(fù)責(zé)分發(fā)任務(wù),從節(jié)點負(fù)責(zé)處理任務(wù),當(dāng)主節(jié)點發(fā)生故障時,任務(wù)沒人分發(fā),那么整個系統(tǒng)就都掛掉了;這種故障就叫做單點故障;
~ 單點故障傳統(tǒng)解決方案:
采用一個備用節(jié)點,這個備用節(jié)點定期給主節(jié)點發(fā)送ping包,主節(jié)點收到ping包以后向備用節(jié)點發(fā)送回復(fù)Ack,備用節(jié)點收到回復(fù)的時候,就會認(rèn)為當(dāng)前主節(jié)點還活著,讓它繼續(xù)提供服務(wù);
當(dāng)主節(jié)點掛了,這個時候備用節(jié)點就收不到回復(fù)了,然后它就認(rèn)為主節(jié)點掛了,就接替它成為主節(jié)點;
但是這種方式存在一個隱患,就是網(wǎng)絡(luò)問題;主節(jié)點沒有掛掉,但是由于網(wǎng)絡(luò)震蕩問題,導(dǎo)致備用節(jié)點向主節(jié)點發(fā)送ping包之后,主節(jié)點沒有收到包,或是收到了,但是在返回Ack字節(jié)碼的時候,網(wǎng)絡(luò)突然丟了一個包,將主節(jié)點回應(yīng)給備用節(jié)點的Ack包丟了,這就一下,備用節(jié)點沒收到回復(fù),就認(rèn)為主節(jié)點掛了,然后備用節(jié)點就將它的Master實例啟動起來,這樣分布式系統(tǒng)中就出現(xiàn)了兩個主節(jié)點 - 雙Master(雙主問題);
出現(xiàn)Master以后,從節(jié)點就會將它所做的事一部分匯報給了主節(jié)點,一部分匯報給了從節(jié)點,這樣服務(wù)就亂套了:當(dāng)發(fā)送插入記錄的請求的時候,2個主節(jié)點都會收到這個請求,機會調(diào)用2此從節(jié)點處理這個請求,這樣就會插入兩次數(shù)據(jù);
為了防止雙主問題,就要使用ZK加入分布式鎖的概念,鎖住主節(jié)點的資源;
~ Zookeeper 解決方案
(1)Master啟動:
在引入ZK以后,啟動兩個主節(jié)點A和B,主節(jié)點-A和主節(jié)點-B啟動以后,都向ZK去注冊一個節(jié)點,注冊后就會有一個編號;假設(shè)主節(jié)點-A 鎖注冊的節(jié)點是master-00001,主節(jié)點-B 鎖注冊的節(jié)點是master-00002,注冊以后進行選舉,編號最小的節(jié)點將會在選舉中獲得鎖稱為主節(jié)點,這里主節(jié)點-A獲勝;然后主節(jié)點-B將會被阻塞成為一個備用節(jié)點;通過這種方式就完成了對兩個Master進程的調(diào)度;
在我們通過UI發(fā)送請求的時候,回去請求ZK,由ZK去請求需要的主節(jié)點進行消息的分發(fā);因為是分布式系統(tǒng),會有多個主節(jié)點的實例,誰來當(dāng)主節(jié)點,由ZK自己來選舉;
(2)Master故障:
如果”主節(jié)點-A“掛了,這時候它在ZK中注冊的節(jié)點就會自動刪除,ZK會自動感知節(jié)點的變化,然后再次發(fā)出選舉,這時候主節(jié)點-B獲勝,替代A稱為新的主節(jié)點;
ZK維護主節(jié)點們,也會向主節(jié)點們發(fā)送ping包,當(dāng)ZK向主節(jié)點-A發(fā)送Ping包,沒有回復(fù)之后,就會通知主節(jié)點-B重新選舉;如果主節(jié)點-A是因為網(wǎng)絡(luò)震蕩無法回復(fù)ZK的話,ZK就會將它從 服務(wù)注冊與發(fā)現(xiàn) 列表中直接刪除;當(dāng)A重新恢復(fù)上線以后,就會重新注冊到ZK中,這時候就會變成master-00003,而不是原來的00001;這時候ZK會感知節(jié)點的變化再次發(fā)動選舉,這時候主節(jié)點-B會再次獲勝繼續(xù)擔(dān)任主節(jié)點,節(jié)點A就會阻塞稱為備用節(jié)點,等待下次選舉;這樣就不會出現(xiàn)之前的雙主e問題了;
~ 總結(jié) - 面試:什么是ZK
什么是Zookeeper:服務(wù)注冊與發(fā)現(xiàn)中心;
ZK解決了什么問題:分布式鎖的問題;
先解釋單點故障:分布式系統(tǒng)才采用主從模式,就是一個主服務(wù)器調(diào)用兩個從服務(wù)器的資源;當(dāng)主服務(wù)器掛掉了,從服務(wù)器還在繼續(xù)提供服務(wù),但是由于主服務(wù)器掛掉了,兩個從服務(wù)器訪問不到了,這就叫做單點故障;
傳統(tǒng)的解決單點故障的方式是有兩個節(jié)點:主節(jié)點和備用節(jié)點,備用節(jié)點會一直ping主節(jié)點,若沒有收到主節(jié)點的回復(fù),就認(rèn)為主節(jié)點掛掉了,備用節(jié)點就上線代替原來的主節(jié)點稱為新的主節(jié)點提供服務(wù);但是若之前的主節(jié)點沒有掛掉,而是由于網(wǎng)絡(luò)震蕩問題沒有及時回復(fù)備用節(jié)點,使得備用節(jié)點誤以為主節(jié)點掛掉了,這就出現(xiàn)了雙主問題;一旦出現(xiàn)雙主問題,所有的請求都會出現(xiàn)多次、重復(fù),數(shù)據(jù)就會出現(xiàn)問題;
為了解決這個問題,就引入了分布式鎖的問題,而ZK這個框架就是解決分布式鎖的問題的;
ZK要求 所有服務(wù)啟動的時候都要想ZK進行注冊,這時候ZK就維護了一個節(jié)點列表;ZK會發(fā)發(fā)動選舉,決定誰會成為主節(jié)點,選舉出一個主節(jié)點,剩下的節(jié)點就會阻塞稱為備用節(jié)點;ZK會一直向主節(jié)點發(fā)送ping包,如沒有收到主節(jié)點的回復(fù),就會從它維護的節(jié)點列表中刪掉,而不是停掉,然后通知所有備用節(jié)點進行選舉,選出新的主節(jié)點繼續(xù)提供服務(wù);若出現(xiàn)剛才相同的網(wǎng)絡(luò)震蕩的導(dǎo)致主節(jié)點無法回復(fù)ZK的時候,主節(jié)點重新上線,就會重新到ZK去注冊,這個時候就會注冊成新的節(jié)點,變成備用節(jié)點,等待下次選舉;
~ 為什么要使用分布式鎖
三個并發(fā)同時去訪問負(fù)載均衡服務(wù)器,負(fù)載均衡服務(wù)器會去調(diào)度后臺服務(wù);后臺有3個服務(wù),3個服務(wù)提供的是3個相同的應(yīng)用程序;
部署了3套應(yīng)用程序,就變成了有3個獨立的JVM進程運行在3臺不同的服務(wù)器上;但是這里面我們可能要調(diào)用相同的變量A(因為系統(tǒng)是一樣的,所以變量是一致的);
3個變量A在3個JVM內(nèi)存中,變量A同時都會在JVM分配內(nèi)存,3個請求發(fā)送過來同時對這個變量進行操作,顯然結(jié)果是不對的;
不是同時發(fā)送過來,三個請求分別操作3個不同JVM內(nèi)存區(qū)域的數(shù)據(jù),變量A之間不存在共享,也不具可見性,處理的結(jié)果也是不對的;
這個變量A主要體現(xiàn)是在一個類中的一個成員變量,是一個有狀態(tài)的對象;
如果業(yè)務(wù)中確實存在這個場景,就需要一種方法解決這個問題;
為了保證一個方法或?qū)傩栽诟卟l(fā)情況下的同一時間只能被一個線程執(zhí)行,在單機環(huán)境中,Java提供了很多并發(fā)處理相關(guān)的API:同步鎖;
由于分布式系統(tǒng)多線程、多進程,并且分布在不同機器上,這使得原單機部署情況下的并發(fā)控制鎖策略生效;
這就需要一種跨JVM的互斥機制來控制共享資源的訪問;分布式鎖就是解決這個問題的;
Zookeeper就能做到跨進程協(xié)作;
分布式鎖應(yīng)該具備的條件:
- 在分布式系統(tǒng)環(huán)境下,一個方法在同一時間只能被一個機器的一個線程執(zhí)行;
- 高可用的獲取鎖和釋放鎖:獲取鎖、釋放鎖的服務(wù)器(ZK)本身也得高可用;
- 高性能的獲取鎖和釋放鎖:獲取/釋放鎖的操作要快;
- 具備可重入性:可理解為重新進入(重新觸發(fā)這個事情的時候),由多于一個任務(wù)并發(fā)使用,而不必?fù)?dān)心數(shù)據(jù)錯誤;
- 具備鎖失效機制,防止死鎖;
- 具備非阻塞鎖特性,就是沒有獲取到鎖將直接返回獲取鎖失敗;類似熔斷機制,拿不到鎖直接返回結(jié)果,不能讓程序阻塞在這個地方;
>> 微服務(wù)架構(gòu)設(shè)計模式
https://www.funtl.com/zh/micro-service-about/再談微服務(wù)-微服務(wù)架構(gòu)設(shè)計模式.html#微服務(wù)架構(gòu)需要考慮的問題
文章整理自此博客視頻教程
總結(jié)
- 上一篇: 设置linux的自动关机和windows
- 下一篇: Group Normalization(