自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

微服務(wù)與RPC

開發(fā) 開發(fā)工具
在支付系統(tǒng)的微服務(wù)架構(gòu)中,基礎(chǔ)服務(wù)的構(gòu)建是重中之重, 本文重點分析如何使用Apache Thrift + Google Protocol Buffer來構(gòu)建基礎(chǔ)服務(wù)。

在支付系統(tǒng)的微服務(wù)架構(gòu)中,基礎(chǔ)服務(wù)的構(gòu)建是重中之重, 本文重點分析如何使用Apache Thrift + Google Protocol Buffer來構(gòu)建基礎(chǔ)服務(wù)。

一、RPC vs Restful

在微服務(wù)中,使用什么協(xié)議來構(gòu)建服務(wù)體系,一直是個熱門話題。 爭論的焦點集中在兩個候選技術(shù): (binary) RPC or Restful。

以Apache Thrift為代表的二進制RPC,支持多種語言(但不是所有語言),四層通訊協(xié)議,性能高,節(jié)省帶寬。相對Restful協(xié)議,使用Thrifpt RPC,在同等硬件條件下,帶寬使用率僅為前者的20%,性能卻提升一個數(shù)量級。但是這種協(xié)議***的問題在于,無法穿透防火墻。

以Spring Cloud為代表所支持的Restful 協(xié)議,優(yōu)勢在于能夠穿透防火墻,使用方便,語言無關(guān),基本上可以使用各種開發(fā)語言實現(xiàn)的系統(tǒng),都可以接受Restful 的請求。 但性能和帶寬占用上有劣勢。

所以,業(yè)內(nèi)對微服務(wù)的實現(xiàn),基本是確定一個組織邊界,在該邊界內(nèi),使用RPC; 邊界外,使用Restful。這個邊界,可以是業(yè)務(wù)、部門,甚至是全公司。

二、 RPC技術(shù)選型

RPC技術(shù)選型上,原則也是選擇自己熟悉的,或者公司內(nèi)部內(nèi)定的框架。 如果是新業(yè)務(wù),則現(xiàn)在可選的框架其實也不多,卻也足夠讓人糾結(jié)。

Apache Thrift

國外用的多,源于facebook,后捐獻給Apache基金。是Apache的***項目 Apache Thrift。使用者包括facebook, Evernote, Uber, Pinterest等大型互聯(lián)網(wǎng)公司。 而在開源界,Apache hadoop/hbase也在使用Thrift作為內(nèi)部通訊協(xié)議。 這是目前最為成熟的框架,優(yōu)點在于穩(wěn)定、高性能。缺點在于它僅提供RPC服務(wù),其他的功能,包括限流、熔斷、服務(wù)治理等,都需要自己實現(xiàn),或者使用第三方軟件。

Dubbo

國內(nèi)用的多,源于阿里公司。 性能上略遜于Apache Thrift,但自身集成了大量的微服務(wù)治理功能,使用起來相當方便。 Dubbo的問題在于,該系統(tǒng)目前已經(jīng)很長時間沒有維護更新了。 官網(wǎng)顯示最近一次的更新也是8個月前。

Google Protobuf

和Apache Thrift類似,Google Protobuf也包括數(shù)據(jù)定義和服務(wù)定義兩部分。問題是,Google Protobuf一直只有數(shù)據(jù)模型的實現(xiàn),沒有官方的RPC服務(wù)的實現(xiàn)。 直到2015年才推出gRPC,作為RPC服務(wù)的官方實現(xiàn)。但缺乏重量級的用戶。

以上僅做定性比較。定量的對比,網(wǎng)上有不少資料,可自行查閱。 此外,還有一些不錯的RPC框架,比如Zeroc ICE等,不在本文的比較范圍。

Thrift 提供多種高性能的傳輸協(xié)議,但在數(shù)據(jù)定義上,不如Protobuf強大。

  1. 同等格式數(shù)據(jù), Protobuf壓縮率和序列化/反序列化性能都略高。
  2. Protobuf支持對數(shù)據(jù)進行自定義標注,并可以通過API來訪問這些標注,這使得Protobuf在數(shù)據(jù)操控上非常靈活。比如可以通過option來定義protobuf定義的屬性和數(shù)據(jù)庫列的映射關(guān)系,實現(xiàn)數(shù)據(jù)存取。
  3. 數(shù)據(jù)結(jié)構(gòu)升級是常見的需求,Protobuf在支持數(shù)據(jù)向下兼容上做的非常不錯。只要實現(xiàn)上處理得當,接口在升級時,老版本的用戶不會受到影響。

