使用gRPC構建實際的微服務
譯文【51CTO.com快譯】早期的微服務實現利用了代表性狀態傳輸(REST)架構作為事實上的通信技術。然而,充分利用REST的服務常常適用于面向外部的服務,這些服務直接暴露給消費者。由于它們基于傳統的基于文本的消息傳遞(JSON、XML和CVS over HTTP等)――針對人類進行了優化,因此這些不是內部服務間通信的理想選擇。
相反,使用一種基于文本的消息傳遞協議,我們可以利用針對服務間通信進行優化的二進制協議。云原生計算基金會的gRPC(一種高性能的開源通用遠程過程調用框架)是服務間通信的理想選擇,因為它使用協議緩沖區(protocol buffer)作為服務間通信的二進制數據交換格式。
我們使用不同的技術和編程語言構建多個微服務時,有一種標準的方法來定義服務接口和底層的消息交換格式很重要。gRPC提供了一種簡潔而強大的方法,可以使用協議緩沖區指定服務合約。因此,gRPC可能是最適合構建內部微服務間通信的解決方案。
我們在本文中將更深入地介紹為什么gRPC是構建微服務間通信的一種出色選擇。
gRPC的基礎知識
有了gRPC,客戶可以對不同機器上的服務器應用程序直接調用方法,好像該機器就是本地對象。gRPC立足于傳統的遠程過程調用(RPC)技術的基礎,但是實施在現代技術堆棧(比如HTTP2和協議緩沖區等)上,確保***的互操作性。
gRPC本身支持這種功能:使用gRPC接口定義語言(IDL)來定義服務合約。因此,作為服務定義的一部分,你可以指定可以遠程調用的方法以及參數和返回類型的數據結構。
圖1表明了gRPC的使用,在線零售應用程序作為庫存和產品搜索服務的一部分。 Inventory服務的合約使用gRPC IDL來定義,該IDL在inventory.proto文件中已有指定。因此,Inventory服務的開發人員應先使用該服務來定義所有業務功能,然后利用proto文件生成服務端框架代碼。與之相仿,可以使用同樣的proto文件生成客戶端代碼(存根,stub)。
圖1
由于gRPC與編程語言無關,你可以使用異構語言來構建服務和客戶端。在這個例子中,我們使用Ballerina(ballerina.io)生成了Inventory服務代碼,使用Java生成了客戶端代碼。你可以使用GitHub上的這個源代碼(https://github.com/kasun04/grpc-microservices)來試試該示例。
庫存(inventory.proto)的服務合約如下所示:
- syntax = "proto3";
- package grpc_service;
- import "google/protobuf/wrappers.proto";
- service InventoryService {
- rpc getItemByName(google.protobuf.StringValue) returns (Items);
- rpc getItemByID(google.protobuf.StringValue) returns (Item);
- rpc addItem(Item) returns (google.protobuf.BoolValue);
- }
- message Items {
- string itemDesc = 1;
- repeated Item items = 2;
- }
- message Item {
- string id = 1;
- string name = 2;
- string description = 3;
- }
服務合約易于理解,可以在客戶端和服務之間共享。如果服務合約有任何變化,服務代碼和客戶端代碼都要重新生成。
比如說,以下代碼片段顯示了為Ballerina生成的gRPC服務的代碼。 對于我們在gRPC服務定義中的每個操作,都會生成相應的Ballerina代碼。(Ballerina提供了開箱即用的功能,使用“ballerina grpc –input inventory.proto –output service-skeleton –mode service”或“ballerina grpc –input inventory.proto –output bal-client –mode client”,生成服務代碼或客戶端代碼)。
- import ballerina/grpc;
- import ballerina/io;
- endpoint grpc:Listener listener {
- host:"localhost",
- port:9000
- };
- @grpc:ServiceConfig
- service InventoryService bind listener {
- getItemByName(endpoint caller, string value) {
- // Implementation goes here.
- // You should return a Items
- }
- getItemByID(endpoint caller, string value) {
- // Creating a dummy inventory item
- Item requested_item;
- requested_item.id = value;
- requested_item.name = "Sample Item " + value ;
- requested_item.description = "Sample Item Desc for " + value;
- _ = caller->send(requested_item);
- _ = caller->complete();
- }
- addItem(endpoint caller, Item value) {
- // Implementation goes here.
- // You should return a boolean
- }
- }
至于客戶端,再次用Inventory服務的gRPC服務定義來生成產品搜索服務,這是一個Java(Spring Boot)服務。你可以使用maven插件為Spring Boot/Java服務生成客戶端存根(客戶端代碼嵌入在Spring Boot服務中)。調用生成的客戶端存根的客戶端代碼如下所示:
- package mfe.ch03.grpc;
- import com.google.protobuf.StringValue;
- import io.grpc.ManagedChannel;
- import io.grpc.ManagedChannelBuilder;
- public class InventoryClient {
- public static void main(String[] args) {
- ManagedChannel channel = ManagedChannelBuilder.forAddress("127.0.0.1", 9000)
- .usePlaintext()
- .build();
- InventoryServiceGrpc.InventoryServiceBlockingStub stub
- = InventoryServiceGrpc.newBlockingStub(channel);
- Inventory.Item item = stub.getItemByID(
- StringValue.newBuilder().setValue("123").build());
- System.out.println("Response : " + item.getDescription());
- }
- }
底層的通信
客戶端調用服務時,客戶端gRPC庫使用協議緩沖區,并編組(marshal)遠程過程調用,該調用隨后通過HTTP2來發送。在服務器端,請求解組(un-marshalled),使用協議緩沖區執行相應的過程調用。響應遵循從服務器到客戶端的類似的執行流程。
使用gRPC開發服務和客戶端的主要優點是,你的服務代碼或客戶端代碼不需要為解析JSON或類似的基于文本的消息格式(在代碼內或隱含在Jackson等底層庫中,對服務代碼而言隱藏起來)操心。二進制格式解組、轉換成對象。此外,我們要處理多個微服務并確保和維護互操作性時,對通過IDL定義服務接口給予***支持是強大的功能。
用gRPC構建微服務的實例
基于微服務的應用程序由多個服務組成,并使用眾多編程語言構建?;跇I務使用場景,你可以選擇最合適的技術來構建服務。gRPC在這種多語言架構中起到非常重要的作用。如圖2所示,產品搜索服務與另外多個服務進行通信,這些服務是使用gRPC作為通信協議構建的。因此,我們可以為每個服務定義服務合約:庫存、電子品類和服裝品類等?,F在,如果你想要打造一種多語言架構,可以使用不同的實現技術來生成服務框架。
圖2顯示了用Ballerina lang編寫的庫存服務、用Golang編寫的電子服務和用Vert.x(Java)編寫的服裝服務??蛻舳诉€可以為這每個服務合約生成存根。
圖2
仔細研究圖2中的微服務通信風格,可以看出gRPC用于所有內部通信,而面向外部的通信可以基于REST或GraphQL。我們將REST用于面向外部的通信時,大多數外部客戶端可以將服務用作API(利用Open API等API定義技術),因為大多數外部客戶端知道如何與充分利用REST的HTTP服務進行通信。此外,我們可以使用GraphQL之類的技術,讓消費者可以根據特定的客戶需求來查詢服務,這是無法用gRPC提供便利的。
因此作為一般實踐,我們可以將gRPC用于內部微服務之間的所有同步通信。其他同步消息傳遞技術(比如充分利用REST的服務和GraphQL)更適合面向外部的服務。
作者簡介:WSO2架構團隊負責該公司集成平臺的開發工作,Kasun Indrasiri是該團隊的重要成員。之前,他作為產品主管參與開發了WSO2企業服務總線(ESB)。他撰有《WSO2 ESB入門》一書,并與人合著了《企業級微服務》。他是Apache軟件基金會的當選成員,還是Apache Synapse開源ESB項目的項目管理委員會成員和提交者。
原文標題:Build Real-World Microservices with gRPC,作者:Kasun Indrasiri
【51CTO譯稿,合作站點轉載請注明原文譯者和出處為51CTO.com】