写点什么

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

  • 2018-12-06
  • 本文字数:2850 字

    阅读完需:约 9 分钟

使用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 = "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: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 = "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 }
}

复制代码


同样,从库存服务的 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("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 库使用 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


2018-12-06 10:447877
用户头像

发布了 731 篇内容, 共 448.8 次阅读, 收获喜欢 2002 次。

关注

评论 4 条评论

发布
用户头像
例子的操作步骤不够详细
2018-12-09 10:32
回复
用户头像
2018-12-07 16:46
回复
没有更多了
发现更多内容

真正的千万级分布式延迟任务系统 Grape

dinstone

一个普通程序员如何看待chatgpt大火 | 社区征文

不觉心动

年中技术盘点

带你走进 IntelliJ IDEA 的插件世界

冰心的小屋

idea plugin

ClickHouse 学习分享

冰心的小屋

OLAP Clickhouse

Cnetos7编译安装Apache教程。

百度搜索:蓝易云

Apache 云计算 Linux centos 运维

Cnetos7编译安装Memcached教程。

百度搜索:蓝易云

memcached 云计算 Linux centos 运维

GitHub Copilot深度剖析:一个AI产品的性能提升、成本控制与效果评估

无人之路

ChatGPT Copilot

Visual Studio Code错误:Cannot build and debug because the active file is not a C or C++ source file

codists

Visual Studio Code

PyTorch: 权值初始化

timerring

PyTorch

Cnetos7编译安装Nginx教程。

百度搜索:蓝易云

nginx 云计算 Linux centos 运维

从头学Java17-今天的Kotlin更香吗

烧霞

kotlin java17

2023-07-15:给你一个 非递减 的正整数数组 nums 和整数 K, 判断该数组是否可以被分成一个或几个 长度至少 为 K 的 不相交的递增子序列。 输入:nums = [1,2,2,3,3,

福大大架构师每日一题

Go rust 福大大架构师每日一题

Antlr4如何自动解析得到AST而不是ParseTree

canonical

ANTLR 低代码 dsl antlr4

Apache Doris 用户行为分析实践

冰心的小屋

数据仓库 OLAP Doris

代码随想录 Day17 - 二叉树(四)

jjn0703

Open AI爆火,4个中国版ChatGPT扎堆爆发 | 社区征文

我搬去水星了

年中技术盘点

可爱小猫猫【InsCode Stable Diffusion美图活动一期】

繁依Fanyi

c++类型转换与RTTI运行阶段类型识别

梦笔生花

Open-OAuth2Playground:开箱即用的开源版OAuth2在线调试服务

冯骐

OAuth 2.0 Go 语言 开放平台 API 调试 Playground

Cnetos7编译安装phpMyAdmin教程。

百度搜索:蓝易云

云计算 Linux centos 运维 phpMyAdmin

Cnetos7编译安装Docker教程。

百度搜索:蓝易云

Docker 云计算 Linux centos 运维

WAIC2023丨AI图像内容安全“黑科技”如何助力科技向善发展?

陈橘又青

chatgpt和文心一言哪个更厉害 | 社区征文

张三丰无极

年中技术盘点

IoTOS-v1.5.3 新增 智能诊断&会话记录导出

开源物联卡管理平台-设备管理

物联网平台 IoT 开源物联网 国产开源 开源项目介绍

Cnetos7编译安装MySQL教程。

百度搜索:蓝易云

MySQL Linux centos 运维 云服务器

强化学习:基于蒙特卡洛树和策略价值网络的深度强化学习五子棋(含码源)

汀丶人工智能

人工智能 深度学习 蒙特卡洛 强化学习

Linux系统安装HomeAssistant教程。

百度搜索:蓝易云

Linux 运维 云服务器 Home Assistant

来自 BOSS 的需求,我们该怎么处理?

Bonaparte

产品 产品需求 BOSS需求 需求处理

小设计,大作用——谈谈防腐层的妙用

JAVA旭阳

Java

Ins风韩国美少女【InsCode Stable Diffusion美图活动一期】

繁依Fanyi

使用gRPC构建真实世界的微服务_语言 & 开发_Kasun Indrasiri_InfoQ精选文章