而Protobuf的劣勢在于其RPC服務(wù)的實現(xiàn)性能不佳(gRPC)。為此,Apache Thrift + Protobuf的RPC實現(xiàn),成為不少公司的選擇。

三、Apache Thrift + Protobuf

如上所述,利用Protobuf在靈活數(shù)據(jù)定義、高性能的序列化/反序列化、兼容性上的優(yōu)勢,以及Thrift在傳輸上的成熟實現(xiàn),將兩者結(jié)合起來使用,是不少互聯(lián)網(wǎng)公司的選擇。

服務(wù)定義:

  1.  service HelloService{ 
  2.     binary hello(1: binary hello_request); 
  3.  } 
  4. 協(xié)議定義: 
  5.  
  6. message HelloRequest{ 
  7.   optional string user_name = 1; //訪問這個接口的用戶 
  8.   optional string password = 2; //訪問這個接口的密碼 
  9.   optional string hello_word = 3; //其他參數(shù); 
  10.  
  11.  
  12. message HelloResponse{ 
  13.   optional string hello_word = 1; //訪問這個接口的用戶 

想對于純的thrift實現(xiàn),這種方式雖然看起來繁瑣,但其在可擴展性、可維護性和服務(wù)治理上,可以帶來不少便利。

四、服務(wù)注冊與發(fā)現(xiàn)

Spring cloud提供了服務(wù)注冊和發(fā)現(xiàn)功能,如果需要自己實現(xiàn),可以考慮使用Apache Zookeeper作為注冊表,使用Apache Curator 來管理Zookeeper的鏈接,它實現(xiàn)如下功能:

  • 偵聽注冊表項的變化,一旦有更新,可以重新加載注冊表。
  • 管理到zookeeper的鏈接,如果出現(xiàn)問題,則進行重試。

Curator的重試策略是可配置的,提供如下策略:

  • BoundedExponentialBackoffRetry
  • ExponentialBackoffRetry
  • RetryForever
  • RetryNTimes
  • RetryOneTime
  • RetryUntilElapsed

一般使用指數(shù)延遲策略,比如重試時間間隔為1s,2s, 4s, 8s……指數(shù)增加,避免把服務(wù)器打死。

對服務(wù)注冊來說,注冊表結(jié)構(gòu)需要詳細設(shè)計,一般注冊表結(jié)構(gòu)會按照如下方式組織:

機房區(qū)域-部門-服務(wù)類型-服務(wù)名稱-服務(wù)器地址

由于在zookeeper上的注冊和發(fā)現(xiàn)有一定的延遲,所以在實現(xiàn)上也得注意,當服務(wù)啟動成功后,才能注冊到zookeeper上;當服務(wù)要下線或者重啟前,需要先斷開同zookeeper的連接,再停止服務(wù)。

五、連接池

RPC服務(wù)訪問和數(shù)據(jù)庫類似,建立鏈接是一個耗時的過程,連接池是服務(wù)調(diào)用的標配。目前還沒有成熟的開源Apache Thrift鏈接池,一般互聯(lián)網(wǎng)公司都會開發(fā)內(nèi)部自用的鏈接池。自己實現(xiàn)可以基于JDBC鏈接池做改進,比如參考Apache commons DBCP鏈接池,使用Apache Pools來管理鏈接。 在接口設(shè)計上,連接池需要管理的是RPC 的Transport:

  1. public interface TransportPool { 
  2.   /** 
  3.   * 獲取一個transport 
  4.   * @return 
  5.   * @throws TException 
  6.   */ 
  7.   public TTransport getTransport() throws TException;} 

連接池實現(xiàn)的主要難點在于如何從多個服務(wù)器中選舉出來為當前調(diào)用提供服務(wù)的連接。比如目前有10臺機器在提供服務(wù),上一次分配的是第4臺服務(wù)器,本次應(yīng)該分配哪一臺?在實現(xiàn)上,需要收集每臺機器的QOS以及當前的負擔,分配一個***的連接。

六、API網(wǎng)關(guān)

隨著公司業(yè)務(wù)的增長,RPC服務(wù)越來越多,這也為服務(wù)調(diào)用帶來挑戰(zhàn)。如果有一個應(yīng)用需要調(diào)用多個服務(wù),對這個應(yīng)用來說,就需要維護和多個服務(wù)器之間的鏈接。服務(wù)的重啟,都會對連接池以及客戶端的訪問帶來影響。為此,在微服務(wù)中,廣泛會使用到API網(wǎng)關(guān)。API網(wǎng)關(guān)可以認為是一系列服務(wù)集合的訪問入口。從面向?qū)ο笤O(shè)計的角度看,它與外觀模式類似,實現(xiàn)對所提供服務(wù)的封裝。

網(wǎng)關(guān)作用

API網(wǎng)關(guān)本身不提供服務(wù)的具體實現(xiàn),它根據(jù)請求,將服務(wù)分發(fā)到具體的實現(xiàn)上。 其主要作用:

  • API路由: 接受到請求時,將請求轉(zhuǎn)發(fā)到具體實現(xiàn)的worker機器上。避免使用方建立大量的連接。
  • 協(xié)議轉(zhuǎn)換: 原API可能使用http或者其他的協(xié)議來實現(xiàn)的,統(tǒng)一封裝為rpc協(xié)議。注意,這里的轉(zhuǎn)換,是批量轉(zhuǎn)換。也就是說,原來這一組的API是使用http實現(xiàn)的,現(xiàn)在要轉(zhuǎn)換為RPC,于是引入網(wǎng)關(guān)來統(tǒng)一處理。對于單個服務(wù)的轉(zhuǎn)換,還是單獨開發(fā)一個Adapter服務(wù)來執(zhí)行。
  • 封裝公共功能: 將微服務(wù)治理相關(guān)功能封裝到網(wǎng)關(guān)上,簡化微服務(wù)的開發(fā),這包括熔斷、限流、身份驗證、監(jiān)控、負載均衡、緩存等。
  • 分流:通過控制API網(wǎng)關(guān)的分發(fā)策略,可以很容易實現(xiàn)訪問的分流,這在灰度測試和AB測試時特別有用。

解耦合

RPC API網(wǎng)關(guān)在實現(xiàn)上,難點在于如何做到服務(wù)無關(guān)。我們知道使用Nginx實現(xiàn)HTTP的路由網(wǎng)關(guān),可以實現(xiàn)和服務(wù)無關(guān)。而RPC網(wǎng)關(guān)由于實現(xiàn)上的不規(guī)范,很難實現(xiàn)和服務(wù)無關(guān)。統(tǒng)一使用thrift + protobuf 來開發(fā)RPC服務(wù)可以簡化API網(wǎng)關(guān)的開發(fā),避免為每個服務(wù)上線而帶來的網(wǎng)關(guān)的調(diào)整,使得網(wǎng)關(guān)和具體的服務(wù)解耦合:

  • 每個服務(wù)實現(xiàn)的worker機器將服務(wù)注冊到zookeeper上;
  • API網(wǎng)關(guān)接收到zookeeper的變更,更新本地的路由表,記錄服務(wù)和worker(連接池)的映射關(guān)系。
  • 當請求被提交到網(wǎng)關(guān)上時,網(wǎng)關(guān)可以從rpc請求中提取出服務(wù)名稱,之后根據(jù)這個名稱,找到對應(yīng)的worker機(連接池),調(diào)用該worker上的服務(wù),接受到結(jié)果后,將結(jié)果返回給調(diào)用方。

權(quán)限和其他

Protobuf的一個重要特性是,數(shù)據(jù)的序列化和名稱無關(guān),只和屬性類型、編號有關(guān)。 這種方式,間接實現(xiàn)了類的繼承關(guān)系。如下所示,我們可以通過Person類來解析Girl和Boy的反序列化流:

  1. message Person { 
  2.   optional string user_name = 1;  
  3.   optional string password = 2; }message Girl { 
  4.   optional string user_name = 1;  
  5.   optional string password = 2;  
  6.   optional string favorite_toys = 3; }message Boy { 
  7.   optional string user_name = 1;  
  8.   optional string password = 2;  
  9.   optional int32  favorite_club_count = 3;  
  10.   optional string favorite_sports = 4; } 

我們只要對服務(wù)的輸入?yún)?shù)做合理的編排,將常用的屬性使用固定的編號來表示,既可以使用通用的基礎(chǔ)類來解析輸入?yún)?shù)。比如我們要求所有輸入的***個和第二個元素必須是user_name和password,則我們就可以使用Person來解析這個輸入,從而可以實現(xiàn)對服務(wù)的統(tǒng)一身份驗證,并基于驗證結(jié)果來實施QPS控制等工作。

