Lazy loaded image
开发
🗒️GRPC 学习笔记
字数 4898阅读时长 13 分钟
2022-8-11
2023-11-24
type
Post
status
Published
date
Aug 11, 2022 14:54
slug
page-23
summary
GRPC 学习笔记
tags
开发
category
开发
icon
password
🌊
这么久了?一年没更新

简介

gRPC 是 Google 开源的一个远程过程调用(Remote Procedure Call) 框架,在 gRPC 中,客户端应用程序可以直接调用不同机器上的服务器应用程序上的方法,就像它是本地对象一样,更容易创建分布式应用程序和服务。默认情况下,gRPC 使用 协议缓冲区 通信, 并支持以下语言:
notion image

协议缓冲区 (protocol buffers)

协议缓冲区提供了一种语言中立、平台中立、可扩展的机制,用于以向前兼容和向后兼容的方式序列化结构化数据。它类似于 JSON,只是它更小更快,并且生成本地语言绑定。 协议缓冲区是定义语言(在 .proto文件中创建)、proto 编译器生成的与数据接口的代码、特定于语言的运行时库以及写入文件(或通过网络连接)。
使用协议缓冲区的第一步是定义要在_proto 文件_中序列化的数据的结构:这是一个带有.proto扩展名的普通文本文件。协议缓冲区数据被构造为_消息_,其中每条消息都是一个小的信息逻辑记录,包含一系列称为_字段_的名称-值对。这是一个简单的例子:

生成 gRPC 代码

一旦定义好服务,我们可以使用 protocol buffer 编译器 protoc 来生成创建应用所需的特定客户端和服务端的代码。 首先运行 brew install protobuf 安装 protoc https://github.com/protocolbuffers/protobuf/releases
其次安装 go 的插件
默认下载到$GOPATH/bin下。 指定源目录(应用程序的源代码所在的位置——如果不提供值,则使用当前目录)、目标目录(希望生成的代码所在的位置;通常与$SRC_DIR相同) ,以及.protp文件.
生成两个文件:
  • helloworld.pb.go 文件 ,包含用于填充、序列化和检索请求和响应消息类型的所有协议缓冲区代码。
  • helloworld_grpc.pb.go 文件, 其中包含以下内容:
    • 客户端使用Greeter服务中定义的方法调用的接口类型(或存根)。
    • 服务器要实现的接口类型,也可以使用Greeter服务中定义的方法。

服务端

客户端

service 方法的4 种请求和响应模式类型

  • 一个_简单的 RPC_,其中客户端使用存根向服务器发送请求并等待响应返回,就像正常的函数调用一样。
前面的SayHello方法 就是一个简单RPC
  • 服务器端流式 RPC ,客户端发送请求到服务器,拿到一个流去读取返回的消息序列。 客户端读取返回的流,直到里面没有任何消息。从例子中可以看出,通过在 响应 类型前插入stream关键字,可以指定一个服务器端的流方法。
  • 一个 客户端流式 RPC , 客户端写入一个消息序列并将其发送到服务器,同样也是使用流。一旦客户端完成写入消息,它等待服务器完成读取返回它的响应。通过在 请求 类型前指定 stream 关键字来指定一个客户端的流方法。
  • 一个 双向流式 RPC 是双方使用读写流去发送一个消息序列。两个流独立操作,因此客户端和服务器可以以任意喜欢的顺序读写:比如, 服务器可以在写入响应前等待接收所有的客户端消息,或者可以交替的读取和写入消息,或者其他读写的组合。 每个流中的消息顺序被预留。你可以通过在请求和响应前加 stream 关键字去制定方法的类型。

身份验证

gRPC 底层是基于 HTTP/2 协议的,HTTP 本身不带任何加密传输功能,基于 SSL 的 HTTPS 协议才是加密传输。gRPC 使用了 HTTP/2 协议但是并未使用 HTTPS,即少了加密传输的部分。 对于加密传输的部分 gRPC 将它抽出来作为一个组件,可以由用户自由选择。gRPC 内默认提供了两种 内置的认证方式:
  • 基于 CA 证书的 SSL/TLS 认证方式;
  • 基于 Token 的认证方式。
gRPC 中的连接类型一共有以下 3 种:
  • insecure connection:不使用 TLS 加密;
  • server-side TLS:仅服务端 TLS 加密;
  • mutual TLS:客户端、服务端都使用 TLS 加密。

基于 TLS/SSL 认证

1.ca根证书生成

新建ca.conf,填入以下内容:
生成ca.key:
生成ca.csr:(直接回车,采用default默认配置值)
生成ca.crt:

2.server证书生成

新建server.conf,填入以下内容:
生成server.key:
生成server.csr:(直接回车,采用default默认配置值)
生成server.crt:
最终只需要 server.pemserver.key两个文件
这样就可以对客户端和服务端之间交互的所有数据进行加密。

Token认证

客户端发请求时,添加Token到上下文context.Context中,服务器接收到请求,先从上下文中获取Token验证,验证通过才进行下一步处理。 gRPC 中默认定义了 PerRPCCredentials,是提供用于自定义认证的接口,它的作用是将所需的安全认证信息添加到每个RPC方法的上下文中。其包含 2 个方法:
  • GetRequestMetadata:获取当前请求认证所需的元数据
  • RequireTransportSecurity:是否需要基于 TLS 认证进行安全传输
使用 token 认证必须实现这两个方法。 这里以 JWT作为 Token 认证为例,新建jwt.go文件
helloworld.proto增加以下代码
执行 protoc --go_out=helloworld --go-grpc_out=helloworld helloworld/helloworld.proto重新生成对应的文件 server.go 实现 Login方法
然后服务端代码中,每个服务的方法都需要添加CheckAuth(ctx)来验证Token,这样十分麻烦。这里使用gRPC拦截器,能够很好地解决这个问题。gRPC拦截器功能类似中间件,拦截器收到请求后,先进行一些操作,然后才进入服务的代码处理。 服务端完整代码
客户端代码

双向流

普通RPC 就像正常调用方法一样,主要就是流式的使用,这里以双向流为例
服务端实现
客户端

流式拦截器

流拦截器过程和一元拦截器有所不同,同样可以分为 3 个阶段:
  • 预处理(pre-processing)
  • 调用 RPC 方法(invoking RPC method)
  • 后处理(post-processing)
预处理阶段的拦截只是在流式请求第一次 发起的时候进行拦截,后面的流式请求不会再进入到处理逻辑。 后面两种情况对应着 Streamer api 提供的两个扩展方法来进行,分别是 SendMsg 和 RecvMsg 方法。 正常情况下实现一个流式拦截器与普通拦截器一样,实现这个已经定义好的拦截器方法即可:
如果是想在发消息之前和之进行处理, 则实现 SendMsg 和 RecvMsg
使用流式拦截器服务端修改, 下面就是同时使用流式和普通拦截器
流式拦截器认证

发布订阅模式

服务端的信息更改时,通知客户端
服务端
客户端
上一篇
弈 - Codeql 自动运行和项目监控工具
下一篇
git 蜜罐复现

评论
Loading...