使用gRPC构建真实世界的微服务

早期的微服务实现主要使用REST架构作为事实上的通信技术。通常,RESTful服务对于面向外部的服务会很有用,这些服务直接暴露给消费者。它们是基于传统的文本消息传递(JSON、XML、基于HTTP的CVS等),但这些消息主要是面向人类的,并不是服务间通信的理想选择。

除了使用基于文本的消息传递协议,我们还可以使用针对服务间通信而优化的二进制协议。云原生计算基金会(CNCF)的gRPC(gRPC远程过程调用)就是服务间通信的一个理想选择,因为它使用protobuf作为服务间通信的二进制数据交换格式。

当我们使用不同的技术和编程语言构建多个微服务时,需要有一个标准的方法来定义服务接口和底层消息交换格式。gRPC提供了一种简洁而强大的使用protobuf来定义服务合约的方法。因此,gRPC可能是构建内部微服务间通信最可行的解决方案。

在本文中,我们将仔细探究为什么gRPC是构建微服务间通信的绝佳选择。

gRPC基础

在使用gRPC时,客户端可以直接调用不同机器上的服务器应用程序,就好像是在调用本地对象一样。gRPC以传统的远程过程调用(RPC)技术为基础,但是在现代技术栈(如HTTP2、protobuf等)之上实现的,以确保能够提供最大的互操作性。

gRPC本身支持使用gRPC接口定义语言(IDL)来定义服务合约。因此,作为服务定义的一部分,你可以指定可远程调用的方法以及参数和返回类型的数据结构。

下图画出了gRPC与在线零售应用程序中的应用,这个应用程序是库存和产品搜索服务的一部分。库存服务的合约是使用gRPC IDL定义的,在inventory.proto文件中指定。库存服务的开发人员首先定义好所有的业务功能,然后根据proto文件生成服务端框架代码。类似地,可以使用相同的proto文件生成客户端存根代码。

\"\"

由于gRPC与编程语言无关,你可以使用异构语言来构建服务和客户端。在这个例子中,我们使用Ballerina(ballerina.io)生成服务端代码,使用Java生成客户端代码。你可以参考GitHub上的源代码示例

库存(inventory.proto)的服务合约如下所示:

syntax = \u0026quot;proto3\u0026quot;;package grpc_service;import \u0026quot;google/protobuf/wrappers.proto\u0026quot;;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:\u0026quot;localhost\u0026quot;,   port:9000};@grpc:ServiceConfigservice 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 = \u0026quot;Sample Item \u0026quot; + value ;       requested_item.description = \u0026quot;Sample Item Desc for \u0026quot; + value;       _ = caller-\u0026gt;send(requested_item);       _ = caller-\u0026gt;complete();   }   addItem(endpoint caller, Item value) {       // Implementation goes here.       // You should return a boolean   }}

同样,从库存服务的gRPC服务定义生成产品搜索服务客户端(一个Spring Boot Java服务)。你可以使用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(\u0026quot;127.0.0.1\u0026quot;, 9000)               .usePlaintext()               .build();       InventoryServiceGrpc.InventoryServiceBlockingStub stub               = InventoryServiceGrpc.newBlockingStub(channel);       Inventory.Item item = stub.getItemByID(StringValue.newBuilder().setValue(\u0026quot;123\u0026quot;).build());       System.out.println(\u0026quot;Response : \u0026quot; + item.getDescription());   }}

底层通信

当客户端调用服务时,客户端gRPC库使用protobuf封装远程过程调用,然后通过HTTP2发送出去。在服务器端,请求被解封,并且通过protobuf执行相应的过程调用。响应遵循类似的流程,从服务器端发送到客户端。

gRPC的主要优点是你的服务代码或客户端代码不需要去解析JSON或其他基于文本的消息格式。网络上传输的内​​容是二进制格式,会被组装成对象。此外,当我们需要处理多个微服务并确保和维护互操作性时,通过IDL定义服务接口是一个强大的功能。

一个使用gRPC的微服务用例

基于微服务的应用程序由多种服务组成,并使用了多种编程语言。你可以根据业务用例选择最合适的技术来构建你的服务。gRPC在这种多语言架构中起着非常重要的作用。我们将进一步扩展之前的在线零售用例。如下图所示,产品搜索服务与多个其他服务通信,这些服务使用gRPC作为通信协议。因此,我们可以为每个服务定义服务合约:库存、电子产品、服装等。现在,如果你想要使用多语言架构,可以使用不同的实现技术来生成服务框架代码。

下图显示了使用Ballerina的库存服务、使用Go语言的电子服务和使用Vert.x(Java)的服装服务。客户端也可以为每个服务合约生成存根。

\"\"

仔细看一下上图中的微服务通信风格,可以看出,gRPC被用在所有的内部通信上,而面向外部的通信主要基于REST或GraphQL。当我们使用REST进行面向外部的通信时,大多数外部客户端可以将服务作为API(可以利用API定义技术,如Open API),因为大多数外部客户端都知道如何与HTTP RESTful服务通信。此外,我们可以使用诸如GraphQL之类的技术让消费者根据特定的客户需求来查询服务,这是gRPC无法提供的。

因此,作为一般实践,我们可以使用gRPC进行内部微服务之间的同步通信,而其他同步消息传递技术(如RESTful服务和GraphQL)更适合面向外部的服务。

英文原文

https://thenewstack.io/build-real-world-microservices-with-grpc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值