七、熔斷與限流

Netflix Hystrix提供不錯的熔斷和限流的實現(xiàn),參考其在GitHub上的項目介紹。這里簡單說下熔斷和限流實現(xiàn)原理。

熔斷一般采用電路熔斷器模式(Circuit Breaker Patten)。當某個服務(wù)發(fā)生錯誤,每秒錯誤次數(shù)達到閾值時,不再響應(yīng)請求,直接返回服務(wù)器忙的錯誤給調(diào)用方。 延遲一段時間后,嘗試開放50%的訪問,如果錯誤還是高,則繼續(xù)熔斷;否則恢復(fù)到正常情況。

限流指按照訪問方、IP地址或者域名等方式對服務(wù)訪問進行限制,一旦超過給定額度,則禁止其訪問。 除了使用Hystrix,如果要自己實現(xiàn),可以考慮使用使用Guava RateLimiter

八、服務(wù)演化

隨著服務(wù)訪問量的增加,服務(wù)的實現(xiàn)也會不斷演化以提升性能。主要的方法有讀寫分離、緩存等。

讀寫分離

針對實體服務(wù),讀寫分離是提升性能的***步。 實現(xiàn)讀寫分離一般有兩種方式:

在同構(gòu)數(shù)據(jù)庫上使用主從復(fù)制的方式: 一般數(shù)據(jù)庫,比如MySQL、HBase、Mongodb等,都提供主從復(fù)制功能。數(shù)據(jù)寫入主庫,讀取、檢索等操作都從從庫上執(zhí)行,實現(xiàn)讀寫分離。這種方式實現(xiàn)簡單,無需額外開發(fā)數(shù)據(jù)同步程序。一般來說,對寫入有事務(wù)要求的數(shù)據(jù)庫,在讀取上的性能會比較差。雖然可以通過增加從庫的方式來sharding請求,但這也會導(dǎo)致成本增加。

 

