摘要:服務(wù)發(fā)現(xiàn)問題對(duì)于來講,我們已經(jīng)解決了傳輸協(xié)議的問題基于,協(xié)議約定問題基于,最后要解決的是服務(wù)發(fā)現(xiàn)問題。另外一方是服務(wù)消費(fèi)方,向獲取服務(wù)提供方的注冊(cè)信息。
????上一節(jié)我們了解了基于 XML 的 SOAP 協(xié)議,SOAP 的 S 是啥意思來著?是 Simple,但是好像一點(diǎn)兒都不簡(jiǎn)單啊!
傳輸協(xié)議問題????對(duì)于 SOAP 來講,比如我創(chuàng)建一個(gè)訂單,用 POST,在 XML 里面寫明動(dòng)作是 CreateOrder;刪除一個(gè)訂單,還是用 POST,在 XML 里面寫明了動(dòng)作是 DeleteOrder。其實(shí)創(chuàng)建訂單完全可以使用 POST 動(dòng)作,然后在 XML 里面放一個(gè)訂單的信息就可以了,而刪除用 DELETE 動(dòng)作,然后在 XML 里面放一個(gè)訂單的 ID 就可以了。
????于是上面的那個(gè) SOAP 就變成下面這個(gè)簡(jiǎn)單的模樣。
POST /purchaseOrder HTTP/1.1 Host: www.cnblog.com Content-Type: application/xml; charset=utf-8 Content-Length: nnn2018-07-01 板栗燜雞 58
????而且 XML 的格式也可以改成另外一種簡(jiǎn)單的文本化的對(duì)象表示格式 JSON。
????經(jīng)常寫 Web 應(yīng)用的應(yīng)該已經(jīng)發(fā)現(xiàn),這就是 RESTful 格式的 API 的樣子。
協(xié)議約定問題????然而 RESTful 可不僅僅是指 API,而是一種架構(gòu)風(fēng)格,全稱 Representational State Transfer,表述性狀態(tài)轉(zhuǎn)移,來自一篇重要的論文《架構(gòu)風(fēng)格與基于網(wǎng)絡(luò)的軟件架構(gòu)設(shè)計(jì)》(Architectural Styles and the Design of Network-based Software Architectures)。
????這篇文章從深層次,更加抽象地論證了一個(gè)互聯(lián)網(wǎng)應(yīng)用應(yīng)該有的設(shè)計(jì)要點(diǎn),而這些設(shè)計(jì)要點(diǎn),成為后來我們能看到的所有高并發(fā)應(yīng)用設(shè)計(jì)都必須要考慮的問題,再加上 REST API 比較簡(jiǎn)單直接,所以后來幾乎成為互聯(lián)網(wǎng)應(yīng)用的標(biāo)準(zhǔn)接口。
????因此,和 SOAP 不一樣,REST 不是一種嚴(yán)格規(guī)定的標(biāo)準(zhǔn),它其實(shí)是一種設(shè)計(jì)風(fēng)格。如果按這種風(fēng)格進(jìn)行設(shè)計(jì),RESTful 接口和 SOAP 接口都能做到,只不過后面的架構(gòu)是 REST 倡導(dǎo)的,而 SOAP 相對(duì)比較關(guān)注前面的接口。
????而且由于能夠通過 WSDL 生成客戶端的 Stub,因而 SOAP 常常被用于類似傳統(tǒng)的 RPC 方式,也即調(diào)用遠(yuǎn)端和調(diào)用本地是一樣的。
????然而本地調(diào)用和遠(yuǎn)程跨網(wǎng)絡(luò)調(diào)用畢竟不一樣,這里的不一樣還不僅僅是因?yàn)橛芯W(wǎng)絡(luò)而導(dǎo)致的客戶端和服務(wù)端的分離,從而帶來的網(wǎng)絡(luò)性能問題。更重要的問題是,客戶端和服務(wù)端誰來維護(hù)狀態(tài)。所謂的狀態(tài)就是對(duì)某個(gè)數(shù)據(jù)當(dāng)前處理到什么程度了。
????這里舉幾個(gè)例子,例如,我瀏覽到哪個(gè)目錄了,我看到第幾頁了,我要買個(gè)東西,需要扣減一下庫存,這些都是狀態(tài)。本地調(diào)用其實(shí)沒有人糾結(jié)這個(gè)問題,因?yàn)閿?shù)據(jù)都在本地,誰處理都一樣,而且一邊處理了,另一邊馬上就能看到。
????當(dāng)有了 RPC 之后,我們本來期望對(duì)上層透明,就像上一節(jié)說的“遠(yuǎn)在天邊,盡在眼前”。于是使用 RPC 的時(shí)候,對(duì)于狀態(tài)的問題也沒有太多的考慮。
????就像 NFS 一樣,客戶端會(huì)告訴服務(wù)端,我要進(jìn)入哪個(gè)目錄,服務(wù)端必須要為某個(gè)客戶端維護(hù)一個(gè)狀態(tài),就是當(dāng)前這個(gè)客戶端瀏覽到哪個(gè)目錄了。例如,客戶端輸入 cd hello,服務(wù)端要在某個(gè)地方記住,上次瀏覽到 /root/liuchao 了,因而客戶的這次輸入,應(yīng)該給它顯示 /root/liuchao/hello 下面的文件列表。而如果有另一個(gè)客戶端,同樣輸入 cd hello,服務(wù)端也在某個(gè)地方記住,上次瀏覽到 /var/lib,因而要給客戶顯示的是 /var/lib/hello。
????不光 NFS,如果瀏覽翻頁,我們經(jīng)常要實(shí)現(xiàn)函數(shù) next(),在一個(gè)列表中取下一頁,但是這就需要服務(wù)端記住,客戶端 A 上次瀏覽到 20~30 頁了,那它調(diào)用 next(),應(yīng)該顯示 30~40 頁,而客戶端 B 上次瀏覽到 100~110 頁了,調(diào)用 next() 應(yīng)該顯示 110~120 頁。
????上面的例子都是在 RPC 場(chǎng)景下,由服務(wù)端來維護(hù)狀態(tài),很多 SOAP 接口設(shè)計(jì)的時(shí)候,也常常按這種模式。這種模式原來沒有問題,是因?yàn)榭蛻舳撕头?wù)端之間的比例沒有失衡。因?yàn)橐话悴粫?huì)同時(shí)有太多的客戶端同時(shí)連上來,所以 NFS 還能把每個(gè)客戶端的狀態(tài)都記住。
????公司內(nèi)部使用的 ERP 系統(tǒng),如果使用 SOAP 的方式實(shí)現(xiàn),并且服務(wù)端為每個(gè)登錄的用戶維護(hù)瀏覽到報(bào)表那一頁的狀態(tài),由于一個(gè)公司內(nèi)部的人也不會(huì)太多,把 ERP 放在一個(gè)強(qiáng)大的物理機(jī)上,也能記得過來。
????但是互聯(lián)網(wǎng)場(chǎng)景下,客戶端和服務(wù)端就徹底失衡了。你可以想象“雙十一”,多少人同時(shí)來購物,作為服務(wù)端,它能記得過來嗎?當(dāng)然不可能,只好多個(gè)服務(wù)端同時(shí)提供服務(wù),大家分擔(dān)一下。但是這就存在一個(gè)問題,服務(wù)端怎么把自己記住的客戶端狀態(tài)告訴另一個(gè)服務(wù)端呢?或者說,你讓我給你分擔(dān)工作,你也要把工作的前因后果給我說清楚啊!
????那服務(wù)端索性就要想了,既然這么多客戶端,那大家就分分工吧。服務(wù)端就只記錄資源的狀態(tài),例如文件的狀態(tài),報(bào)表的狀態(tài),庫存的狀態(tài),而客戶端自己維護(hù)自己的狀態(tài)。比如,你訪問到哪個(gè)目錄了啊,報(bào)表的哪一頁了啊,等等。
????這樣對(duì)于 API 也有影響,也就是說,當(dāng)客戶端維護(hù)了自己的狀態(tài),就不能這樣調(diào)用服務(wù)端了。例如客戶端說,我想訪問當(dāng)前目錄下的 hello 路徑。服務(wù)端說,我怎么知道你的當(dāng)前路徑。所以客戶端要先看看自己當(dāng)前路徑是 /root/liuchao,然后告訴服務(wù)端說,我想訪問 /root/liuchao/hello 路徑。
????再比如,客戶端說我想訪問下一頁,服務(wù)端說,我怎么知道你當(dāng)前訪問到哪一頁了。所以客戶端要先看看自己訪問到了 100~110 頁,然后告訴服務(wù)器說,我想訪問 110~120 頁。
????這就是服務(wù)端的無狀態(tài)化。這樣服務(wù)端就可以橫向擴(kuò)展了,一百個(gè)人一起服務(wù),不用交接,每個(gè)人都能處理。
????所謂的無狀態(tài),其實(shí)是服務(wù)端維護(hù)資源的狀態(tài),客戶端維護(hù)會(huì)話的狀態(tài)。對(duì)于服務(wù)端來講,只有資源的狀態(tài)改變了,客戶端才調(diào)用 POST、PUT、DELETE 方法來找我;如果資源的狀態(tài)沒變,只是客戶端的狀態(tài)變了,就不用告訴我了,對(duì)于我來說都是統(tǒng)一的 GET。
????雖然這只改進(jìn)了 GET,但是已經(jīng)帶來了很大的進(jìn)步。因?yàn)閷?duì)于互聯(lián)網(wǎng)應(yīng)用,大多數(shù)是讀多寫少的。而且只要服務(wù)端的資源狀態(tài)不變,就給了我們緩存的可能。例如可以將狀態(tài)緩存到接入層,甚至緩存到 CDN 的邊緣節(jié)點(diǎn),這都是資源狀態(tài)不變的好處。
????按照這種思路,對(duì)于 API 的設(shè)計(jì),就慢慢變成了以資源為核心,而非以過程為核心。也就是說,客戶端只要告訴服務(wù)端你想讓資源狀態(tài)最終變成什么樣就可以了,而不用告訴我過程,不用告訴我動(dòng)作。
????還是文件目錄的例子。客戶端應(yīng)該訪問哪個(gè)絕對(duì)路徑,而非一個(gè)動(dòng)作,我就要進(jìn)入某個(gè)路徑。再如,庫存的調(diào)用,應(yīng)該查看當(dāng)前的庫存數(shù)目,然后減去購買的數(shù)量,得到結(jié)果的庫存數(shù)。這個(gè)時(shí)候應(yīng)該設(shè)置為目標(biāo)庫存數(shù)(但是當(dāng)前庫存數(shù)要匹配),而非告知減去多少庫存。
????這種 API 的設(shè)計(jì)需要實(shí)現(xiàn)冪等,因?yàn)榫W(wǎng)絡(luò)不穩(wěn)定,就會(huì)經(jīng)常出錯(cuò),因而需要重試,但是一旦重試,就會(huì)存在冪等的問題,也就是同一個(gè)調(diào)用,多次調(diào)用的結(jié)果應(yīng)該一樣,不能一次支付調(diào)用,因?yàn)檎{(diào)用三次變成了支付三次。不能進(jìn)入 cd a,做了三次,就變成了 cd a/a/a。也不能扣減庫存,調(diào)用了三次,就扣減三次庫存。
????當(dāng)然按照這種設(shè)計(jì)模式,無論 RESTful API 還是 SOAP API 都可以將架構(gòu)實(shí)現(xiàn)成無狀態(tài)的,面向資源的、冪等的、橫向擴(kuò)展的、可緩存的。
????但是 SOAP 的 XML 正文中,是可以放任何動(dòng)作的。例如 XML 里面可以寫 < ADD >,< MINUS > 等。這就方便使用 SOAP 的人,將大量的動(dòng)作放在 API 里面。
????RESTful 沒這么復(fù)雜,也沒給客戶提供這么多的可能性,正文里的 JSON 基本描述的就是資源的狀態(tài),沒辦法描述動(dòng)作,而且能夠出發(fā)的動(dòng)作只有 CRUD,也即 POST、GET、PUT、DELETE,也就是對(duì)于狀態(tài)的改變。
????所以,從接口角度,就讓你死了這條心。當(dāng)然也有很多技巧的方法,在使用 RESTful API 的情況下,依然提供基于動(dòng)作的有狀態(tài)請(qǐng)求,這屬于反模式了。
服務(wù)發(fā)現(xiàn)問題????對(duì)于 RESTful API 來講,我們已經(jīng)解決了傳輸協(xié)議的問題——基于 HTTP,協(xié)議約定問題——基于 JSON,最后要解決的是服務(wù)發(fā)現(xiàn)問題。
????有個(gè)著名的基于 RESTful API 的跨系統(tǒng)調(diào)用框架叫 Spring Cloud。在 Spring Cloud 中有一個(gè)組件叫 Eureka。傳說,阿基米德在洗澡時(shí)發(fā)現(xiàn)浮力原理,高興得來不及穿上褲子,跑到街上大喊:“Eureka(我找到了)!”所以 Eureka 是用來實(shí)現(xiàn)注冊(cè)中心的,負(fù)責(zé)維護(hù)注冊(cè)的服務(wù)列表。
????服務(wù)分服務(wù)提供方,它向 Eureka 做服務(wù)注冊(cè)、續(xù)約和下線等操作,注冊(cè)的主要數(shù)據(jù)包括服務(wù)名、機(jī)器 IP、端口號(hào)、域名等等。
????另外一方是服務(wù)消費(fèi)方,向 Eureka 獲取服務(wù)提供方的注冊(cè)信息。為了實(shí)現(xiàn)負(fù)載均衡和容錯(cuò),服務(wù)提供方可以注冊(cè)多個(gè)。
????當(dāng)消費(fèi)方要調(diào)用服務(wù)的時(shí)候,會(huì)從注冊(cè)中心讀出多個(gè)服務(wù)來,那怎么調(diào)用呢?當(dāng)然是 RESTful 方式了。
????Spring Cloud 提供一個(gè) RestTemplate 工具,用于將請(qǐng)求對(duì)象轉(zhuǎn)換為 JSON,并發(fā)起 Rest 調(diào)用,RestTemplate 的調(diào)用也是分 POST、PUT、GET、 DELETE 的,當(dāng)結(jié)果返回的時(shí)候,根據(jù)返回的 JSON 解析成對(duì)象。
????通過這樣封裝,調(diào)用起來也很方便。
小結(jié)SOAP 過于復(fù)雜,而且設(shè)計(jì)是面向動(dòng)作的,因而往往因?yàn)榧軜?gòu)問題導(dǎo)致并發(fā)量上不去;
RESTful 不僅僅是一個(gè) API,而且是一種架構(gòu)模式,主要面向資源,提供無狀態(tài)服務(wù),有利于橫向擴(kuò)展應(yīng)對(duì)高并發(fā)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/29948.html
摘要:服務(wù)發(fā)現(xiàn)問題對(duì)于來講,我們已經(jīng)解決了傳輸協(xié)議的問題基于,協(xié)議約定問題基于,最后要解決的是服務(wù)發(fā)現(xiàn)問題。另外一方是服務(wù)消費(fèi)方,向獲取服務(wù)提供方的注冊(cè)信息。 ????上一節(jié)我們了解了基于 XML 的 SOAP 協(xié)議,SOAP 的 S 是啥意思來著?是 Simple,但是好像一點(diǎn)兒都不簡(jiǎn)單??! 傳輸協(xié)議問題 ????對(duì)于 SOAP 來講,比如我創(chuàng)建一個(gè)訂單,用 POST,在 XML 里面寫明...
摘要:但是只不過都是以二進(jìn)制的形式編碼的。這其實(shí)相當(dāng)于綜合了和二進(jìn)制共同優(yōu)勢(shì)的一個(gè)協(xié)議。在上面的架構(gòu)中,如果使用二進(jìn)制的方式進(jìn)行序列化,雖然不用協(xié)議文件來生成,但是對(duì)于接口的定義,以及傳的對(duì)象,還是需要共享。 ????前面我們認(rèn)識(shí)了兩個(gè)常用文本類的 RPC 協(xié)議,對(duì)于陌生人之間的溝通,用 NBA、CBA 這樣的縮略語,會(huì)使得協(xié)議約定非常不方便。 ????在講 CDN 和 DNS 的時(shí)候,我們...
摘要:但是只不過都是以二進(jìn)制的形式編碼的。這其實(shí)相當(dāng)于綜合了和二進(jìn)制共同優(yōu)勢(shì)的一個(gè)協(xié)議。在上面的架構(gòu)中,如果使用二進(jìn)制的方式進(jìn)行序列化,雖然不用協(xié)議文件來生成,但是對(duì)于接口的定義,以及傳的對(duì)象,還是需要共享。 ????前面我們認(rèn)識(shí)了兩個(gè)常用文本類的 RPC 協(xié)議,對(duì)于陌生人之間的溝通,用 NBA、CBA 這樣的縮略語,會(huì)使得協(xié)議約定非常不方便。 ????在講 CDN 和 DNS 的時(shí)候,我們...
摘要:對(duì)于與而言,則可以看做是消息傳遞技術(shù)的一種衍生或封裝。在生產(chǎn)者通知消費(fèi)者時(shí),傳遞的往往是消息或事件,而非生產(chǎn)者自身。通過消息路由,我們可以配置路由規(guī)則指定消息傳遞的路徑,以及指定具體的消費(fèi)者消費(fèi)對(duì)應(yīng)的生產(chǎn)者。采用和來進(jìn)行遠(yuǎn)程對(duì)象的通訊。 消息模式 歸根結(jié)底,企業(yè)應(yīng)用系統(tǒng)就是對(duì)數(shù)據(jù)的處理,而對(duì)于一個(gè)擁有多個(gè)子系統(tǒng)的企業(yè)應(yīng)用系統(tǒng)而言,它的基礎(chǔ)支撐無疑就是對(duì)消息的處理。與對(duì)象不同,消息本質(zhì)上...
摘要:微軟的雖然引入了事件機(jī)制,可以在隊(duì)列收到消息時(shí)觸發(fā)事件,通知訂閱者。由微軟作為主要貢獻(xiàn)者的,則對(duì)以及做了進(jìn)一層包裝,并能夠很好地實(shí)現(xiàn)這一模式。 在分布式服務(wù)框架中,一個(gè)最基礎(chǔ)的問題就是遠(yuǎn)程服務(wù)是怎么通訊的,在Java領(lǐng)域中有很多可實(shí)現(xiàn)遠(yuǎn)程通訊的技術(shù),例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,這些名詞之間到底是些什么關(guān)系呢,它們背后到底是基...
閱讀 2542·2021-10-11 10:58
閱讀 1020·2019-08-29 13:58
閱讀 1661·2019-08-26 13:32
閱讀 830·2019-08-26 10:40
閱讀 3256·2019-08-26 10:18
閱讀 1756·2019-08-23 14:18
閱讀 1106·2019-08-23 10:54
閱讀 435·2019-08-22 18:39