上一節(jié)大概的講述了一下微服務(wù)框架,這一節(jié)將講到它的設(shè)計(jì)與實(shí)現(xiàn)序矩。可能會(huì)涉及到一些Dubbo相關(guān)的東西,畢竟接觸到的其中一種實(shí)現(xiàn)就是Dubbo+zookeeper
同樣也是轉(zhuǎn)自知乎:
---API網(wǎng)關(guān)的設(shè)計(jì)與實(shí)現(xiàn)
注意帆竹,我下面提到著這些內(nèi)容,所涉及的java基礎(chǔ)知識(shí)可能會(huì)是我后面需要補(bǔ)足的脓规,比如NIO
對(duì)于大多數(shù)的應(yīng)用程序而言栽连,API網(wǎng)關(guān)的性能和可擴(kuò)展性都非常重要。因此將API網(wǎng)關(guān)構(gòu)建在一個(gè)支持異步抖拦、IO非阻塞的平臺(tái)上是合理的升酣。有多種不同的技術(shù)可以實(shí)現(xiàn)一個(gè)可擴(kuò)展的API網(wǎng)關(guān)舷暮。在JVM上态罪,可以使用一種基于NIO的框架,比如Netty下面、Vertx复颈,Spring Reactor或JBoss Undertow中的一種。一個(gè)非常流行的非JVM是Node.js沥割。
對(duì)于API網(wǎng)關(guān)需要實(shí)現(xiàn)底層多個(gè)細(xì)粒度的API組合場(chǎng)景耗啦,文章推薦使用響應(yīng)式編程模型進(jìn)行而不是傳統(tǒng)的異步回調(diào)方法組合代碼【比如ajax就是一種異步回調(diào),因?yàn)樗鼤?huì)導(dǎo)致代碼混亂】由于API本身存在并行或先后調(diào)用机杜,對(duì)于回調(diào)方法難以控制
基于微服務(wù)的應(yīng)用系統(tǒng)本身是一個(gè)分布式的系統(tǒng)帜讲,因此必須有一種合理的進(jìn)程通信機(jī)制,有兩種可供選擇椒拗,一種是異步的似将、基于消息傳遞機(jī)制的获黔,實(shí)現(xiàn)諸如:JMS或AMQP;另一種是基于HTTP和Thrift的進(jìn)程同步機(jī)制在验。通常一個(gè)系統(tǒng)會(huì)采用異步和同步兩種機(jī)制玷氏,甚至同一種機(jī)制下的多種實(shí)現(xiàn)。
注意:為了更好地將微服務(wù)之間解耦合腋舌,希望能夠保存一些服務(wù)結(jié)果的緩存盏触,以免造成信息不可用的情況,另外更建議的是采用異步的通信方式块饺。
總結(jié):API網(wǎng)關(guān)作為系統(tǒng)的唯一入口赞辩,API網(wǎng)關(guān)負(fù)責(zé)服務(wù)請(qǐng)求路由、組合以及協(xié)議轉(zhuǎn)換授艰,它為每個(gè)應(yīng)用客戶端提供定制的API诗宣。API網(wǎng)關(guān)還可以通過(guò)返回緩存數(shù)據(jù)或默認(rèn)數(shù)據(jù)屏蔽后端服務(wù)的失敗
---微服務(wù)框架中進(jìn)程間的通信
基于微服務(wù)的分布式應(yīng)用是運(yùn)行在多臺(tái)服務(wù)器上的,一般來(lái)說(shuō)每個(gè)服務(wù)實(shí)例都是一個(gè)進(jìn)程想诅,因此服務(wù)之間必須通過(guò)進(jìn)程通信【IPC】來(lái)實(shí)現(xiàn)召庞。
對(duì)于微服務(wù)框架的交互模式,文章從兩個(gè)維度進(jìn)行描述:
一對(duì)一:每個(gè)客戶端請(qǐng)求由一個(gè)服務(wù)實(shí)例來(lái)響應(yīng)来破。
一對(duì)多:每個(gè)客戶端的請(qǐng)求由多個(gè)服務(wù)實(shí)例來(lái)響應(yīng)篮灼。
同步模式:客戶端請(qǐng)求需要服務(wù)器及時(shí)響應(yīng),甚至由于等待而阻塞
異步模式:客戶端請(qǐng)求不會(huì)阻塞進(jìn)程徘禁,服務(wù)端的響應(yīng)式非及時(shí)的
基于異步模塊往往采用消息機(jī)制來(lái)實(shí)現(xiàn)诅诱,同時(shí)配合消息中間件可以進(jìn)一步實(shí)現(xiàn)消息的發(fā)布訂閱。異步消息機(jī)制可以做到最大化解耦送朱,對(duì)于數(shù)據(jù)CUD的場(chǎng)景可以看到是比較容易通過(guò)異步消息機(jī)制實(shí)現(xiàn)的娘荡,但是會(huì)進(jìn)一步引入事務(wù)一致性問(wèn)題,即在采用異步消息機(jī)制后往往通過(guò)BASE事務(wù)最終一致性來(lái)解決事務(wù)層面問(wèn)題驶沼。
而對(duì)于查詢功能可以看到的是比較難通過(guò)異步消息API實(shí)現(xiàn)炮沐,在引入這個(gè)之前,可能有兩方面的問(wèn)題需要考慮回怜。
其一大年,服務(wù)網(wǎng)關(guān)需要有數(shù)據(jù)緩存能力,以解決無(wú)法從源端獲取數(shù)據(jù)的場(chǎng)景玉雾。其二是翔试,前端開(kāi)發(fā)框架本身需要支持異步調(diào)用和數(shù)據(jù)裝載模式,特別是數(shù)據(jù)查詢功能對(duì)于用戶來(lái)講复旬,在前端感受仍然是需要同步的垦缅,即通過(guò)異步的方式返回了查詢數(shù)據(jù)動(dòng)態(tài)刷新前端展示界面
---服務(wù)版本問(wèn)題:
這是不可避免要遇到的問(wèn)題,特別是對(duì)于RestAPI的驹碍,由于JSON本身格式無(wú)Schema返回壁涎,會(huì)更加忽視對(duì)服務(wù)版本的管理和控制柏蘑。要知道對(duì)于JSON數(shù)據(jù)格式變化,會(huì)導(dǎo)致RestAPI調(diào)用后處理失敗粹庞。因此服務(wù)版本仍然采用大小版本機(jī)制比較好咳焚,對(duì)于小版本變更,則直接對(duì)原有服務(wù)進(jìn)行覆蓋同時(shí)對(duì)所有受影響的服務(wù)消費(fèi)端進(jìn)行升級(jí)庞溜;而對(duì)大版本升級(jí)則本質(zhì)是新增了一個(gè)服務(wù)革半,而對(duì)于舊版本服務(wù)逐步遷移和代替。
---處理局部失敗
文中提到Netfilix的服務(wù)解決方案流码,對(duì)于失敗的問(wèn)題的解決要注意常用的仍然是服務(wù)超時(shí)設(shè)置又官,斷路器機(jī)制,流量控制漫试,緩存數(shù)據(jù)或默認(rèn)值返回等六敬。不論采用哪種失敗處理策略,都需要考慮盡量減少服務(wù)調(diào)用失敗或超時(shí)對(duì)最終用戶的影響驾荣。
---基于請(qǐng)求/響應(yīng)的同步IPC
使用同步的外构、基于請(qǐng)求/響應(yīng)的IPC機(jī)制的時(shí)候,客戶端向服務(wù)端發(fā)送請(qǐng)求播掷,服務(wù)端處理請(qǐng)求并返回響應(yīng)审编,一些客戶端會(huì)由于等待服務(wù)端響應(yīng)而被阻塞,而另外一些客戶端可能使用異步的歧匈、基于事件驅(qū)動(dòng)的客戶端代碼垒酬,這些代碼可能通過(guò)Future或者Rx Observable封裝。然而與使用消息機(jī)制不同件炉,客戶端需要響應(yīng)及時(shí)返回勘究,這個(gè)模式中有很多可選的協(xié)議,最常見(jiàn)的還是REST和Thrift斟冕。
在文章中提到了兩種服務(wù)發(fā)現(xiàn)模式口糕,即客戶端發(fā)現(xiàn)模式和服務(wù)端發(fā)現(xiàn)模式,分開(kāi)描述如下:
---客戶端發(fā)現(xiàn)模式
使用客戶端發(fā)現(xiàn)模式時(shí)宫静,客戶端決定相應(yīng)服務(wù)實(shí)例的網(wǎng)絡(luò)位置走净,并且對(duì)請(qǐng)求實(shí)現(xiàn)負(fù)載均衡券时」吕铮客戶端查詢服務(wù)注冊(cè)表,后者是一個(gè)可用服務(wù)實(shí)例的數(shù)據(jù)庫(kù)橘洞;然后使用負(fù)載均衡算法從中選擇一個(gè)實(shí)例捌袜,并發(fā)出請(qǐng)求。
注:這是類似Dubbo實(shí)現(xiàn)機(jī)制一樣的兩階段模式炸枣,任何一個(gè)服務(wù)的消費(fèi)都需要分兩個(gè)步驟進(jìn)行虏等。第一步弄唧,首先是訪問(wèn)服務(wù)注冊(cè)庫(kù)【更多的是API Gateway提供的一個(gè)能力】返回一個(gè)已經(jīng)動(dòng)態(tài)均衡過(guò)的服務(wù)可用地址;第二步客戶端和該地址直接連接進(jìn)行服務(wù)消費(fèi)和訪問(wèn)霍衫。
這種模式的實(shí)現(xiàn)兩個(gè)重點(diǎn)候引,一是動(dòng)態(tài)負(fù)載均衡算法,其二是服務(wù)網(wǎng)關(guān)需要能夠?qū)υ挤?wù)提供點(diǎn)進(jìn)行實(shí)時(shí)心跳檢測(cè)以確定服務(wù)提供的可用性敦跌。
---服務(wù)端發(fā)現(xiàn)模式
客戶端通過(guò)負(fù)載均衡器向某個(gè)服務(wù)提出請(qǐng)求澄干,負(fù)載均衡器查詢服務(wù)注冊(cè)表,并將請(qǐng)求轉(zhuǎn)發(fā)到可用的服務(wù)實(shí)例柠傍,如同客戶端發(fā)現(xiàn)麸俘,服務(wù)實(shí)例在服務(wù)注冊(cè)表中注冊(cè)或注銷。在服務(wù)注冊(cè)器前新增一個(gè)Load Balance節(jié)點(diǎn)惧笛。
服務(wù)器發(fā)現(xiàn)模式兼具優(yōu)缺點(diǎn)从媚,它最大的優(yōu)點(diǎn)是客戶端無(wú)需注意細(xì)節(jié),只需要簡(jiǎn)單地向負(fù)載均衡器發(fā)出請(qǐng)求患整,這就減少了編程語(yǔ)言框架需要的發(fā)現(xiàn)邏輯拜效。某些部署環(huán)境免費(fèi)提供這一功能
----服務(wù)注冊(cè)表
服務(wù)注冊(cè)表需要高可用而且隨時(shí)更新「餮瑁客戶端能夠緩存從服務(wù)注冊(cè)表中獲取的網(wǎng)絡(luò)地址拂檩,然而,這些信息最終會(huì)過(guò)時(shí)嘲碧,客戶端也就無(wú)法發(fā)現(xiàn)服務(wù)實(shí)例稻励,因此,服務(wù)注冊(cè)表會(huì)包含若干服務(wù)端愈涩,使用復(fù)制協(xié)議保持一致性望抽。
首先可以看到服務(wù)注冊(cè)表本身不能是單點(diǎn),否則會(huì)存在單點(diǎn)故障履婉,當(dāng)服務(wù)注冊(cè)表有多臺(tái)服務(wù)器的時(shí)候同時(shí)需要考慮服務(wù)注冊(cè)庫(kù)信息在多臺(tái)機(jī)器上的實(shí)時(shí)同步和一致煤篙。我們操作和配置服務(wù)注冊(cè)信息的時(shí)候,往往只會(huì)在一個(gè)統(tǒng)一的服務(wù)管控端完成毁腿。
如果注冊(cè)服務(wù)器宕機(jī)是否一定會(huì)影響到客戶端消費(fèi)和調(diào)用辑奈,如果考慮更高的整體架構(gòu)可用性,還可以設(shè)計(jì)對(duì)于服務(wù)注冊(cè)庫(kù)信息在客戶端本地的緩存已烤,當(dāng)服務(wù)注冊(cè)表無(wú)法訪問(wèn)的時(shí)候可以臨時(shí)讀取本地緩存的服務(wù)注冊(cè)庫(kù)信息并發(fā)起請(qǐng)求鸠窗。
對(duì)于服務(wù)注冊(cè)表,文章提供了3個(gè)選擇胯究,最常用的還是基于Zookeeper的稍计。Dubbo也有集成廣播的發(fā)現(xiàn)。
Zookeeper--分布式應(yīng)用廣泛使用的高性能協(xié)調(diào)服務(wù)
如前所述裕循,服務(wù)實(shí)例必須在注冊(cè)表中注冊(cè)和銷毀臣嚣,注冊(cè)和銷毀有兩種不同的方法净刮。
1. 服務(wù)實(shí)例自己注冊(cè),自注冊(cè)模式
2. 管理服務(wù)實(shí)例的其他組件硅则,即第三方注冊(cè)
雖然方法一把服務(wù)實(shí)例和服務(wù)注冊(cè)表耦合淹父,必須在每個(gè)編程語(yǔ)言和框架內(nèi)實(shí)現(xiàn)注冊(cè)代碼,但是在自己實(shí)現(xiàn)完整微服務(wù)框架中怎虫,考慮到PaaS平臺(tái)微服務(wù)模塊的動(dòng)態(tài)部署和擴(kuò)展弹灭,采用方法一相對(duì)來(lái)說(shuō)更加容易實(shí)現(xiàn)。