在異構(gòu)數(shù)據(jù)庫上進行讀寫分離。發(fā)揮不同數(shù)據(jù)庫的優(yōu)勢,通過消息機制或者其他方式,將數(shù)據(jù)從主庫同步到從庫。 比如使用MySQL作為主庫來寫入,數(shù)據(jù)寫入時投遞消息到消息服務(wù)器,同步程序接收到消息后,將數(shù)據(jù)更新到讀庫中??梢允褂肦edis,Mongodb等內(nèi)存數(shù)據(jù)庫作為讀庫,用來支持根據(jù)ID來讀取;使用Elastic作為從庫,支持搜索。

 

緩存使用

如果數(shù)據(jù)量大,使用從庫也會導(dǎo)致從庫成本非常高。對大部分數(shù)據(jù)來說,比如訂單庫,一般需要的只是一段時間,比如三個月內(nèi)的數(shù)據(jù)。更長時間的數(shù)據(jù)訪問量就非常低了。 這種情況下,沒有必要將所有數(shù)據(jù)加載到成本高昂的讀庫中,即這時候,讀庫是緩存模式。 在緩存模式下,數(shù)據(jù)更新策略是一個大問題。

  • 對于實時性要求不高的數(shù)據(jù),可以考慮采用被動更新的策略。即數(shù)據(jù)加載到緩存的時候,設(shè)置過期時間。一般內(nèi)存數(shù)據(jù)庫,包括Redis,couchbase等,都支持這個特性。到過期時間后,數(shù)據(jù)將失效,再次被訪問時,系統(tǒng)將觸發(fā)從主庫讀寫數(shù)據(jù)的流程。
  • 對實時性要求高的數(shù)據(jù),需要采用主動更新的策略,也就是接受Message后,立即更新緩存數(shù)據(jù)。

