在分布式服務框架中,一個最基礎的問題就是遠程服務是怎么通訊的,在Java領域中有很多可實現(xiàn)遠程通訊的技術,例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,這些名詞之間到底是些什么關系呢,它們背后到底是基于什么原理實現(xiàn)的呢,了解這些是實現(xiàn)分布式服務框架的基礎知識,而如果在性能上有高的要求的話,那深入了解這些技術背后的機制就是必須的了。 1 基本原理要實現(xiàn)網(wǎng)絡機器間的通訊,首先得來看看計算機系統(tǒng)網(wǎng)絡通信的基本原理,在底層層面去看,網(wǎng)絡通信需要做的就是將流從一臺計算機傳輸?shù)搅硗庖慌_計算機,基于傳輸協(xié)議和網(wǎng)絡IO來實現(xiàn),其中傳輸協(xié)議比較出名的有tcp、udp等等,tcp、udp都是在基于Socket概念上為某類應用場景而擴展出的傳輸協(xié)議,網(wǎng)絡IO,主要有bio、nio、aio三種方式,所有的分布式應用通訊都基于這個原理而實現(xiàn),只是為了應用的易用,各種語言通常都會提供一些更為貼近應用易用的應用層協(xié)議。 2 消息模式歸根結底,企業(yè)應用系統(tǒng)就是對數(shù)據(jù)的處理,而對于一個擁有多個子系統(tǒng)的企業(yè)應用系統(tǒng)而言,它的基礎支撐無疑就是對消息的處理。與對象不同,消息本質上是一種數(shù)據(jù)結構(當然,對象也可以看做是一種特殊的消息),它包含消費者與服務雙方都能識別的數(shù)據(jù),這些數(shù)據(jù)需要在不同的進程(機器)之間進行傳遞,并可能會被多個完全不同的客戶端消費。消息傳遞相較文件傳遞與遠程過程調用(RPC)而言,似乎更勝一籌,因為它具有更好的平臺無關性,并能夠很好地支持并發(fā)與異步調用。 對于Web Service與RESTful而言,則可以看做是消息傳遞技術的一種衍生或封裝。 2.1 消息通道(Message Channel)模式我們常常運用的消息模式是Message Channel(消息通道)模式,如圖所示。 消息通道作為在客戶端(消費者,Consumer)與服務(生產(chǎn)者,Producer)之間引入的間接層,可以有效地解除二者之間的耦合。只要實現(xiàn)規(guī)定雙方需要通信的消息格式,以及處理消息的機制與時機,就可以做到消費者對生產(chǎn)者的“無知”。事實上,該模式可以支持多個生產(chǎn)者與消費者。例如,我們可以讓多個生產(chǎn)者向消息通道發(fā)送消息,因為消費者對生產(chǎn)者的無知性,它不必考慮究竟是哪個生產(chǎn)者發(fā)來的消息。 雖然消息通道解除了生產(chǎn)者與消費者之間的耦合,使得我們可以任意地對生產(chǎn)者與消費者進行擴展,但它又同時引入了各自對消息通道的依賴,因為它們必須知道通道資源的位置。要解除這種對通道的依賴,可以考慮引入Lookup服務來查找該通道資源。例如,在JMS中就可以通過JNDI來獲取消息通道Queue。若要做到充分的靈活性,可以將與通道相關的信息存儲到配置文件中,Lookup服務首先通過讀取配置文件來獲得通道。 消息通道通常以隊列的形式存在,這種先進先出的數(shù)據(jù)結構無疑最為適合這種處理消息的場景。微軟的MSMQ、IBM MQ、JBoss MQ以及開源的RabbitMQ、Apache ActiveMQ都通過隊列實現(xiàn)了Message Channel模式。因此,在選擇運用Message Channel模式時,更多地是要從質量屬性的層面對各種實現(xiàn)了該模式的產(chǎn)品進行全方位的分析與權衡。例如,消息通道對并發(fā)的支持以及在性能上的表現(xiàn);消息通道是否充分地考慮了錯誤處理;對消息安全的支持;以及關于消息持久化、災備(fail over)與集群等方面的支持。 因為通道傳遞的消息往往是一些重要的業(yè)務數(shù)據(jù),一旦通道成為故障點或安全性的突破點,對系統(tǒng)就會造成災難性的影響。 此處也順帶的提下jndi的機制,由于JNDI取決于具體的實現(xiàn),在這里只能是講解下jboss的jndi的實現(xiàn)了:
2.2 發(fā)布者-訂閱者(Publisher-Subscriber)模式一旦消息通道需要支持多個消費者時,就可能面臨兩種模型的選擇:拉模型與推模型。拉模型是由消息的消費者發(fā)起的,主動權把握在消費者手中,它會根據(jù)自己的情況對生產(chǎn)者發(fā)起調用。如圖所示: 拉模型的另一種體現(xiàn)則由生產(chǎn)者在狀態(tài)發(fā)生變更時,通知消費者其狀態(tài)發(fā)生了改變。但得到通知的消費者卻會以回調方式,通過調用傳遞過來的消費者對象獲取更多細節(jié)消息。 在基于消息的分布式系統(tǒng)中,拉模型的消費者通常以Batch Job的形式,根據(jù)事先設定的時間間隔,定期偵聽通道的情況。一旦發(fā)現(xiàn)有消息傳遞進來,就會轉而將消息傳遞給真正的處理器(也可以看做是消費者)處理消息,執(zhí)行相關的業(yè)務。 推模型的主動權常常掌握在生產(chǎn)者手中,消費者被動地等待生產(chǎn)者發(fā)出的通知,這就要求生產(chǎn)者必須了解消費者的相關信息。如圖所示: 對于推模型而言,消費者無需了解生產(chǎn)者。在生產(chǎn)者通知消費者時,傳遞的往往是消息(或事件),而非生產(chǎn)者自身。同時,生產(chǎn)者還可以根據(jù)不同的情況,注冊不同的消費者,又或者在封裝的通知邏輯中,根據(jù)不同的狀態(tài)變化,通知不同的消費者。 兩種模型各有優(yōu)勢。拉模型的好處在于可以進一步解除消費者對通道的依賴,通過后臺任務去定期訪問消息通道。壞處是需要引入一個單獨的服務進程,以Schedule形式執(zhí)行。而對于推模型而言,消息通道事實上會作為消費者觀察的主體,一旦發(fā)現(xiàn)消息進入,就會通知消費者執(zhí)行對消息的處理。無論推模型,拉模型,對于消息對象而言,都可能采用類似Observer模式的機制,實現(xiàn)消費者對生產(chǎn)者的訂閱,因此這種機制通常又被稱為Publisher-Subscriber模式,如圖所示: 通常情況下,發(fā)布者和訂閱者都會被注冊到用于傳播變更的基礎設施(即消息通道)上。發(fā)布者會主動地了解消息通道,使其能夠將消息發(fā)送到通道中;消息通道一旦接收到消息,會主動地調用注冊在通道中的訂閱者,進而完成對消息內容的消費。 對于訂閱者而言,有兩種處理消息的方式。一種方式是廣播機制,這時消息通道中的消息在出列的同時,還需要復制消息對象,將消息傳遞給多個訂閱者。例如,有多個子系統(tǒng)都需要獲取從CRM系統(tǒng)傳來的客戶信息,并根據(jù)傳遞過來的客戶信息,進行相應的處理。此時的消息通道又被稱為Propagation通道。另一種方式則屬于搶占機制,它遵循同步方式,在同一時間只能有一個訂閱者能夠處理該消息。實現(xiàn)Publisher-Subscriber模式的消息通道會選擇當前空閑的唯一訂閱者,并將消息出列,并傳遞給訂閱者的消息處理方法。 目前,有許多消息中間件都能夠很好地支持Publisher-Subscriber模式,例如JMS接口規(guī)約中對于Topic對象提供的MessagePublisher與MessageSubscriber接口。RabbitMQ也提供了自己對該模式的實現(xiàn)。微軟的MSMQ雖然引入了事件機制,可以在隊列收到消息時觸發(fā)事件,通知訂閱者。但它并非嚴格意義上的Publisher-Subscriber模式實現(xiàn)。由微軟MVP Udi Dahan作為主要貢獻者的NServiceBus,則對MSMQ以及WCF做了進一層包裝,并能夠很好地實現(xiàn)這一模式。 2.3 消息路由(Message Router)模式無論是Message Channel模式,還是Publisher-Subscriber模式,隊列在其中都扮演了舉足輕重的角色。然而,在企業(yè)應用系統(tǒng)中,當系統(tǒng)變得越來越復雜時,對性能的要求也會越來越高,此時對于系統(tǒng)而言,可能就需要支持同時部署多個隊列,并可能要求分布式部署不同的隊列。這些隊列可以根據(jù)定義接收不同的消息,例如訂單處理的消息,日志信息,查詢任務消息等。這時,對于消息的生產(chǎn)者和消費者而言,并不適宜承擔決定消息傳遞路徑的職責。事實上,根據(jù)S單一職責原則,這種職責分配也是不合理的,它既不利于業(yè)務邏輯的重用,也會造成生產(chǎn)者、消費者與消息隊列之間的耦合,從而影響系統(tǒng)的擴展。 既然這三種對象(組件)都不宜承擔這樣的職責,就有必要引入一個新的對象專門負責傳遞路徑選擇的功能,這就是所謂的Message Router模式,如圖所示: 通過消息路由,我們可以配置路由規(guī)則指定消息傳遞的路徑,以及指定具體的消費者消費對應的生產(chǎn)者。例如指定路由的關鍵字,并由它來綁定具體的隊列與指定的生產(chǎn)者(或消費者)。路由的支持提供了消息傳遞與處理的靈活性,也有利于提高整個系統(tǒng)的消息處理能力。同時,路由對象有效地封裝了尋找與匹配消息路徑的邏輯,就好似一個調停者(Meditator),負責協(xié)調消息、隊列與路徑尋址之間關系。 3 應用級協(xié)議遠程服務通訊,需要達到的目標是在一臺計算機發(fā)起請求,另外一臺機器在接收到請求后進行相應的處理并將結果返回給請求端,這其中又會有諸如one way request、同步請求、異步請求等等請求方式,按照網(wǎng)絡通信原理,需要實現(xiàn)這個需要做的就是將請求轉換成流,通過傳輸協(xié)議傳輸至遠端,遠端計算機在接收到請求的流后進行處理,處理完畢后將結果轉化為流,并通過傳輸協(xié)議返回給調用端。 原理是這樣的,但為了應用的方便,業(yè)界推出了很多基于此原理之上的應用級的協(xié)議,使得大家可以不用去直接操作這么底層的東西,通常應用級的遠程通信協(xié)議會提供:
所以在學習應用級的遠程通信協(xié)議時,我們可以帶著這幾個問題進行學習:
不過應用級的遠程通信協(xié)議并不會在傳輸協(xié)議上做什么多大的改進,主要是在流操作方面,讓應用層生成流和處理流的這個過程更加的貼合所使用的語言或標準,至于傳輸協(xié)議則通常都是可選的,在java領域中知名的有:RMI、XML-RPC、Binary-RPC、SOAP、CORBA、JMS、HTTP,來具體的看看這些遠程通信的應用級協(xié)議。 3.1 RMI(遠程方法調用)RMI是個典型的為java定制的遠程通信協(xié)議,我們都知道,在single vm中,我們可以通過直接調用java object instance來實現(xiàn)通信,那么在遠程通信時,如果也能按照這種方式當然是最好了,這種遠程通信的機制成為RPC(Remote Procedure Call),RMI正是朝著這個目標而誕生的。 RMI 采用stubs 和 skeletons 來進行遠程對象(remote object)的通訊。stub 充當遠程對象的客戶端代理,有著和遠程對象相同的遠程接口,遠程對象的調用實際是通過調用該對象的客戶端代理對象stub來完成的,通過該機制RMI就好比它是本地工作,采用tcp/ip協(xié)議,客戶端直接調用服務端上的一些方法。優(yōu)點是強類型,編譯期可檢查錯誤,缺點是只能基于JAVA語言,客戶機與服務器緊耦合。 來看下基于RMI的一次完整的遠程通信過程的原理:
根據(jù)原理來回答下之前學習應用級協(xié)議帶著的幾個問題:
3.2 XML-RPCRPC使用C/S方式,采用http協(xié)議,發(fā)送請求到服務器,等待服務器返回結果。這個請求包括一個參數(shù)集和一個文本集,通常形成“classname.methodname”形式。優(yōu)點是跨語言跨平臺,C端、S端有更大的獨立性,缺點是不支持對象,無法在編譯器檢查錯誤,只能在運行期檢查。 XML-RPC也是一種和RMI類似的遠程調用的協(xié)議,它和RMI的不同之處在于它以標準的xml格式來定義請求的信息(請求的對象、方法、參數(shù)等),這樣的好處是什么呢,就是在跨語言通訊的時候也可以使用。 來看下XML-RPC協(xié)議的一次遠程通信過程:
同樣來回答問題:
3.3 Binary-RPCBinary-RPC看名字就知道和XML-RPC是差不多的了,不同之處僅在于傳輸?shù)臉藴矢袷接蒟ML轉為了二進制的格式。 同樣來回答問題:
3.4 SOAPSOAP原意為Simple Object Access Protocol,是一個用于分布式環(huán)境的、輕量級的、基于XML進行信息交換的通信協(xié)議,可以認為SOAP是XML RPC的高級版,兩者的原理完全相同,都是http+XML,不同的僅在于兩者定義的XML規(guī)范不同,SOAP也是Webservice采用的服務調用協(xié)議標準,因此在此就不多加闡述了。 Web Service提供的服務是基于web容器的,底層使用http協(xié)議,類似一個遠程的服務提供者,比如天氣預報服務,對各地客戶端提供天氣預報,是一種請求應答的機制,是跨系統(tǒng)跨平臺的。就是通過一個servlet,提供服務出去。 首先客戶端從服務器獲得WebService的WSDL,同時在客戶端生成一個代理類(Proxy Class),這個代理類負責與WebService服務器進行Request和Response。當一個數(shù)據(jù)(XML格式的)被封裝成SOAP格式的數(shù)據(jù)流發(fā)送到服務器端的時候,就會生成一個進程對象并且把接收到這個Request的SOAP包進行解析,然后對事物進行處理,處理結束以后再對這個計算結果進行SOAP包裝,然后把這個包作為一個Response發(fā)送給客戶端的代理類(Proxy Class),同樣地,這個代理類也對這個SOAP包進行解析處理,繼而進行后續(xù)操作。這就是WebService的一個運行過程。 Web Service大體上分為5個層次:
3.5 JMSJMS是實現(xiàn)java領域遠程通信的一種手段和方法,基于JMS實現(xiàn)遠程通信時和RPC是不同的,雖然可以做到RPC的效果,但因為不是從協(xié)議級別定義的,因此我們不認為JMS是個RPC協(xié)議,但它確實是個遠程通信協(xié)議,在其他的語言體系中也存在著類似JMS的東西,可以統(tǒng)一的將這類機制稱為消息機制,而消息機制呢,通常是高并發(fā)、分布式領域推薦的一種通信機制,這里的主要一個問題是容錯。 JMS是Java的消息服務,JMS的客戶端之間可以通過JMS服務進行異步的消息傳輸。JMS支持兩種消息模型:Point-to-Point(P2P)和Publish/Subscribe(Pub/Sub),即點對點和發(fā)布訂閱模型。 來看JMS中的一次遠程通信的過程:
同樣來回答問題:
基于JMS也是常用的實現(xiàn)遠程異步調用的方法之一。 4 之間的區(qū)別4.1 RPC與RMI
4.2 JMS與RMI
4.3 Webservice與RMIRMI是在tcp協(xié)議上傳遞可序列化的java對象,只能用在java虛擬機上,綁定語言,客戶端和服務端都必須是java。webservice沒有這個限制,webservice是在http協(xié)議上傳遞xml文本文件,與語言和平臺無關。 4.4 Webservice與JMSWebservice專注于遠程服務調用,jms專注于信息交換。 大多數(shù)情況下Webservice是兩系統(tǒng)間的直接交互(Consumer Producer),而大多數(shù)情況下jms是三方系統(tǒng)交互(Consumer Producer)。當然,JMS也可以實現(xiàn)request-response模式的通信,只要Consumer或Producer其中一方兼任broker即可。 JMS可以做到異步調用完全隔離了客戶端和服務提供者,能夠抵御流量洪峰;WebService服務通常為同步調用,需要有復雜的對象轉換,相比SOAP,現(xiàn)在JSON,rest都是很好的http架構方案; JMS是java平臺上的消息規(guī)范。一般jms消息不是一個xml,而是一個java對象,很明顯,jms沒考慮異構系統(tǒng),說白了,JMS就沒考慮非java的東西。但是好在現(xiàn)在大多數(shù)的jms provider(就是JMS的各種實現(xiàn)產(chǎn)品)都解決了異構問題。相比WebService的跨平臺各有千秋吧。 5 可選實現(xiàn)技術目前java領域可用于實現(xiàn)遠程通訊的框架或library,知名的有:JBoss-Remoting、Spring-Remoting、Hessian、Burlap、XFire(Axis)、ActiveMQ、Mina、Mule、EJB3等等,來對每種做個簡單的介紹和評價,其實呢,要做分布式服務框架,這些東西都是要有非常深刻的了解的,因為分布式服務框架其實是包含了解決分布式領域以及應用層面領域兩方面問題的。 當然,你也可以自己根據(jù)遠程網(wǎng)絡通信原理(transport protocol+Net IO)去實現(xiàn)自己的通訊框架或library。 那么在了解這些遠程通訊的框架或library時,會帶著什么問題去學習呢?
5.1 Spring-RemotingSpring-remoting是Spring提供java領域的遠程通訊框架,基于此框架,同樣也可以很簡單的將普通的spring bean以某種遠程協(xié)議的方式來發(fā)布,同樣也可以配置spring bean為遠程調用的bean。
5.2 HessianHessian是由caucho提供的一個基于binary-RPC實現(xiàn)的遠程通訊library。
5.3 BurlapBurlap也是有caucho提供,它和hessian的不同在于,它是基于XML-RPC協(xié)議的。
5.4 XFire、AxisXFire、Axis是Webservice的實現(xiàn)框架,WebService可算是一個完整的SOA架構實現(xiàn)標準了,因此采用XFire、Axis這些也就意味著是采用webservice方式了。
5.5 ActiveMQActiveMQ是JMS的實現(xiàn),基于JMS這類消息機制實現(xiàn)遠程通訊是一種不錯的選擇,畢竟消息機制本身的功能使得基于它可以很容易的去實現(xiàn)同步/異步/單向調用等,而且消息機制從容錯角度上來說也是個不錯的選擇,這是Erlang能夠做到容錯的重要基礎。
5.6 MinaMina是Apache提供的通訊框架,在之前一直沒有提到網(wǎng)絡IO這塊,之前提及的框架或library基本都是基于BIO的,而Mina是采用NIO的,NIO在并發(fā)量增長時對比BIO而言會有明顯的性能提升,而java性能的提升,與其NIO這塊與OS的緊密結合是有不小的關系的。
MINA是NIO方式的,因此支持異步調用是毫無懸念的。 6 RPC框架的發(fā)展與現(xiàn)狀RPC(Remote Procedure Call)是一種遠程調用協(xié)議,簡單地說就是能使應用像調用本地方法一樣的調用遠程的過程或服務,可以應用在分布式服務、分布式計算、遠程服務調用等許多場景。說起 RPC 大家并不陌生,業(yè)界有很多開源的優(yōu)秀 RPC 框架,例如 Dubbo、Thrift、gRPC、Hprose 等等。下面先簡單介紹一下 RPC 與常用遠程調用方式的特點,以及一些優(yōu)秀的開源 RPC 框架。 RPC 與其它遠程調用方式比較,RPC 與 HTTP、RMI、Web Service 都能完成遠程調用,但是實現(xiàn)方式和側重點各有不同。 6.1 RPC與HTTPHTTP(HyperText Transfer Protocol)是應用層通信協(xié)議,使用標準語義訪問指定資源(圖片、接口等),網(wǎng)絡中的中轉服務器能識別協(xié)議內容。HTTP 協(xié)議是一種資源訪問協(xié)議,通過 HTTP 協(xié)議可以完成遠程請求并返回請求結果。 HTTP 的優(yōu)點是簡單、易用、可理解性強且語言無關,在遠程服務調用中包括微博有著廣泛應用。HTTP 的缺點是協(xié)議頭較重,一般請求到具體服務器的鏈路較長,可能會有 DNS 解析、Nginx 代理等。 RPC 是一種協(xié)議規(guī)范,可以把 HTTP 看作是一種 RPC 的實現(xiàn),也可以把 HTTP 作為 RPC 的傳輸協(xié)議來應用。RPC 服務的自動化程度比較高,能夠實現(xiàn)強大的服務治理功能,和語言結合更友好,性能也十分優(yōu)秀。與 HTTP 相比,RPC 的缺點就是相對復雜,學習成本稍高。 6.2 RPC與RMIRMI(Remote Method Invocation)是指 Java 語言中的遠程方法調用,RMI 中的每個方法都具有方法簽名,RMI 客戶端和服務器端通過方法簽名進行遠程方法調用。RMI 只能在 Java 語言中使用,可以把 RMI 看作面向對象的 Java RPC。 6.3 RPC與Web ServiceWeb Service 是一種基于 Web 進行服務發(fā)布、查詢、調用的架構方式,重點在于服務的管理與使用。Web Service 一般通過 WSDL 描述服務,使用 SOAP通過 HTTP 調用服務。 RPC 是一種遠程訪問協(xié)議,而 Web Service 是一種體系結構,Web Service 也可以通過 RPC 來進行服務調用,因此 Web Service 更適合同一個 RPC 框架進行比較。當 RPC 框架提供了服務的發(fā)現(xiàn)與管理,并使用 HTTP 作為傳輸協(xié)議時,其實就是 Web Service。 相對 Web Service,RPC 框架可以對服務進行更細粒度的治理,包括流量控制、SLA 管理等,在微服務化、分布式計算方面有更大的優(yōu)勢。 RPC 可基于 HTTP 或 TCP 協(xié)議,Web Service 就是基于 HTTP 協(xié)議的 RPC,它具有良好的跨平臺性,但其性能卻不如基于 TCP 協(xié)議的 RPC。會兩方面會直接影響 RPC 的性能,一是傳輸方式,二是序列化。 眾所周知,TCP 是傳輸層協(xié)議,HTTP 是應用層協(xié)議,而傳輸層較應用層更加底層,在數(shù)據(jù)傳輸方面,越底層越快,因此,在一般情況下,TCP 一定比 HTTP 快。 7 總結在遠程通訊領域中,涉及的知識點還是相當?shù)亩嗟?,例如有?strong>通信協(xié)議(Socket/tcp/http/udp/rmi/xml-rpc etc.)、消息機制、網(wǎng)絡IO(BIO/NIO/AIO)、MultiThread、本地調用與遠程調用的透明化方案(涉及Java Classloader、Dynamic Proxy、Unit Test etc.)、異步與同步調用、網(wǎng)絡通信處理機制(自動重連、廣播、異常、池處理等等)、Java Serialization (各種協(xié)議的私有序列化機制等)、各種框架的實現(xiàn)原理(傳輸格式、如何將傳輸格式轉化為流的、如何將請求信息轉化為傳輸格式的、如何接收流的、如何將流還原為傳輸格式的等等),要精通其中的哪些東西,得根據(jù)實際需求來決定了,只有在了解了原理的情況下才能很容易的做出選擇,甚至可以根據(jù)需求做私有的遠程通訊協(xié)議,對于從事分布式服務平臺或開發(fā)較大型的分布式應用的人而言,我覺得至少上面提及的知識點是需要比較了解的。 |
|