Skip to content

110.接入grpc相关思路(2)

大家好~我是米洛
我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的教程,希望大家多多支持。
欢迎关注我的公众号米洛的测开日记,获取最新文章教程!

回顾

上一节我们浅谈了支持grpc的相关思路,只抛出了问题,但没有解决问题,那这一节我们就来聊聊相关的解决方案。

核心问题

回到之前的核心问题,我们在进行一次grpc的请求时,首先不太明确服务部署的地址,当服务是多节点部署的时候,我们希望能够自动获取到服务的ip和端口。这个问题挺好解决,业内常用的注册中心就那几种,还记得我们之前讲过的系统设置页面吗?

系统设置里面现在可以多加一项,注册中心类型/注册中心地址/服务/方法节点路径,根据配置好的设置针对不同的注册中心,完成我们想要的功能。

但还有一个stub的问题,这个虽然比较麻烦,但也不是没有办法解决

grpcurl

上一节我们提到过一个关键词: grpc_reflection。没错,这就是我们解决问题的关键。

在介绍反射的时候,我们先来看看一款工具: grpcurl(github一搜就知道)

不难发现,其实它是一款类似于CURL的工具,基于go编写。api也和curl比较接近,但有个问题,它并没有提供python的api。

由于我具备go代码的阅读能力,所以我很好奇它是怎么支持无proto调用grpc接口的,为此我前段时间一直在阅读它的源码。

在阅读他代码的时候,我意外地发现了grpc的一个特质: grpc_reflection,这个简单的说就是grpc反射。(资料也相当少)

服务端开启反射

  1. 安装grpcio-reflection
pip install grpcio-reflection
  1. 允许服务开启反射

这边别忘记

from grpc_reflection.v1alpha import reflection

这样启动的时候,服务就开启了反射,我们就可以用grpcurl请求接口了。

简单的说,在grpc服务启动的时候,如果打开了grpc_reflection开关,那么它会自带额外的几个grpc接口,而我们使用的grpcurl也是基于这个原理而工作的。我们来看看它们一一做了些什么

我们可以看到,反射的服务,主要提供了一个反射服务,里面会有file_by_filename,list_services等方法。其中list_services可以列举出你这个ip+port下的grpc服务有哪些服务,核心的实现方法都在这:

为此本人熬了2天左右,终于完成了一个可以摆脱proto的类似grpcurl的实现,在此感谢grpcurl提供的思路。(对着源码debug)

最终的实现效果如下:

只需要自己定义一个Stub(因为反射也是个grpc服务,所以我们还是得通过生成反射的stub去获取服务的信息)。

上面的res是获取服务列表并打印,与下面的调用没关系,实际上调用的方法只需要:

md = Stub.client(channel, "Hello", "Edit")

params = dict(data="李逍遥")
data = hello_pb2.Request(**params)
response = md(data)
print(response.message)

md是通过反射的客户端+服务名+方法名获取到方法,接着直接传入dict即可调用方法。

两级反转

为啥要做这个库,因为我确实没搜到类似的实现。就当我优化了一些版本,还没支持异步,也没完善各种api的时候,我得意地想把我这个版本传到pypi帮助其他人。

关于命名,我想要它以后和requests一样好用,所以我毫不犹豫叫了grpc-requests,发现一直上传失败。

我在pypi搜索,结果发现一个韩国哥们早就实现了,而且做的还比我屌多了,我比克大魔王当时脸都绿了!!!

我下载了试用了一番,别人已经碉堡了,而且测下来也没发现啥问题。

所以我肝2天肝了个寂寞,不过把具体的api是熟悉了一遍。所以大家如果有类似需求,直接用这个库就可以了!!!

我还是咬着牙传了自己的项目到pypi

这哥们说,如果你的服务开启了反射,你可以自动获取到方法等数据,否则可以继续用stub去调用。我看了这哥们的实现,代码确实写的好过我很多。


今天的内容就介绍到这里了,关于后续的想法,grpc也是可以根据文件获取到服务信息,唯一我们以后能做的就是根据proto生成接口文档。

(我想这个就算个卖点吧,各位有兴趣也可以自行实现哈!)