當然,在服務(wù)演化后,對原有服務(wù)的實現(xiàn)也會產(chǎn)生影響。 考慮到微服務(wù)的一個實現(xiàn)原則,即一個服務(wù)僅管一個存儲庫,原有的服務(wù)就被分裂成多個服務(wù)了。 為了保持使用方的穩(wěn)定,原有服務(wù)被重新實現(xiàn)為服務(wù)網(wǎng)關(guān),作為各個子服務(wù)的代理來提供服務(wù)。

以上是RPC與微服務(wù)的全部內(nèi)容,以下是thrift + protobuf的實現(xiàn)規(guī)范的介紹。

附一、基礎(chǔ)服務(wù)設(shè)計規(guī)范

基礎(chǔ)服務(wù)是微服務(wù)的服務(wù)棧中***層的模塊, 基礎(chǔ)服務(wù)直接和數(shù)據(jù)存儲打交道,提供數(shù)據(jù)增刪改查的基本操作。

附1.1 設(shè)計規(guī)范

文件規(guī)范

rpc接口文件名以 xxx_rpc_service.thrift 來命名; protobuf參數(shù)文件名以 xxx_service.proto 來命名。

這兩種文件全部使用UTF-8編碼。

命名規(guī)范

服務(wù)名稱以 “XXXXService” 的格式命名, XXXX是實體,必須是名詞。以下是合理的接口名稱。

  • OrderService
  • AccountService

附1.2 方法設(shè)計

