写点什么

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

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

关注

评论 4 条评论

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

燃烧吧!开发者们,一起在云端构建开放成熟的 ARM 生态!

亚马逊云科技 (Amazon Web Services)

面试必备知识点!2021Android大厂面试知识分享,offer拿到手软

欢喜学安卓

android 程序员 面试 移动开发

使用Spark Mllib进行数据分析

大数据技术指南

大数据 spark 28天写作 3月日更

办公自动化:Day01

缭乱地男神

办公自动化 IT蜗壳教学

白话解读 WebRTC 音频 NetEQ 及优化实践

阿里云CloudImagine

阿里云 音视频 WebRTC 音频技术 视频云

你的头发还好吗?大数据分析脱发城市哪里强

不脱发的程序猿

大数据 程序员 程序人生 数据分析 3月日更

华为在数字化浪潮下的API变革实践

华为云开发者联盟

华为 架构 数字化 API API战略

大作业--联合运营平台

ALone

JVM笔记--如果你写JVM,最需要考虑的重要结构是什么?

秦怀杂货店

Java JVM

为什么MySQL不推荐使用子查询和join

Java小咖秀

MySQL MySQL优化

网易 Duilib:功能全面的开源桌面 UI 开发框架

有道技术团队

开源

寻找被遗忘的勇气(十六)

Changing Lin

3月日更

Rancher 2.5.6发布,支持Kubernetes 1.20

Rancher

OpenCV萌新福音:易上手的数字识别实践案例

华为云开发者联盟

OpenCV 图像处理 数字 图像预处理 信用卡

别再做智慧园区无效投入了!想要高效运行试试这个方法

一只数据鲸鱼

物联网 数据可视化 智慧城市 智慧园区

不愧为Java程序员福音 2021阿里巴巴中台架构实战重磅来袭!

比伯

Java 编程 架构 面试 程序人生

语音通话 2.0

anyRTC开发者

音视频 WebRTC RTC 语音通话

挑灯夜战800个小时,终从外包成功上岸字节!入职那一天我眼眶湿润了「Java岗」

Java架构之路

Java 程序员 架构 面试 编程语言

EFT是什么?EGG公链又是什么?一文带你了解

币圈那点事

公链 挖矿 #区块链#

第一个mybatis程序,实现CRUD

xiezhr

mybatis 中间件 crud

软件匠艺

Teobler

敏捷 敏捷开发 软件匠艺 伪敏捷

APP搜索如何又快又准?

华为云开发者联盟

elasticsearch App 搜索 云搜索 词库

Java面试“圣经”,已助朋友拿到7个Offer!2021年金三银四面试知识点合集

Java架构追梦

Java 阿里巴巴 面试 架构师

看了 GitHub 上的这些面试题项目后,我飘了!

JackTian

GitHub 开源 面试

我帮大厂做架构之——微信的“N个朋友读过”怎么实现

臧萌

成长 架构师 职场成长

【LeetCode】螺旋矩阵 II Java 题解

Albert

算法 LeetCode 28天写作 3月日更

史上超强拷贝仓——GitHub 热点速览 v.21.11

HelloGitHub

GitHub 开源

初识Golang之声明变量

Kylin

读书笔记 3月日更 21天挑战 Java转go Go 语言

还在等机会?Android岗面试12家大厂成功跳槽,最全的BAT大厂面试题整理

欢喜学安卓

android 程序员 面试 移动开发

几个你不知道的dubbo注册中心细节

捉虫大师

zookeeper dubbo 注册中心

带你全面认识CMMI V2.0(二)

IPD产品研发管理

项目管理 CMMI

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