gRPC技術(shù)優(yōu)勢(shì)哪里?有什么缺點(diǎn)和應(yīng)對(duì)策略?(grpc的優(yōu)勢(shì))

      網(wǎng)友投稿 2181 2022-05-30

      【引言】

      gRPC(gRPC Remote Procedure Calls)是一個(gè)開源的遠(yuǎn)程過程調(diào)用(RPC)系統(tǒng),由谷歌公司最先在2015年開發(fā)。它使用HTTP/2作為傳輸方式,協(xié)議緩沖器作為接口描述語言,提供了認(rèn)證、雙向流和流控制、阻塞或非阻塞綁定、取消和超時(shí)等功能。它可以為許多編程語言生成跨平臺(tái)的客戶端和服務(wù)器綁定。最常見的使用場景包括在微服務(wù)架構(gòu)中的服務(wù)連接,以及移動(dòng)設(shè)備、網(wǎng)頁客戶端連接到后端服務(wù)等。

      【概述】

      在gRPC中,客戶端應(yīng)用程序可以直接調(diào)用不同服務(wù)器應(yīng)用程序上的方法,就像調(diào)用本地對(duì)象接口一樣,這讓你更容易創(chuàng)建分布式應(yīng)用和服務(wù)。和許多RPC系統(tǒng)一樣,gRPC也是圍繞著定義一個(gè)服務(wù)的思想,指定可以遠(yuǎn)程調(diào)用的方法,參數(shù)和返回類型。在服務(wù)器端,服務(wù)程序?qū)崿F(xiàn)這個(gè)接口,并運(yùn)行g(shù)RPC服務(wù)器來處理客戶端的調(diào)用。在客戶端上有一個(gè)存根,這個(gè)存根提供與服務(wù)器相同的方法。

      gRPC客戶端和服務(wù)器可以在各種環(huán)境下運(yùn)行和對(duì)話,并且可以用gRPC支持的任何一種語言編寫。比如,你可以輕松地用Java創(chuàng)建一個(gè)gRPC服務(wù)器,用Go、Python或Ruby的客戶端來調(diào)用。此外,最新的Google API都會(huì)有g(shù)RPC版本的接口,讓你可以輕松地將Google功能構(gòu)建到你的應(yīng)用程序中。

      【gRPC的優(yōu)點(diǎn)】

      性能

      gRPC消息使用Protobuf進(jìn)行序列化,Protobuf是一種高效的二進(jìn)制消息格式。Protobuf在服務(wù)器和客戶端上的序列化速度非常快。Protobuf序列化的結(jié)果是消息的有效載荷小,這對(duì)于移動(dòng)應(yīng)用等有限帶寬的場景來說非常重要。

      gRPC是為HTTP/2設(shè)計(jì)的,這是HTTP的一個(gè)重要修訂版,它比HTTP 1.x提供了顯著的性能優(yōu)勢(shì)。

      l??二進(jìn)制框架和壓縮技術(shù)的使用使得HTTP/2協(xié)議在發(fā)送和接收方面都非常緊湊和高效。

      l??在單一TCP連接上實(shí)現(xiàn)多個(gè)HTTP/2調(diào)用的復(fù)用。多路復(fù)用消除了線頭阻塞。

      代碼通過工具生成

      所有的gRPC框架都提供了一流的代碼生成支持。gRPC開發(fā)的一個(gè)核心文件是.proto文件,它定義了gRPC服務(wù)和消息的契約。從這個(gè)文件中,gRPC框架將代碼生成一個(gè)服務(wù)基類、消息和一個(gè)完整的客戶端。

      通過在服務(wù)器和客戶端之間共享.proto文件,消息和客戶端的代碼可以從端到端的生成。客戶端的代碼生成消除了客戶端和服務(wù)器上的消息重復(fù),為你創(chuàng)建一個(gè)強(qiáng)類型化的客戶端。在有很多服務(wù)的應(yīng)用程序中,不需要編寫客戶端,這可以節(jié)省大量的開發(fā)時(shí)間。

      嚴(yán)格的規(guī)范

      目前還沒有一個(gè)針對(duì)使用JSON的HTTP API的正式規(guī)范。開發(fā)者們一直對(duì)URL、HTTP動(dòng)詞和響應(yīng)代碼的最佳格式爭論不休。

      gRPC規(guī)范對(duì)gRPC服務(wù)必須遵循的格式是有規(guī)定的。gRPC消除了爭論,從而節(jié)省了開發(fā)者的時(shí)間,因?yàn)間RPC在不同平臺(tái)和實(shí)現(xiàn)上是一致的。

      流處理

      HTTP/2為長效實(shí)時(shí)通信流提供了基礎(chǔ),gRPC通過HTTP/2提供了一流的流處理支持。

      一個(gè)gRPC服務(wù)支持所有的流處理組合:

      l??單一式(無流處理)

      l??服務(wù)器到客戶端的流處理

      l??客戶端到服務(wù)器的流處理

      l??雙向流處理

      超時(shí)取消機(jī)制

      gRPC允許客戶端指定他們?cè)敢獾却嚅L時(shí)間完成一個(gè)RPC。把這個(gè)時(shí)間決定的最后期限被發(fā)送至服務(wù)器,服務(wù)器可以決定超過最后期限時(shí)采取什么行動(dòng)。例如,服務(wù)器可以在超時(shí)后取消正在進(jìn)行中的gRPC或HTTP或數(shù)據(jù)庫請(qǐng)求。

      通過對(duì)gRPC調(diào)用設(shè)置超時(shí)取消機(jī)制,有助于實(shí)現(xiàn)對(duì)資源的限制使用。

      【gRPC的緩沖器與認(rèn)證】

      【使用協(xié)議緩沖器】

      gRPC使用協(xié)議緩沖區(qū)對(duì)數(shù)據(jù)進(jìn)行編碼。與使用JSON的HTTP API不同,它們有一個(gè)更嚴(yán)格的規(guī)范。

      協(xié)議緩沖區(qū)是Google成熟的開源機(jī)制,用于序列化結(jié)構(gòu)化數(shù)據(jù)(盡管它可以使用其他數(shù)據(jù)格式,如JSON)。以下是對(duì)其工作原理的簡單介紹。

      在使用協(xié)議緩沖區(qū)時(shí),第一步是在proto文件中定義要序列化的數(shù)據(jù)結(jié)構(gòu):是一個(gè)普通的文本文件,擴(kuò)展名為.proto。協(xié)議緩沖區(qū)的數(shù)據(jù)是以消息的形式結(jié)構(gòu)化,每個(gè)消息都是一個(gè)小的邏輯信息記錄,其中包含一系列稱為字段的名-值對(duì)。下面是一個(gè)簡單的例子:

      message?Person?{

      string?name?=?1;

      int32?id?=?2;

      bool?has_ponycopter?=?3;

      }

      接著,一旦你指定了你的數(shù)據(jù)結(jié)構(gòu),你就可以使用協(xié)議緩沖區(qū)編譯器?protoc?從你的?proto?定義中生成你喜歡的編程語言的數(shù)據(jù)訪問類。這些類為每個(gè)字段提供了簡單的訪問器,如?name()和?set_name(),以及將整個(gè)結(jié)構(gòu)序列化/解析為原始字節(jié)的方法。因此,例如,如果你選擇的語言是C++,用上面的例子中運(yùn)行,編譯器會(huì)生成一個(gè)名為Person的類。然后你可以在你的應(yīng)用程序中使用這個(gè)類來填充、序列化和檢索Person協(xié)議緩沖區(qū)消息。

      你在普通的proto文件中定義gRPC服務(wù),RPC方法參數(shù)和返回類型指定為協(xié)議緩沖區(qū)消息:

      //?greeter?服務(wù)定義.

      service?Greeter?{

      //?發(fā)出問候

      rpc?SayHello?(HelloRequest)?returns?(HelloReply)?{}

      }

      //?請(qǐng)求信息包含用戶名字

      message?HelloRequest?{

      string?name?=?1;

      }

      //?響應(yīng)消息包含問候消息

      message?HelloReply?{

      string?message?=?1;

      }

      gRPC?使用?protoc?和一個(gè)特殊的?gRPC?插件來從你的?proto?文件中生成代碼:你會(huì)得到生成的?gRPC?客戶端和服務(wù)器代碼,以及用于補(bǔ)足、序列化和檢索消息類型的常規(guī)協(xié)議緩沖區(qū)代碼。

      【協(xié)議緩沖區(qū)版本】

      雖然協(xié)議緩沖區(qū)已經(jīng)向開源用戶提供了一段時(shí)間,目前推薦使用協(xié)議緩沖區(qū)3版(proto3),它的語法稍有簡化,并添加了一些有用的新功能,而且支持了更多的語言。

      Proto3目前支持Java、C++、Dart、Python、Objective-C、C#、Android Java、Ruby、Golang和JavaScript,,還有更多語言正在開發(fā)中。

      一般來說,雖然可以使用proto2(當(dāng)前默認(rèn)的協(xié)議緩沖區(qū)版本),但建議你使用gRPC時(shí)使用proto3,因?yàn)樗С謌RPC目前支持的所有語言,同時(shí)也避免了proto2客戶端與proto3服務(wù)器的兼容性問題,反之亦然。

      【認(rèn)證】

      gRPC支持使用TLS和基于令牌的認(rèn)證。與Google服務(wù)的連接必須使用TLS。

      gRPC設(shè)計(jì)的初衷是可以與各種認(rèn)證機(jī)制一起工作,從而可以很容易地通過gRPC與其他系統(tǒng)對(duì)話。

      gRPC還提供了一個(gè)簡單的認(rèn)證API,讓您在創(chuàng)建通道或調(diào)用時(shí)提供所有必要的認(rèn)證信息作為憑證。

      憑證類型

      憑證可以分為兩種類型:

      l??通道憑證,附加在通道上,如SSL憑證。

      l??調(diào)用憑證,它附加到一個(gè)調(diào)用(或C++中的ClientContext)上。

      你也可以在CompositeChannelCredentials中結(jié)合這些內(nèi)容,例如,你可以為通道指定SSL的詳細(xì)信息,并為通道上的每個(gè)呼叫指定呼叫憑證。CompositeChannelCredentials?將通道憑證和呼叫憑證關(guān)聯(lián)起來,以創(chuàng)建一個(gè)新的通道憑證。其結(jié)果將在信道上的每一次呼叫中發(fā)送與組成的CallCredentials相關(guān)聯(lián)的認(rèn)證數(shù)據(jù)。

      比如說,你可以從一個(gè)SSLCredentials和一個(gè)AccessTokenCredentials創(chuàng)建一個(gè)ChannelCredentials。當(dāng)應(yīng)用到一個(gè)Channel時(shí),其結(jié)果將為這個(gè)通道上的每個(gè)呼叫發(fā)送相應(yīng)的訪問令牌。

      單個(gè)CallCredentials也可以用CompositeCallCredentials組成。在呼叫中使用的CallCredentials將觸發(fā)與兩個(gè)CallCredentials相關(guān)聯(lián)的認(rèn)證數(shù)據(jù)的發(fā)送。

      gRPC具有SSL/TLS集成功能,提倡使用SSL/TLS來驗(yàn)證服務(wù)器,并對(duì)客戶端和服務(wù)器之間交換的所有數(shù)據(jù)進(jìn)行加密。客戶端可選擇提供相互認(rèn)證的證書機(jī)制。

      現(xiàn)在我們來看看Credentials是如何與我們支持的一種認(rèn)證機(jī)制一起工作的。我們假定最簡單的驗(yàn)證場景,客戶端只想驗(yàn)證服務(wù)器并加密所有數(shù)據(jù)。這個(gè)例子是用C++語言編寫的,但所有語言的API都是類似的。

      //?創(chuàng)建一個(gè)默認(rèn)的SSL?ChannelCredentials對(duì)象。

      auto?channel_creds?=?grpc::SslCredentials(grpc::SslCredentialsOptions());

      //?使用上一步中創(chuàng)建的憑證創(chuàng)建一個(gè)通道。

      auto?channel?=?grpc::CreateChannel(server_name,?channel_creds);

      //?在通道上創(chuàng)建一個(gè)存根。

      std::unique_ptr?stub(Greeter::NewStub(channel));

      //?在存根上進(jìn)行實(shí)際的RPC調(diào)用。

      grpc::Status?s?=?stub->sayHello(&context,?*request,?response);

      對(duì)于高級(jí)用例,如修改根CA或使用客戶端證書,可以在傳遞給工廠方法的?SslCredentialsOptions?參數(shù)中設(shè)置相應(yīng)的選項(xiàng)。

      基于令牌的身份驗(yàn)證

      gRPC提供了一個(gè)通用的機(jī)制,可以將基于元數(shù)據(jù)的憑證附加到請(qǐng)求和響應(yīng)中。這種機(jī)制專門用于訪問Google?的API服務(wù)。?一般來說,Google不允許沒有SSL/TLS的連接,而且大多數(shù)gRPC語言實(shí)現(xiàn)也不會(huì)讓你在未加密的通道上發(fā)送憑證。

      gRPC應(yīng)用程序可以使用一個(gè)簡單的API來創(chuàng)建一個(gè)在各種部署場景中與Google進(jìn)行認(rèn)證的憑證。例子:

      auto?creds?=?grpc::GoogleDefaultCredentials();

      //?創(chuàng)建一個(gè)通道,存根并進(jìn)行RPC調(diào)用(與上例的功能一樣)

      auto?channel?=?grpc::CreateChannel(server_name,?creds);

      std::unique_ptr?stub(Greeter::NewStub(channel));

      grpc::Status?s?=?stub->sayHello(&context,?*request,?response);

      這個(gè)通道憑證對(duì)象適用于使用服務(wù)賬戶的應(yīng)用程序和在?Google Compute Engine (GCE)?中運(yùn)行的應(yīng)用程序。在前一種情況下,服務(wù)賬戶的私鑰是從環(huán)境變量?GOOGLE_APPLICATION_CREDENTIALS?中命名的文件中加載的。這些密鑰用于生成附加到相應(yīng)通道上的每個(gè)出站RPC的承載令牌。

      對(duì)于在?GCE?中運(yùn)行的應(yīng)用程序,可以在?VM?設(shè)置期間配置一個(gè)默認(rèn)服務(wù)帳戶和相應(yīng)的?OAuth2?作用域。在運(yùn)行時(shí),該憑證處理與認(rèn)證系統(tǒng)的通信,以獲取OAuth2訪問令牌,并將其附加到相應(yīng)通道上的每個(gè)出站RPC上。

      擴(kuò)展gRPC以支持其他認(rèn)證機(jī)制

      憑證插件API允許開發(fā)人員插入自己的憑證類型。這些插件有:

      l??MetadataCredentialsPlugin抽象類,它包含純虛擬的GetMetadata方法,需要由開發(fā)者創(chuàng)建的子類來實(shí)現(xiàn)。

      l??MetadataCredentialsFromPlugin函數(shù),它從

      MetadataCredentialsPlugin中創(chuàng)建一個(gè)CallCredentials。

      下面是一個(gè)簡單的憑證插件的例子,它可以在自定義頭中設(shè)置一個(gè)認(rèn)證依據(jù)。

      類實(shí)現(xiàn):

      class?MyCustomAuthenticator?:?public?grpc::MetadataCredentialsPlugin?{

      public:

      MyCustomAuthenticator(const?grpc::string&?ticket)?:?ticket_(ticket)?{}

      grpc::Status?GetMetadata(

      grpc::string_ref?service_url,?grpc::string_ref?method_name,

      const?grpc::AuthContext&?channel_auth_context,

      std::multimap*?metadata)?override?{

      metadata->insert(std::make_pair("x-custom-auth-ticket",?ticket_));

      return?grpc::Status::OK;

      }

      private:

      grpc::string?ticket_;

      };

      類調(diào)用:

      auto?call_creds?=?grpc::MetadataCredentialsFromPlugin(

      std::unique_ptr(

      new?MyCustomAuthenticator("super-secret-ticket")));

      通過在核心層插入gRPC憑證實(shí)現(xiàn),可以實(shí)現(xiàn)更深層次的集成。

      更多例子

      這些認(rèn)證機(jī)制將適用于所有g(shù)RPC支持的語言。

      conn,?_?:=?grpc.Dial("localhost:50051",?grpc.WithInsecure())

      //?此處需要添加錯(cuò)誤處理

      client?:=?pb.NewGreeterClient(conn)

      //?...

      s?:=?grpc.NewServer()

      lis,?_?:=?net.Listen("tcp",?"localhost:50051")

      //?此處需要添加錯(cuò)誤處理

      s.Serve(lis)

      creds,?_?:=?credentials.NewClientTLSFromFile(certFile,?"")

      conn,?_?:=?grpc.Dial("localhost:50051",?grpc.WithTransportCredentials(creds))

      //?此處需要添加錯(cuò)誤處理

      client?:=?pb.NewGreeterClient(conn)

      //?...

      creds,?_?:=?credentials.NewServerTLSFromFile(certFile,?keyFile)

      s?:=?grpc.NewServer(grpc.Creds(creds))

      lis,?_?:=?net.Listen("tcp",?"localhost:50051")

      //?此處需要添加錯(cuò)誤處理

      s.Serve(lis)

      pool,?_?:=?x509.SystemCertPool()

      //?此處需要添加錯(cuò)誤處理

      creds?:=?credentials.NewClientTLSFromCert(pool,?"")

      perRPC,?_?:=?oauth.NewServiceAccountFromFile("service-account.json",?scope)

      conn,?_?:=?grpc.Dial(

      "greeter.googleapis.com",

      grpc.WithTransportCredentials(creds),

      grpc.WithPerRPCCredentials(perRPC),

      )

      //?此處需要添加錯(cuò)誤處理

      client?:=?pb.NewGreeterClient(conn)

      //?...

      stub?=?Helloworld::Greeter::Stub.new('localhost:50051',?:this_channel_is_insecure)

      creds?=?GRPC::Core::ChannelCredentials.new(load_certs)??#?load_certs通常加載一個(gè)CA根文件

      stub?=?Helloworld::Greeter::Stub.new('myservice.example.com',?creds)

      require?'googleauth'??#?from?http://www.rubydoc.info/gems/googleauth/0.1.0

      ...

      ssl_creds?=?GRPC::Core::ChannelCredentials.new(load_certs)??#?load_certs通常加載一個(gè)CA根文件

      authentication?=?Google::Auth.get_application_default()

      call_creds?=?GRPC::Core::CallCredentials.new(authentication.updater_proc)

      combined_creds?=?ssl_creds.compose(call_creds)

      stub?=?Helloworld::Greeter::Stub.new('greeter.googleapis.com',?combined_creds)

      auto?channel?=?grpc::CreateChannel("localhost:50051",?InsecureChannelCredentials());

      std::unique_ptr?stub(Greeter::NewStub(channel));

      ...

      auto?channel_creds?=?grpc::SslCredentials(grpc::SslCredentialsOptions());

      auto?channel?=?grpc::CreateChannel("myservice.example.com",?channel_creds);

      std::unique_ptr?stub(Greeter::NewStub(channel));

      ...

      auto?creds?=?grpc::GoogleDefaultCredentials();

      auto?channel?=?grpc::CreateChannel("greeter.googleapis.com",?creds);

      std::unique_ptr?stub(Greeter::NewStub(channel));

      ...

      var?channel?=?new?Channel("localhost:50051",?ChannelCredentials.Insecure);

      var?client?=?new?Greeter.GreeterClient(channel);

      ...

      var?channelCredentials?=?new?SslCredentials(File.ReadAllText("roots.pem"));??//?Load?a?custom?roots?file.

      var?channel?=?new?Channel("myservice.example.com",?channelCredentials);

      var?client?=?new?Greeter.GreeterClient(channel);

      using?Grpc.Auth;??//?從Grpc.Auth?NuGet包中獲取

      ...

      //?加載Google應(yīng)用的默認(rèn)憑證與公開信任的根。

      var?channelCredentials?=?await?GoogleGrpcCredentials.GetApplicationDefaultAsync();

      var?channel?=?new?Channel("greeter.googleapis.com",?channelCredentials);

      var?client?=?new?Greeter.GreeterClient(channel);

      ...

      var?channel?=?new?Channel("greeter.googleapis.com",?new?SslCredentials());??//?Use?publicly?trusted?roots.

      var?client?=?new?Greeter.GreeterClient(channel);

      ...

      var?googleCredential?=?await?GoogleCredential.GetApplicationDefaultAsync();

      gRPC技術(shù)優(yōu)勢(shì)在哪里?有什么缺點(diǎn)和應(yīng)對(duì)策略?(grpc的優(yōu)勢(shì))

      var?result?=?client.SayHello(request,?new?CallOptions(credentials:?googleCredential.ToCallCredentials()));

      ...

      import?grpc

      import?helloworld_pb2

      channel?=?grpc.insecure_channel('localhost:50051')

      stub?=?helloworld_pb2.GreeterStub(channel)

      import?grpc

      import?helloworld_pb2

      with?open('roots.pem',?'rb')?as?f:

      creds?=?grpc.ssl_channel_credentials(f.read())

      channel?=?grpc.secure_channel('myservice.example.com:443',?creds)

      stub?=?helloworld_pb2.GreeterStub(channel)

      import?grpc

      import?helloworld_pb2

      from?concurrent?import?futures

      server?=?grpc.server(futures.ThreadPoolExecutor(max_workers=10))

      with?open('key.pem',?'rb')?as?f:

      private_key?=?f.read()

      with?open('chain.pem',?'rb')?as?f:

      certificate_chain?=?f.read()

      server_credentials?=?grpc.ssl_server_credentials(?(?(private_key,?certificate_chain),?)?)

      #?此處要將GreeterServicer添加到服務(wù)器

      server.add_secure_port('myservice.example.com:443',?server_credentials)

      server.start()

      import?grpc

      import?helloworld_pb2

      from?google?import?auth?as?google_auth

      from?google.auth?import?jwt?as?google_auth_jwt

      from?google.auth.transport?import?grpc?as?google_auth_transport_grpc

      credentials,?_?=?google_auth.default()

      jwt_creds?=?google_auth_jwt.OnDemandCredentials.from_signing_credentials(

      credentials)

      channel?=?google_auth_transport_grpc.secure_authorized_channel(

      jwt_creds,?None,?'greeter.googleapis.com:443')

      stub?=?helloworld_pb2.GreeterStub(channel)

      import?grpc

      import?helloworld_pb2

      from?google?import?auth?as?google_auth

      from?google.auth.transport?import?grpc?as?google_auth_transport_grpc

      from?google.auth.transport?import?requests?as?google_auth_transport_requests

      credentials,?_?=?google_auth.default(scopes=(scope,))

      request?=?google_auth_transport_requests.Request()

      channel?=?google_auth_transport_grpc.secure_authorized_channel(

      credentials,?request,?'greeter.googleapis.com:443')

      stub?=?helloworld_pb2.GreeterStub(channel)

      ManagedChannel?channel?=?ManagedChannelBuilder.forAddress("localhost",?50051).usePlaintext(true).build();

      GreeterGrpc.GreeterStub?stub?=?GreeterGrpc.newStub(channel);

      在Java中,建議使用OpenSSL。

      要在服務(wù)器上啟用TLS,需要以PEM格式指定證書鏈和私鑰。這樣的私鑰不應(yīng)該使用密碼。證書鏈中證書的順序很重要:更具體地說,最上面的證書必須是主機(jī)CA,而最下面的證書必須是根CA。標(biāo)準(zhǔn)的TLS端口是443,但為了避免申請(qǐng)操作系統(tǒng)的額外權(quán)限,下面用的是8443。

      Server?server?=?ServerBuilder.forPort(8443)

      //?啟用TLS

      .useTransportSecurity(certChainFile,?privateKeyFile)

      .addService(TestServiceGrpc.bindService(serviceImplementation))

      .build();

      server.start();

      如果客戶端不知道發(fā)證機(jī)構(gòu),那么應(yīng)該分別向NettyChannelBuilder或OkHttpChannelBuilder提供一個(gè)正確配置的SSLContext或SSLSocketFactory。

      在客戶端,使用SSL/TLS的服務(wù)器認(rèn)證大體是這樣的:

      //?通過服務(wù)器認(rèn)證?SSL/TLS

      ManagedChannel?channel?=?ManagedChannelBuilder.forAddress("myservice.example.com",?443).build();

      GreeterGrpc.GreeterStub?stub?=?GreeterGrpc.newStub(channel);

      //?具有服務(wù)器認(rèn)證SSL/TLS;自定義CA根證書;不適用于Android

      ManagedChannel?channel?=?NettyChannelBuilder.forAddress("myservice.example.com",?443)

      .sslContext(GrpcSslContexts.forClient().trustManager(new?File("roots.pem")).build()).build();

      GreeterGrpc.GreeterStub?stub?=?GreeterGrpc.newStub(channel);

      下面的代碼片段顯示了如何使用服務(wù)賬戶使用gRPC調(diào)用Google Cloud PubSub API。憑證是從存儲(chǔ)在一個(gè)已知位置的密鑰中加載的,或者通過檢測(cè)應(yīng)用程序運(yùn)行在一個(gè)可以自動(dòng)提供密鑰的環(huán)境中,例如Google Compute Engine等,來加載。雖然這個(gè)例子是針對(duì)Google及其服務(wù)的,但類似的模式也可以適用于其他服務(wù)提供商。

      GoogleCredentials?creds?=?GoogleCredentials.getApplicationDefault();

      ManagedChannel?channel?=?ManagedChannelBuilder.forTarget("greeter.googleapis.com")

      .build();

      GreeterGrpc.GreeterStub?stub?=?GreeterGrpc.newStub(channel)

      .withCallCredentials(MoreCallCredentials.from(creds));

      var?stub?=?new?helloworld.Greeter('localhost:50051',?grpc.credentials.createInsecure());

      var?ssl_creds?=?grpc.credentials.createSsl(root_certs);

      var?stub?=?new?helloworld.Greeter('myservice.example.com',?ssl_creds);

      //?使用谷歌認(rèn)證

      var?GoogleAuth?=?require('google-auth-library');?//?from?https://www.npmjs.com/package/google-auth-library

      ...

      var?ssl_creds?=?grpc.credentials.createSsl(root_certs);

      (new?GoogleAuth()).getApplicationDefault(function(err,?auth)?{

      var?call_creds?=?grpc.credentials.createFromGoogleCredential(auth);

      var?combined_creds?=?grpc.credentials.combineChannelCredentials(ssl_creds,?call_creds);

      var?stub?=?new?helloworld.Greeter('greeter.googleapis.com',?combined_credentials);

      });

      var?GoogleAuth?=?require('google-auth-library');?//?from?https://www.npmjs.com/package/google-auth-library

      ...

      var?ssl_creds?=?grpc.Credentials.createSsl(root_certs);?//?load_certs通常加載一個(gè)CA根文件

      var?scope?=?'https://www.googleapis.com/auth/grpc-testing';

      (new?GoogleAuth()).getApplicationDefault(function(err,?auth)?{

      if?(auth.createScopeRequired())?{

      auth?=?auth.createScoped(scope);

      }

      var?call_creds?=?grpc.credentials.createFromGoogleCredential(auth);

      var?combined_creds?=?grpc.credentials.combineChannelCredentials(ssl_creds,?call_creds);

      var?stub?=?new?helloworld.Greeter('greeter.googleapis.com',?combined_credentials);

      });

      $client?=?new?helloworld\GreeterClient('localhost:50051',?[

      'credentials'?=>?Grpc\ChannelCredentials::createInsecure(),

      ]);

      function?updateAuthMetadataCallback($context)

      {

      $auth_credentials?=?ApplicationDefaultCredentials::getCredentials();

      return?$auth_credentials->updateMetadata($metadata?=?[],?$context->service_url);

      }

      $channel_credentials?=?Grpc\ChannelCredentials::createComposite(

      Grpc\ChannelCredentials::createSsl(file_get_contents('roots.pem')),

      Grpc\CallCredentials::createFromPlugin('updateAuthMetadataCallback')

      );

      $opts?=?[

      'credentials'?=>?$channel_credentials

      ];

      $client?=?new?helloworld\GreeterClient('greeter.googleapis.com',?$opts);

      //?需要設(shè)置環(huán)境變量?"GOOGLE_APPLICATION_CREDENTIALS?"

      $scope?=?"https://www.googleapis.com/auth/grpc-testing";

      $auth?=?Google\Auth\ApplicationDefaultCredentials::getCredentials($scope);

      $opts?=?[

      'credentials'?=>?Grpc\Credentials::createSsl(file_get_contents('roots.pem'));

      'update_metadata'?=>?$auth->getUpdateMetadataFunc(),

      ];

      $client?=?new?helloworld\GreeterClient('greeter.googleapis.com',?$opts);

      final?channel?=?new?ClientChannel('localhost',

      port:?50051,

      options:?const?ChannelOptions(

      credentials:?const?ChannelCredentials.insecure()));

      final?stub?=?new?GreeterClient(channel);

      //?加載一個(gè)自定義的根文件。

      final?trustedRoot?=?new?File('roots.pem').readAsBytesSync();

      final?channelCredentials?=

      new?ChannelCredentials.secure(certificates:?trustedRoot);

      final?channelOptions?=?new?ChannelOptions(credentials:?channelCredentials);

      final?channel?=?new?ClientChannel('myservice.example.com',

      options:?channelOptions);

      final?client?=?new?GreeterClient(channel);

      //?默認(rèn)使用公開的信任根。

      final?channel?=?new?ClientChannel('greeter.googleapis.com');

      final?serviceAccountJson?=

      new?File('service-account.json').readAsStringSync();

      final?credentials?=?new?JwtServiceAccountAuthenticator(serviceAccountJson);

      final?client?=

      new?GreeterClient(channel,?options:?credentials.toCallOptions);

      //?默認(rèn)使用公開的信任根。

      final?channel?=?new?ClientChannel('greeter.googleapis.com');

      final?client?=?new?GreeterClient(channel);

      ...

      final?serviceAccountJson?=

      new?File('service-account.json').readAsStringSync();

      final?credentials?=?new?JwtServiceAccountAuthenticator(serviceAccountJson);

      final?response?=

      await?client.sayHello(request,?options:?credentials.toCallOptions);

      【gRPC的應(yīng)用場景】

      gRPC非常適用于以下情況:

      l??微服務(wù)--gRPC是為低延遲和高吞吐量通信而設(shè)計(jì)的。

      l??點(diǎn)對(duì)點(diǎn)實(shí)時(shí)通信--gRPC對(duì)雙向流的支持非常好,gRPC服務(wù)可以實(shí)時(shí)推送消息,無需輪詢。

      l??多語言環(huán)境--gRPC工具支持所有流行的開發(fā)語言,使gRPC成為多語言環(huán)境的最佳選擇。

      l??網(wǎng)絡(luò)約束環(huán)境--gRPC消息采用Protobuf(一種輕量級(jí)消息格式)進(jìn)行序列化。一個(gè)gRPC消息總是比同等的JSON消息小。

      【應(yīng)用現(xiàn)狀】

      許多公司都采用了gRPC,如Square、Netflix、CoreOS、Docker、Cocker、CockroachDB、Cisco、Juniper Networks等。

      開源項(xiàng)目u-bmc使用gRPC來取代IPMI。2019年1月8日,Dropbox宣布,其SOA架構(gòu)核心的RPC框架?"Courier "的下一個(gè)版本將遷移到基于gRPC的新架構(gòu)上,主要原因是該框架與他們現(xiàn)有的定制的RPC框架可以很好地接軌。

      【小結(jié)】

      在我們的開發(fā)過程中,對(duì)于API技術(shù)的選取是一個(gè)重要的環(huán)節(jié),相比HTTP API,?本文介紹了gRPC具有的獨(dú)特優(yōu)勢(shì),并從緩沖機(jī)制和認(rèn)證兩個(gè)重要方面對(duì)這門技術(shù)進(jìn)行了學(xué)習(xí),下面來看看它的缺點(diǎn)和對(duì)應(yīng)的策略:

      瀏覽器支持有限

      在目前情況下,從瀏覽器中直接調(diào)用gRPC服務(wù)是不可能的,gRPC大量使用HTTP/2的功能,目前的瀏覽器不支持gRPC客戶端所需要的網(wǎng)絡(luò)請(qǐng)求控制能力。例如,瀏覽器不允許調(diào)用者使用HTTP/2,也不提供對(duì)底層HTTP/2幀的訪問。

      應(yīng)對(duì)策略

      gRPC-Web是gRPC團(tuán)隊(duì)的一項(xiàng)附加支持技術(shù),它在瀏覽器中提供有限的gRPC支持。

      gRPC-Web由兩部分組成:支持所有現(xiàn)代瀏覽器的JavaScript客戶端和服務(wù)器上的gRPC-Web代理。通過客戶端調(diào)用代理,代理再把gRPC請(qǐng)求轉(zhuǎn)發(fā)到gRPC服務(wù)器上。

      gRPC-Web并不支持gRPC的所有功能,比如不支持客戶端流處理和雙向流處理,對(duì)服務(wù)器流處理的支持也很有限。

      傳輸內(nèi)容人類不可讀

      HTTP API請(qǐng)求以文本形式發(fā)送,人類可以讀取。

      gRPC消息默認(rèn)使用Protobuf進(jìn)行編碼。雖然Protobuf的發(fā)送和接收效率很高,但它的二進(jìn)制格式并不是人類可以讀取的。

      Protobuf需要在.proto文件中指定消息的接口描述來正確地解序列化。需要額外的工具來分析Protobuf的線上有效載荷和手工編寫請(qǐng)求。

      應(yīng)對(duì)策略

      諸如服務(wù)器反射和gRPC命令行工具等功能可以幫助處理二進(jìn)制Protobuf消息。此外,Protobuf消息支持與JSON格式的轉(zhuǎn)換。內(nèi)置的JSON轉(zhuǎn)換,可以將Protobuf消息轉(zhuǎn)換為人類可讀的形式,這在調(diào)試時(shí)非常有用。

      RPC

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:使用 Python、SQLite 和 SQLAlchemy 進(jìn)行數(shù)據(jù)管理2 |【生長吧!Python!】 【生長吧!Python】有獎(jiǎng)?wù)魑幕馃徇M(jìn)行中:https://bbs.huaweicloud.com/blogs/278897(使用驅(qū)動(dòng)器u盤之前需要格式化)
      下一篇:excel表格篩選后保持編號(hào)連續(xù)的方法(excel表格篩選后序號(hào)連續(xù))
      相關(guān)文章
      亚洲黄色在线播放| 亚洲av永久无码制服河南实里| 久久久久亚洲AV成人网| 日韩亚洲产在线观看| 亚洲国产精品成人精品小说| 久久综合亚洲鲁鲁五月天| 亚洲欧洲在线观看| 香蕉视频在线观看亚洲| 久久久久亚洲AV片无码| 亚洲成AV人片在| 国产成人亚洲精品青草天美| 亚洲精品无码专区久久久| 国产日韩亚洲大尺度高清| 亚洲无av在线中文字幕| 亚洲人成人无码网www电影首页| 在线精品亚洲一区二区小说| 亚洲日产韩国一二三四区| 亚洲热妇无码AV在线播放| 亚洲精品国精品久久99热一| 国产AV无码专区亚洲AV毛网站| 九月丁香婷婷亚洲综合色| 久久精品国产亚洲综合色| 国产成人亚洲精品青草天美| 亚洲成人中文字幕| 亚洲综合久久1区2区3区| 亚洲国产精品成人久久久| 亚洲国产成人在线视频| 亚洲日本乱码卡2卡3卡新区| 亚洲AV综合色区无码一二三区| 亚洲AV无码之日韩精品| 怡红院亚洲怡红院首页| 久久精品国产精品亚洲蜜月| 亚洲精品第五页中文字幕| 国产成人亚洲合集青青草原精品| 亚洲一线产品二线产品| 偷自拍亚洲视频在线观看| 国产偷国产偷亚洲清高动态图| 久久久久亚洲AV片无码| 亚洲不卡中文字幕| 亚洲av无码专区在线电影天堂| 亚洲精品网站在线观看不卡无广告|