由于基礎(chǔ)服務(wù)主要是解決數(shù)據(jù)讀寫問題,所以從使用的角度,對外提供的接口,可以參考數(shù)據(jù)庫操作,標準化為增、刪、改、查、統(tǒng)計等基本接口。接口采用 操作+實體來命名,如createOrder。 接口的輸入輸出參數(shù)采用 接口名+Request 和 接口名Response 的規(guī)范來命名。 這種方式使得接口易于使用和管理。

  1. file: xxx_rpc_service.thrift 
  2.  
  3. /** 
  4.  * 這里是版權(quán)申明 
  5.  **/ 
  6.  
  7. namespace java com.phoenix.service 
  8. /** 
  9.  * 提供關(guān)于XXX實體的增刪改查基本操作。 
  10. **/ 
  11. service XXXRpcService { 
  12.  
  13. /** 
  14. * 創(chuàng)建實體 
  15. * 輸入?yún)?shù): 
  16. * 1. createXXXRequest: 創(chuàng)建請求,支持創(chuàng)建多個實體; 
  17. * 輸出參數(shù) 
  18. * createXXXResponse: 創(chuàng)建成功,返回創(chuàng)建實體的ID列表; 
  19. * 異常 
  20. * 1. userException:輸入的參數(shù)有誤; 
  21. * 2. systemExeption:服務(wù)器端出錯導(dǎo)致無法創(chuàng)建; 
  22. * 3. notFoundException: 必填的參數(shù)沒有提供。 
  23. **/ 
  24. binary createXXX(1: binary create_xxx_request) throws (1: Errors.UserException userException, 2: Errors.systemException, 3: Errors.notFoundException) 
  25.  
  26. /** 
  27. * 更新實體 
  28. * 輸入?yún)?shù): 
  29. * 1. updateXXXRequest: 更新請求,支持同時更新多個實體; 
  30. * 輸出參數(shù) 
  31. * updateXXXResponse: 更新成功,返回被更行的實體的ID列表; 
  32. * 異常 
  33. * 1. userException:輸入的參數(shù)有誤; 
  34. * 2. systemExeption:服務(wù)器端出錯導(dǎo)致無法創(chuàng)建; 
  35. * 3. notFoundException: 該實體在服務(wù)器端沒有找到。 
  36. **/ 
  37. binary updateXXX(1: binary update_xxx_request) throws (1: Errors.UserException userException, 2: Errors.systemException, 3: Errors.notFoundException) 
  38.  
  39. /** 
  40. * 刪除實體 
  41. * 輸入?yún)?shù): 
  42. * 1. removeXXXRequest: 刪除請求,按照id來刪除,支持一次刪除多個實體; 
  43. * 輸出參數(shù) 
  44. * removeXXXResponse: 刪除成功,返回被刪除的實體的ID列表; 
  45. * 異常 
  46. * 1. userException:輸入的參數(shù)有誤; 
  47. * 2. systemExeption:服務(wù)器端出錯導(dǎo)致無法創(chuàng)建; 
  48. * 3. notFoundException: 該實體在服務(wù)器端沒有找到。 
  49. **/ 
  50. binary removeXXX(1: binary remove_xxx_request) throws (1: Errors.UserException userException, 2: Errors.systemException, 3: Errors.notFoundException) 
  51.  
  52. /** 
  53. * 根據(jù)ID獲取實體 
  54. * 輸入?yún)?shù): 
  55. * 1. getXXXRequest: 獲取請求,按照id來獲取,支持一次獲取多個實體; 
  56. * 輸出參數(shù) 
  57. * getXXXResponse: 返回對應(yīng)的實體列表; 
  58. * 異常 
  59. * 1. userException:輸入的參數(shù)有誤; 
  60. * 2. systemExeption:服務(wù)器端出錯導(dǎo)致無法創(chuàng)建; 
  61. * 3. notFoundException: 該實體在服務(wù)器端沒有找到。 
  62. **/ 
  63. binary getXXX(1: binary get_xxx_request) throws (1: Errors.UserException userException, 2: Errors.systemException, 3: Errors.notFoundException) 
  64.  
  65. /** 
  66. * 查詢實體 
  67. * 輸入?yún)?shù): 
  68. * 1. queryXXXRequest: 查詢條件; 
  69. * 輸出參數(shù) 
  70. * queryXXXResponse: 返回對應(yīng)的實體列表; 
  71. * 異常 
  72. * 1. userException:輸入的參數(shù)有誤; 
  73. * 2. systemExeption:服務(wù)器端出錯導(dǎo)致無法創(chuàng)建; 
  74. * 3. notFoundException: 該實體在服務(wù)器端沒有找到。 
  75. **/ 
  76. binary queryXXX(1: binary query_xxx_request) throws (1: Errors.UserException userException, 2: Errors.systemException, 3: Errors.notFoundException) 
  77.  
  78. /** 
  79. * 統(tǒng)計符合條件的實體的數(shù)量 
  80. * 輸入?yún)?shù): 
  81. * 1. countXXXRequest: 查詢條件; 
  82. * 輸出參數(shù) 
  83. * countXXXResponse: 返回對應(yīng)的實體數(shù)量; 
  84. * 異常 
  85. * 1. userException:輸入的參數(shù)有誤; 
  86. * 2. systemExeption:服務(wù)器端出錯導(dǎo)致無法創(chuàng)建; 
  87. * 3. notFoundException: 該實體在服務(wù)器端沒有找到。 
  88. **/ 
  89. binary countXXX(1: binary count_xxx_request) throws (1: Errors.UserException userException, 2: Errors.systemException, 3: Errors.notFoundException) 
  90.  

附1.3 參數(shù)設(shè)計

每個方法的輸入輸出參數(shù),采用protobuf來表示。

  1. file: xxx_service.protobuf 
  2.  
  3. /** 
  4.  * 
  5.  * 這里是版權(quán)申明 
  6. **/ 
  7.  
  8. option java_package = "com.phoenix.service"
  9. import "entity.proto"
  10. import "taglib.proto"
  11.  
  12. /** 
  13.  * 創(chuàng)建實體的請求 
  14.  * 
  15. **/ 
  16. message CreateXXXRequest { 
  17.  
  18.   optional string user_name = 1; //訪問這個接口的用戶 
  19.   optional string password = 2; //訪問這個接口的密碼 
  20.   repeated XXXX xxx = 21; // 實體內(nèi)容; 
  21.  
  22. /** 
  23.  * 創(chuàng)建實體的結(jié)果響應(yīng) 
  24.  * 
  25.  **/ 
  26. message CreateXXXResponse { 
  27.  
  28. repeated int64 id = 11;//成功創(chuàng)建的實體的ID列表 
  29. 附1.4 異常設(shè)計 
  30. RPC接口也不需要太復(fù)雜的異常,一般是定義三類異常。 
  31.  
  32. file errors.thrift 
  33.  
  34. /** 
  35.  * 由于調(diào)用方的原因引起的錯誤, 比如參數(shù)不符合規(guī)范、缺乏必要的參數(shù),沒有權(quán)限等。 
  36.  * 這種異常一般是可以重試的。 
  37.  * 
  38. **/ 
  39.  
  40. exception UserException { 
  41. 1: required ErrorCode error_code; 
  42. 2: optional string message; 
  43.  
  44. /** 
  45.  * 由于服務(wù)器端發(fā)生錯誤導(dǎo)致的,比如數(shù)據(jù)庫無法連接。這也包括QPS超過限額的情況,這時候rateLimit返回分配給的QPS上限; 
  46.  * 
  47. **/ 
  48.  
  49. exception systemException { 
  50. 1: required ErrorCode error_code; 
  51. 2: optional string message; 
  52. 3: i32 rateLimit; 
  53.  
  54. /** 
  55.  * 根據(jù)給定的ID或者其他條件無法找到對象。 
  56.  * 
  57. **/ 
  58.  
  59. exception systemException { 
  60. 1: optional string identifier; 

附二、服務(wù)SDK

當然,RPC服務(wù)不應(yīng)該直接提供給業(yè)務(wù)方使用,需要提供封裝好的客戶端。 一般來說,客戶端除了提供訪問服務(wù)端的代理外,還需要對常有功能進行封裝,這包括服務(wù)發(fā)現(xiàn)、RPC連接池、重試機制、QPS控制。這里首先介紹服務(wù)SDK的設(shè)計。 直接使用Protobuf作為輸入?yún)?shù)和輸出參數(shù),開發(fā)出來的代碼很繁瑣:

  1. GetXXXRequest.Builder request = GetXXXRequest.newBuilder(); 
  2. request.setUsername("username"); 
  3. request.setPassword("password"); 
  4. request.addId("123"); 
  5.  
  6. GetXXXResponse response = xxxService.getXXX(request.build()); 
  7. if(response.xxx.size()==1) 
  8. XXX xxx = response.xxx.get(0); 

如上,有大量的重復(fù)性代碼,使用起來不直觀也不方便。 因而需要使用客戶端SDK來做一層封裝,供業(yè)務(wù)方調(diào)用:

  1. class XXXService { 
  2. //根據(jù)ID獲取對象 
  3. public XXX getXXX(String id){ 
  4. GetXXXRequest.Builder request = GetXXXRequest.newBuilder(); 
  5. request.setUsername("username"); 
  6. request.setPassword("password"); 
  7. request.addId("123"); 
  8.  
  9. GetXXXResponse response = xxxService.getXXX(request.build()); 
  10. if(response.xxx.size()==1) 
  11. return response.xxx.get(0); 
  12. return null
  13.  

對所有服務(wù)器端接口提供對應(yīng)的客戶端SDK,也是微服務(wù)架構(gòu)***實踐之一。以此封裝完成后,調(diào)用方即可以像使用普通接口一樣,無需了解實現(xiàn)細節(jié)。

【本文為51CTO專欄作者“鳳凰牌老熊”的原創(chuàng)稿件,轉(zhuǎn)載請通過微信公眾號“鳳凰牌老熊”聯(lián)系作者本人】

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO專欄
相關(guān)推薦

2024-07-02 10:58:53

2019-08-21 08:44:52

RPC框架Java

2021-03-04 15:48:05

微服務(wù)語言開源

2022-11-11 17:09:55

微服務(wù)RPC

2020-04-10 13:04:19

微服務(wù)架構(gòu)RPC

2016-09-22 16:40:48

微服務(wù)架構(gòu)RPC-client序

2020-09-29 07:00:00

微服務(wù)API架構(gòu)

2016-09-22 16:06:21

微服務(wù)架構(gòu)RPC框架

2019-05-21 14:01:17

RPC框架Http

2019-02-21 09:18:27

服務(wù)路由負載均衡微服務(wù)

2021-12-28 08:36:55

網(wǎng)關(guān)APIRPC

2025-01-20 00:10:00

Go語言Kratos

2019-09-18 09:05:58

技術(shù)SQLDevOps

2021-01-22 17:52:01

微服務(wù)DevOps開發(fā)與運營

2018-04-09 10:06:53

微服務(wù)云計算競爭

2020-11-26 18:18:21

微服務(wù)業(yè)務(wù)規(guī)模技術(shù)

2019-12-26 15:49:14

微服務(wù)架構(gòu)業(yè)務(wù)

2020-09-08 06:48:07

微服務(wù)算法限流

2023-03-27 15:39:53

微服務(wù)架構(gòu)REST

2015-05-25 13:44:42

微服務(wù)微服務(wù)架構(gòu)Docker
點贊
收藏

51CTO技術(shù)棧公眾號