GRPC是一個高性能、通用的開源RPC框架,基於HTTP/2協議標準和Protobuf序列化協議開發,支持衆多的開發語言。html
@[TOC]java
在GRPC框架中,客戶端能夠像調用本地對象同樣直接調用位於不一樣機器的服務端方法,如此咱們就能夠很是方便的建立一些分佈式的應用服務。c++
在服務端,咱們實現了所定義的服務和可供遠程調用的方法,運行一個gRPC server來處理客戶端的請求;在客戶端,gRPC實現了一個stub(能夠簡單理解爲一個client),其提供跟服務端相同的方法。 gRPC使用protocol buffers做爲接口描述語言(IDL)以及底層的信息交換格式,通常狀況下推薦使用 proto3由於其可以支持更多的語言,並減小一些兼容性的問題。 因爲gRPC涉及到幾個比較重要的技術點http二、protobuf,正是這幾個技術點才使得gRPC獲得普遍應用,這裏也順帶講一下這幾個技術點git
HTTP/2是最新的HTTP協議,提升了資源訪問效率。經過本篇科普小文,能夠了解HTTP/2協議的概念以及優點。github
HTTP/2也被稱爲HTTP 2.0,相對於HTTP 1.1新增多路複用、壓縮HTTP頭、劃分請求優先級、服務端推送等特性,解決了在HTTP 1.1中一直存在的問題,優化了請求性能,同時兼容了HTTP 1.1的語義。算法
2015年,HTTP/2 發佈。HTTP/2是現行HTTP協議(HTTP/1.1)的替代,但它不是重寫,HTTP方法、狀態碼、語義都與HTTP/1.1同樣。HTTP/2 相比於 HTTP/1.1,能夠說是大幅度提升了網頁的性能,只須要升級到該協議就能夠減小不少以前須要作的性能優化工做。HTTP/2基於SPDY,專一於性能,最大的一個目標是在用戶和網站間只用一個鏈接(connection)。spring
HTTP/2新特性編程
HTTP/2傳輸數據量的大幅減小,主要有兩個緣由:以二進制方式傳輸和Header 壓縮。先來介紹一下二進制傳輸,HTTP/2 採用二進制格式傳輸數據,而非HTTP/1.1 裏純文本形式的報文 ,二進制協議解析起來更高效。HTTP/2 將請求和響應數據分割爲更小的幀,而且它們採用二進制編碼。HTTP/2全部性能加強的核心在於新的二進制分幀層,它定義瞭如何封裝http消息並在客戶端與服務器之間傳輸。json
HTTP/1.1的header帶有大量信息,並且每次都要重複發送,HTTP/2並無使用傳統的壓縮算法,而是開發了專門的「HPACK」算法,在客戶端和服務器兩端創建「字典」,用索引號表示重複的字符串,還採用哈夫曼編碼來壓縮整數和字符串,能夠達到50%~90%的高壓縮率。api
多路複用容許同時經過單一的HTTP/2鏈接發起多重的請求-響應信息,很好的解決了瀏覽器限制同一個域名下的請求數量的問題,同時也更容易實現全速傳輸。
HTTP2還在必定程度上改變了傳統的「請求-應答」工做模式,服務器再也不是徹底被動地響應請求,也能夠新建「流」主動向客戶端發送消息。好比,在瀏覽器剛請求HTML的時候就提早把可能會用到的JS、CSS文件發給客戶端,減小等待的延遲,這被稱爲」服務器推送」( Server Push,也叫 Cache push)。
Protocol buffers 是一種語言中立,平臺無關,可擴展的序列化數據的格式,可用於通訊協議,數據存儲等。
Protocol buffers 在序列化數據方面,它是靈活的,高效的。相比於 XML 來講,Protocol buffers 更加小巧,更加快速,更加簡單。一旦定義了要處理的數據的數據結構以後,就能夠利用 Protocol buffers 的代碼生成工具生成相關的代碼。甚至能夠在無需從新部署程序的狀況下更新數據結構。只需使用 Protobuf 對數據結構進行一次描述,便可利用各類不一樣語言或從各類不一樣數據流中對你的結構化數據輕鬆讀寫。
Protocol buffers 很適合作數據存儲或 RPC 數據交換格式。可用於通信協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。
一、性能好/效率高
時間開銷: XML格式化(序列化)的開銷還好;可是XML解析(反序列化)的開銷就不敢恭維了。 可是protobuf在這個方面就進行了優化。可使序列化和反序列化的時間開銷都減短。
空間開銷:也減小了不少
二、有代碼生成機制
好比你你寫個一下相似結構體的內容
message testA { required int32 m_testA = 1; }
像寫一個這樣的結構,protobuf能夠自動生成它的.h 文件和點.cpp文件。 protobuf將對結構體testA的操做封裝成一個類。
三、支持向後兼容和向前兼容
當客戶端和服務器同事使用一塊協議的時候, 當客戶端在協議中增長一個字節,並不會影響客戶端的使用
四、支持多種編程語言
在Google官方發佈的源代碼中包含了c++、java、Python三種語言
一、二進制格式致使可讀性差
爲了提升性能,protobuf採用了二進制格式進行編碼。這直接致使了可讀性差。這個直接影響開發測試時候的效率。固然,通常狀況下,protobuf很是可靠,並不會出現太大的問題。
二、缺少自描述
通常來講,XML是自描述的,而protobuf格式則不是。 給你一段二進制格式的協議內容,不配合你寫的結構體是看不出來什麼做用的。
三、通用性差
protobuf雖然支持了大量語言的序列化和反序列化,但仍然並非一個跨平臺和語言的傳輸標準。在多平臺消息傳遞中,對其餘項目的兼容性並非很好,須要作相應的適配改造工做。相比json 和 XML,通用性仍是沒那麼好。
protobuf處理整型特別快,若是須要了解原理能夠查看高效的數據壓縮編碼方式 Protobuf
至於與其餘序列化方式以及使用場景的對比能夠參考下面的文章 Protobuf有沒有比JSON快5倍?用代碼來擊破pb性能神話
全方位評測:Protobuf性能到底有沒有比JSON快5倍?
1,簡單模式:簡單模式只是使用參數和返回值做爲服務器與客戶端傳遞數據的方式,最簡單。
2,客戶端流模式:即從客戶端往服務器端發送數據使用的是流,即服務器端的參數爲流類型,然而在服務器相應後返還數據給客戶端,使用的也是流的send方法。通常在服務器端的代碼,須要先recv再send,而客戶端與此相反。可是在後面的雙向模式中可使用go的協程協做。
3,服務器端流模式:即服務器端返回結果的時候使用的是流模式,即傳入的數據是經過參數形式傳入的。可是在往客戶端發送數據時使用send方法,與客戶端返回數據的方式大同小異。
4,雙向模式:客戶端若是不適用協程,那麼發送必須在接收以前。若是使用協程,發送與接收並無前後順序。爲了保證協程的同步,可使用互斥量進行約束。
若是想要了解詳細demo,能夠查看gRPC 官方文檔中文版
這裏集成grpc建議有兩種方案,
這個方案就是不用編寫protobuf了,能夠直接相似dubbo同樣提供java api就能夠實現rpc調用,這裏詳情能夠參考github上的demo ttps://github.com/ChinaSilence/spring-boot-starter-grpc
facade:獨立的 Maven 模塊,依賴 spring-boot-starter-grpc
,須要遠程調用的方法,都定義在此模塊,形式能夠爲接口(interface) 或者抽象類(abstract class)
server:服務提供方,依賴 facade
模塊,需實現 facade
模塊定義的接口或者抽象類的抽象方法
client:服務調用方,依賴 facade
模塊,使用時,直接調用便可
優勢:
不須要編寫probuff文件,以java api形式來定義接口
不依賴於eureka,完美適用於k8s
缺點:
這裏內容還比較多,詳情能夠參考個人博客 springcloud集成grpc(一) 這種方式集成每次都須要編寫proto接口文件並自動生成代碼,客戶端和服務端都須要另外組裝參數。
不過優點是,有詳細的接口規範(protobuf),而且能夠支持異構語言調用。
gRPC開源組件官方並未直接提供服務註冊與發現的功能實現,但其設計文檔已提供實現的思路,並在不一樣語言的gRPC代碼API中已提供了命名解析和負載均衡接口供擴展。
其基本實現原理:
服務啓動後gRPC客戶端向命名服務器發出名稱解析請求,名稱將解析爲一個或多個IP地址,每一個IP地址標示它是服務器地址仍是負載均衡器地址,以及標示要使用那個客戶端負載均衡策略或服務配置。
客戶端實例化負載均衡策略,若是解析返回的地址是負載均衡器地址,則客戶端將使用grpclb策略,不然客戶端使用服務配置請求的負載均衡策略。
負載均衡策略爲每一個服務器地址建立一個子通道(channel)。
當有rpc請求時,負載均衡策略決定那個子通道即grpc服務器將接收請求,當可用服務器爲空時客戶端的請求將被阻塞。
根據gRPC官方提供的設計思路,基於進程內LB方案(即第2個案,阿里開源的服務框架 Dubbo 也是採用相似機制),結合分佈式一致的組件(如Zookeeper、Consul、Etcd),可找到gRPC服務發現和負載均衡的可行解決方案。接下來以GO語言爲例,簡單介紹下基於Etcd3的關鍵代碼實現:
上面有描述,dubbo支持grpc,方案相似本文3.1提出的方案,不過是阿里提供了一整套微服務體系,包括註冊中心nacas、dubbo、sentinel都支持grpc
這個方案一樣是相似3.2章,上面是集成了net.devh.grpc, 該插件最新版本,一樣支持springcloud全家桶,詳細能夠參考github: https://github.com/yidongnan/grpc-spring-boot-starter。 若是是異構語言則須要集成springcloud中的sidecar來實現服務發現,這裏也僅僅是支持java調用其餘異構語言,若是須要其餘語言也支持相互調用,則須要對應語言按照開源組件官方說的方案二來實現相應組件
Istio是什麼:Istio是Google/IBM/Lyft聯合開發的開源項目,2017年5月發佈第一個release 0.1.0, 官方定義爲:
Istio:一個鏈接,管理和保護微服務的開放平臺。
按照isito文檔中給出的定義:
Istio提供一種簡單的方式來創建已部署的服務的網絡,具有負載均衡,服務到服務認證,監控等等功能,而不須要改動任何服務代碼。
簡單的說,有了Istio,你的服務就再也不須要任何微服務開發框架(典型如Spring Cloud,Dubbo),也再也不須要本身動手實現各類複雜的服務治理的功能(不少是Spring Cloud和Dubbo也不能提供的,須要本身動手)。只要服務的客戶端和服務器能夠進行簡單的直接網絡訪問,就能夠經過將網絡層委託給Istio,從而得到一系列的完備功能。 Istio的關鍵功能:
能夠近似的理解爲:Istio = 微服務框架 + 服務治理 如下是 Istio 的官方拓撲圖: 這裏的前提是使用了k8s,在k8s中能夠無縫集成istio。具體操做步驟我這裏不作詳細描述,詳情能夠參考下面連接使用Istio和Envoy實踐服務網格gRPC度量
grpc自帶認證,不過有時候也須要在調用前,或者調用後作一些操做,好比說記錄監控信息、或者透傳header等等,這時就須要用到grpc的攔截器,這裏僅以java語言來講一下攔截器用法。
public class MyServerInsterceptor implements ServerInterceptor{ @Override public <reqt, respt> ServerCall.Listener<reqt> interceptCall(ServerCall<reqt, respt> call, Metadata headers, ServerCallHandler<reqt, respt> next) { return next.startCall(call,headers); } }
這裏能夠設置全局攔截器
@Configuration public class GrpcOpenConfig { //grpc-spring-boot-starter provides @GrpcGlobalInterceptor to allow server-side interceptors to be registered with all //server stubs, we are just taking advantage of that to install the server-side gRPC tracer. @Bean ServerInterceptor grpcServerInterceptor() { return new MyServerInterceptor(); } @Bean public GlobalServerInterceptorConfigurer globalInterceptorConfigurerAdapter(ServerInterceptor grpcServerInterceptor) { return registry -> registry.addServerInterceptors(grpcServerInterceptor); } }
同時若是集成了grpc-spring-boot-starter,也可使用@GrpcGlobalInterceptor來增長全局攔截器,hi須要將該註解加到類名上
public class MyClientInterceptor implements ClientInterceptor { Metadata.Key<string> token = Metadata.Key.of("token", Metadata.ASCII_STRING_MARSHALLER); @Override public <reqt, respt> ClientCall<reqt, respt> interceptCall(MethodDescriptor<reqt, respt> method, CallOptions callOptions, Channel next) { return new SimpleForwardingClientCall<reqt, respt>(next.newCall(method, callOptions)) { @Override public void start(Listener<respt> responseListener, Metadata headers) { //此處爲你登陸後得到的token的值 headers.put(token, "A2D05E5ED2414B1F8C6AEB19F40EF77C"); super.start(new SimpleForwardingClientCallListener<respt>(responseListener) { @Override public void onHeaders(Metadata headers) { super.onHeaders(headers); } }, headers); } }; } }
這裏能夠設置全局攔截器
@Order(Ordered.LOWEST_PRECEDENCE) @Configuration @Slf4j public class GrpcOpenTracingConfig { //We also create a client-side interceptor and put that in the context, this interceptor can then be injected into gRPC clients and //then applied to the managed channel. @Bean ClientInterceptor grpcClientInterceptor() { return new MyclientInterceptor(); } @Bean public GlobalClientInterceptorConfigurer globalInterceptorConfigurerAdapter(ClientInterceptor grpcClientInterceptor) { return registry -> registry.addClientInterceptors(grpcClientInterceptor); } }
同時若是集成了grpc-spring-boot-starter,也可使用@GrpcGlobalInterceptor來增長全局攔截器,hi須要將該註解加到類名上
關於全鏈路監控,能夠參考個人全鏈路系列博客
微服務全鏈路跟蹤:jaeger集成istio,併兼容uber-trace-id與b3
若是是集成了 grpc-spring-boot-starter,則只須要訪問 http://服務域名/actuator/prometheus ,能夠看到grpc相關監控指標
若是是集成了grafana,就能看到下面的效果:
grpc斷路器有幾種方案:
一、istio斷路器 參考相關博客istio-斷路器示例
二、hystrix 參考個人博客grpc斷路器之hystrix
三、sentinel grpc斷路器之sentinel
這裏能夠參考個人博客 springcloud線上發佈超時之grpc優化
參考個人博客:
grpc坑之Could not find TLS ALPN provider; no working netty-tcnative
未完待續