【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

使用 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:447409
用户头像

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

关注

评论 4 条评论

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

嵌入式系统的开发概述

timerring

嵌入式 12月月更

web前端培训程序员学习什么呢

小谷哥

三种基本排序

我是一个茶壶

排序算法 C语音 11月月更

​ AngularJS进阶(七)AngularJS实现根据不同条件显示不同控件

No Silver Bullet

AngularJS 12月月更 条件筛选

极客时间运维进阶训练营第六周作业

9527

实践案例:同程艺龙网的 Dubbo 升级经验总结

Apache Dubbo

Java 开源 微服务 云原生 dubbo

【云享·人物】华为云AI高级专家白小龙:AI如何释放应用生产力,向AI工程化前行?

华为云开发者联盟

人工智能 华为云 AI工程化 12 月 PK 榜

打造无证服务化:这个政务服务平台有点不一样

华为云开发者联盟

区块链 华为云 12 月 PK 榜

华为云CDN 真的有点“东西”!极速网上冲浪全靠它

爱科技的水月

Hash 的定义

HoneyMoose

Dubbo 3.1.3、3.2.0-beta.2 正式发布

Apache Dubbo

Java 开源 微服务 云原生 dubbo

安全配置错误规避指南

SEAL安全

配置管理 企业安全 安全配置 配置错误 12 月 PK 榜

旺链科技荣膺“2022上海软件核心竞争力企业”

旺链科技

区块链 产业区块链 12 月 PK 榜

云小课|云小课带你玩转可视化分析ELB日志

华为云开发者联盟

云计算 后端 华为云 12 月 PK 榜

Java Hash 碰撞

HoneyMoose

Java HashMap 在获得 Key 的 Hash 值的时候用的是什么算法

HoneyMoose

Vision Transformer这两年

OneFlow

人工智能 深度学习 NLP 大模型

HashMap 的初始值和最大值和扩容因子

HoneyMoose

Java HashMap 的扩容因子为什么是 0.75

HoneyMoose

MASA Framework 事件总线 - 跨进程事件总线

MASA技术团队

.net MASA Framewrok MASA

设计模式之美--MVC(1)充血模型的DDD开发模式例子

GalaxyCreater

设计模式

瓴羊Quick BI数据大屏,服务企业数字化转型发展

巷子

JavaScript进阶(八)实现图片预览并导入服务器功能

No Silver Bullet

图片预览 AngularJS 12月月更

阿里云视觉智能开放平台——年终特惠来袭

夏夜许游

人工智能 AI 视觉 特惠

双十一特惠,华为云桌面助力便捷高效办公!

爱科技的水月

一个有点咬文嚼字的 sorting 和 ordering

HoneyMoose

AngularJS进阶(九)控制器controller之间如何通信

No Silver Bullet

通信 AngularJS 12月月更

上海大数据培训机构怎么选择比较好

小谷哥

架构实战营模块一作业

张贺

架构实战营

企业云上办公的最佳选择——华为云桌面Workspace

爱科技的水月

一文了解 Go 标准库 strconv:string 与其他基本数据类型的转换

陈明勇

Go golang string 11月月更 strconv

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