在 gRPC 里客戶端應用可以像調用本地對象一樣直接調用另一臺不同的機器上服務端 應用的方法,使得您能夠更容易地創(chuàng)建分布式應用和服務。與許多 RPC 系統(tǒng)類似,gRPC 也是基于以下理念:定義一個服務,指定其能夠被遠程調用的方法(包含參數(shù)和返回類型)。在服務端實現(xiàn)這個接口,并運行一個 gRPC 服務器來處理客戶端調用。在客戶端擁有一個存根能夠像服務端一樣的方法。
網(wǎng)站設計制作、成都網(wǎng)站制作的關注點不是能為您做些什么網(wǎng)站,而是怎么做網(wǎng)站,有沒有做好網(wǎng)站,給成都創(chuàng)新互聯(lián)一個展示的機會來證明自己,這并不會花費您太多時間,或許會給您帶來新的靈感和驚喜。面向用戶友好,注重用戶體驗,一切以用戶為中心。
gRPC 客戶端和服務端可以在多種環(huán)境中運行和交互 - 從 google 內(nèi)部的服務器到你自己的筆記本,并且可以用任何 gRPC 支持的語言來編寫。所以,你可以很容易地用 Java 創(chuàng)建一個 gRPC 服務端,用 Go、Python、Ruby 來創(chuàng)建客戶端。此外,Google 最新 API 將有 gRPC 版本的接口,使你很容易地將 Google 的功能集成到你的應用里。
gRPC 默認使用 protocol buffers,這是 Google 開源的一套成熟的結構數(shù)據(jù)序列化機制(當然也可以使用其他數(shù)據(jù)格式如 JSON)。名叫 proto3 的新風格的 protocol buffers,它擁有輕量簡化的語法、一些有用的新功能,并且支持更多新語言。當前針對 Java 和 C++ 發(fā)布了 beta 版本,針對 JavaNano(即 Android Java)發(fā)布 alpha 版本,在protocol buffers Github 源碼庫里有 Ruby 支持, 在golang/protobuf Github 源碼庫里還有針對 Go 語言的生成器, 對更多語言的支持正在開發(fā)中。
有了 gRPC, 我們可以一次性的在一個 .proto 文件中定義服務并使用任何支持它的語言去實現(xiàn)客戶端和服務器,反過來,它們可以在各種環(huán)境中,從Google的服務器到你自己的平板電腦—— gRPC 幫你解決了不同語言及環(huán)境間通信的復雜性.使用 protocol buffers 還能獲得其他好處,包括高效的序列號,簡單的 IDL 以及容易進行接口更新。
現(xiàn)在讓我們來仔細了解一下當 gRPC 客戶端調用 gRPC 服務端的方法時到底發(fā)生了什么。我們不究其實現(xiàn)細節(jié),關于實現(xiàn)細節(jié)的部分,你可以在我們的特定語言頁面里找到更為詳盡的內(nèi)容。
首先我們來了解一下最簡單的 RPC 形式:客戶端發(fā)出單個請求,獲得單個響應。
服務端流式 RPC 除了在得到客戶端請求信息后發(fā)送回一個應答流之外,與我們的簡單例子一樣。在發(fā)送完所有應答后,服務端的狀態(tài)詳情(狀態(tài)碼和可選的狀態(tài)信息)和可選的跟蹤元數(shù)據(jù)被發(fā)送回客戶端,以此來完成服務端的工作??蛻舳嗽诮邮盏剿蟹斩说膽鸷笠餐瓿闪斯ぷ?。
客戶端流式 RPC 也基本與我們的簡單例子一樣,區(qū)別在于客戶端通過發(fā)送一個請求流給服務端,取代了原先發(fā)送的單個請求。服務端通常(但并不必須)會在接收到客戶端所有的請求后發(fā)送回一個應答,其中附帶有它的狀態(tài)詳情和可選的跟蹤數(shù)據(jù)。
雙向流式 RPC ,調用由客戶端調用方法來初始化,而服務端則接收到客戶端的元數(shù)據(jù),方法名和截止時間。服務端可以選擇發(fā)送回它的初始元數(shù)據(jù)或等待客戶端發(fā)送請求。 下一步怎樣發(fā)展取決于應用,因為客戶端和服務端能在任意順序上讀寫 - 這些流的操作是完全獨立的。例如服務端可以一直等直到它接收到所有客戶端的消息才寫應答,或者服務端和客戶端可以像"乒乓球"一樣:服務端后得到一個請求就回送一個應答,接著客戶端根據(jù)應答來發(fā)送另一個請求,以此類推。
通過運行下面的命令克隆并安裝grpc-go代碼庫:
下載protobuf源碼包
安裝golang-protobuf
第一步使用 protocol buffers去定義 gRPC service 和方法 request 以及 response 的類型。
要定義一個服務,必須在.proto 文件中指定 service:
然后在服務中定義 rpc 方法,指定請求的和響應類型,gRPC 允許定義4種類型的 service 方法。
服務.proto文件如下所示:
rpc調用原理框架如圖:
-支持多語言的rpc框架,例如Google的grpc,facebook thrift, 百度的brpc
-支持特定語言的rpc框架, 例如新浪微博的Motan
-支持服務治理微服務化特性框架,其底層仍是rpc框架,例如 阿里的Dubbo
目前業(yè)內(nèi)主要使用基于多語言的 RPC 框架來構建微服務,是一種比較好的技術選擇,例如netflix ,API服務編排層和后端微服務之間采用微服務rpc進行通信
-支持C java js
-git地址
-原理圖:
gRPC 的線程模型遵循 Netty 的線程分工原則,即:協(xié)議層消息的接收和編解碼由 Netty 的 I/O(NioEventLoop) 線程負責;后續(xù)應用層的處理由應用線程負責,防止由于應用處理耗時而阻塞 Netty 的 I/O 線程
不過正是因為有了分工原則,grpc 之間會做頻繁的線程切換,如果在一次grpc調用過程中,做了多次I/O線程到應用線程之間的切換,會導致性能的下降,這也是為什么grpc在一些私有協(xié)議支持不太友好的原因
缺點
改進:
優(yōu)化后BIO線程模型采用了線程池的做法但是后端的應用處理線程仍然采用同步阻塞的模型,阻塞的時間取決對方I/O處理的速度和網(wǎng)絡I/O傳輸?shù)乃俣?/p>
grpc的線程模型主要包含服務端線程模型,客戶端線程模型
2.1.1 I/O 通信線程模型
gRPC的做法是服務監(jiān)聽線程和I/O線程分離Reactor多個線程模型 其工作原理如下:
2.1.2 服務調度線程模型
gRPC 客戶端線程模型工作原理如下圖所示(同步阻塞調用為例)
相比于服務端,客戶端的線程模型簡單一些,它的工作原理如下:
grpc 線程模型
RPC(Remote Procedure Call,即遠程過程調用)是建立在Socket之上的,在一臺機器上運行的主程序,可以調用另一臺機器上準備好的子程序,就像LPC(本地過程調用)。也就是說兩臺服務器A,B,一個應用部署在A服務器上,想要調用B服務器上應用提供的函數(shù)/方法。
由于不在一個內(nèi)存空間,不能直接調用,需要通過網(wǎng)絡來表達調用的語義和傳達調用的數(shù)據(jù)。對于RPC架構來說,應用越底層,代碼越復雜、靈活性越高、效率越高;應用越上層,抽象封裝的越好、代碼越簡單、效率越差。
RPC 框架注意事項
RPC 的調用通常為了方便使用,會被偽裝成普通方法調用的形式。但實際二者之間存在巨大的差異,進程內(nèi)的方法調用的時間量級是 ns(納秒),而進程間的 RPC 方法調用時間量級通常是 ms(毫秒),它們之間差著 10 的六次方。
因此,微服務架構下,內(nèi)部主服務鏈之間的 RPC 調用需要異步化,服務之間的調用請求和等待結果相互之間解耦。
降級功能基本是rpc框架的標配了,不過對比了一些rpc框架,發(fā)現(xiàn)實現(xiàn)方式還是挺不一樣的。
osp是提供了一個配置,如果配置服務為降級,那個這個服務的server端收到請求,直接返回一個降級對應的錯誤碼,client收到這個結果后,可以根據(jù)這個錯誤碼做處理,比如返回一些固定數(shù)據(jù)之類的。
優(yōu)點:
1 降級配置方式非常靈活,可以根據(jù)請求來源配置是否降級。
2 能非??焖俜奖闾幚硪恍﹫鼍埃罕热缥ㄆ窌蟠俚臅r候,把商品評論服務設置為降級,這樣就可以方便的關閉掉商品評論功能了。
3 不同的調用方可以根據(jù)降級錯誤碼來做不同的事情,非常的靈活。
缺點:
1 降級了的服務,還是會收到client的請求,對client和server還是有些壓力
sofa沒有看到明確的降級功能。
只是提供了自動故障剔除功能,但是這個功能只是修改server的流量權重,叫他為熔斷更加貼切。
dubbo提供了一個mock功能,如果server返回異常的情況下,可以用mock數(shù)據(jù)替代。
近幾年誕生了很多微服務框架,比如JAVA的Spring Cloud、Dubbo;Golang的GoKit和GoMicro以及NodeJs的Seneca。幾乎每種主流語言都有其對應的微服務框架。
Go在微服務框架中有其獨特的優(yōu)勢,至于優(yōu)勢在哪,自行google。
1、GoKit框架
這是一個工具包的集合,可以幫助攻城獅構建強大、可靠和可維護的微服務。提供了用于實現(xiàn)系統(tǒng)監(jiān)控和彈性模式組件的庫,例如日志、跟蹤、限流、熔斷等。
基于這個框架的應用程序架構由三個主要的部分組成:
傳輸層:用于網(wǎng)絡通信,服務通常使用HTTP或者gRPC等網(wǎng)絡傳輸協(xié)議,或者使用NATS等發(fā)布訂閱系統(tǒng)相互通信。
接口層:是服務器和客戶端的基本構建塊。每個對外提供的接口方法都會定義為一個Endpoint,一遍在服務器和客戶端之間進行網(wǎng)絡通信,每個端點使用傳輸層通過HTTP或gRPC等具體通信模式對外提供服務
服務成:具體的業(yè)務邏輯實現(xiàn)
2、GoMicro框架
這是一個基于Go語言實現(xiàn)的插件化RPC微服務框架。提供了服務發(fā)現(xiàn)、負載均衡、同步傳輸、異步通信以及事件驅動等機制,嘗試簡化分布式系統(tǒng)之間的通信,讓開發(fā)者更專注于自身業(yè)務邏輯的開發(fā)。
GoMicro的設計哲學是可插拔的架構理念,提供了可快速構建系統(tǒng)的組件,并且可以根據(jù)自身的需求對GoMicro提供的默認實現(xiàn)進行定制。所有插件都可在倉庫github.com/micro/go-plugins 中找到。
RPC是遠程過程調用的簡稱,廣泛應用在大規(guī)模分布式應用中,作用是有助于系統(tǒng)的垂直拆分,使系統(tǒng)更易拓展。Java中的RPC框架比較多,各有特色,廣泛使用的有RMI、Hessian、Dubbo等。RPC還有一個特點就是能夠跨語言。
1、RMI(遠程方法調用)
JAVA自帶的遠程方法調用工具,不過有一定的局限性,畢竟是JAVA語言最開始時的設計,后來很多框架的原理都基于RMI,RMI的使用如下:
對外接口
span?style="font-size:12px;"public?interface?IService?extends?Remote?{??
public?String?queryName(String?no)?throws?RemoteException;??
}/span
服務實現(xiàn)
import?java.rmi.RemoteException;??
import?java.rmi.server.UnicastRemoteObject;??
//?服務實現(xiàn)??
public?class?ServiceImpl?extends?UnicastRemoteObject?implements?IService?{??
/**?
*/??
private?static?final?long?serialVersionUID?=?682805210518738166L;??
/**?
*?@throws?RemoteException?
*/??
protected?ServiceImpl()?throws?RemoteException?{??
super();??
}??
/*?(non-Javadoc)?
*?@see?com.suning.ebuy.wd.web.IService#queryName(java.lang.String)?
*/??
@Override??
public?String?queryName(String?no)?throws?RemoteException?{??
//?方法的具體實現(xiàn)??
System.out.println("hello"?+?no);??
return?String.valueOf(System.currentTimeMillis());??
}??
}??
RMI客戶端
[java]?view?plain?copy
import?java.rmi.AccessException;??
import?java.rmi.NotBoundException;??
import?java.rmi.RemoteException;??
import?java.rmi.registry.LocateRegistry;??
import?java.rmi.registry.Registry;??
//?RMI客戶端??
public?class?Client?{??
public?static?void?main(String[]?args)?{??
//?注冊管理器??
Registry?registry?=?null;??
try?{??
//?獲取服務注冊管理器??
registry?=?LocateRegistry.getRegistry("127.0.0.1",8088);??
//?列出所有注冊的服務??
String[]?list?=?registry.list();??
for(String?s?:?list){??
System.out.println(s);??
}??
}?catch?(RemoteException?e)?{??
}??
try?{??
//?根據(jù)命名獲取服務??
IService?server?=?(IService)?registry.lookup("vince");??
//?調用遠程方法??
String?result?=?server.queryName("ha?ha?ha?ha");??
//?輸出調用結果??
System.out.println("result?from?remote?:?"?+?result);??
}?catch?(AccessException?e)?{??
}?catch?(RemoteException?e)?{??
}?catch?(NotBoundException?e)?{??
}??
}??
}??
RMI服務端
[java]?view?plain?copy
import?java.rmi.RemoteException;??
import?java.rmi.registry.LocateRegistry;??
import?java.rmi.registry.Registry;??
//?RMI服務端??
public?class?Server?{??
public?static?void?main(String[]?args)?{??
//?注冊管理器??
Registry?registry?=?null;??
try?{??
//?創(chuàng)建一個服務注冊管理器??
registry?=?LocateRegistry.createRegistry(8088);??
}?catch?(RemoteException?e)?{??
}??
try?{??
//?創(chuàng)建一個服務??
ServiceImpl?server?=?new?ServiceImpl();??
//?將服務綁定命名??
registry.rebind("vince",?server);??
System.out.println("bind?server");??
}?catch?(RemoteException?e)?{??
}??
}??
}
2、Hessian(基于HTTP的遠程方法調用)
基于HTTP協(xié)議傳輸,在性能方面還不夠完美,負載均衡和失效轉移依賴于應用的負載均衡器,Hessian的使用則與RMI類似,區(qū)別在于淡化了Registry的角色,通過顯示的地址調用,利用HessianProxyFactory根據(jù)配置的地址create一個代理對象,另外還要引入Hessian的Jar包。
3、Dubbo(淘寶開源的基于TCP的RPC框架)
基于Netty的高性能RPC框架,是阿里巴巴開源的,總體原理如下: