PHP搞微服务杂谈(四) 实现GRPC服务反射
拉点家长
看这一篇的同学,如果对利用hyperf(php+swoole)+ gRPC 实现微服务还没了解可以翻一下前面的分享。使用hyperf + gRPC 的同学相信都看过了文档中关于gRPC的实现 hyperf.wiki/3.0/#/zh-cn/grpc。按照文档跑成功的服务,是没有反射的,也就是使用 Use Server Reflection 提示了异常。
先解释下为何要使用gRPC服务反射,服务反射是在开发/测试阶段方便调试,我们都清楚gRPC是通过protobuf定义服务,服务端是基于服务定义实现,而客户端也是基于服务定义去调用。gRPC 服务反射它能提供服务的定义信息,简单的来说,就是服务反射向客户端提供了服务的定义。 因此客户端不需要预编译服务定义就能与服务端进行交互。
当然可以不选择服务反射,我们可以在Postman中选用导入.proto文件。但每次定义文件更新就得跟着更新(再导入),就变成了……. 是的,难受
这个时候就开始羡慕起用GO实现的gRPC服务,只要注册反射就能享用,更新了定义点刷新就可以了
不行!PHP也得拥有!!!
模仿
是的,最快解决的方式就是参照 GO gRPC库对服务反射的实现 github.com/grpc/grpc-go/blob/maste... (感兴趣的同学可以研究下)
其实就是实现gRPC服务对反射的定义,定义如下:
github.com/grpc/grpc/blob/master/s...
根据请求类型,分别把服务列表(ListServices)、服务定义(FileDescriptor)响应即可。
服务列表的实现相对简单,我们是通过路由定义了服务路径,因此获取路由就能得到服务列表。
服务定义(FileDescriptor)就复杂很多了,从GO实现上看是需要将 FileDescriptor 通过 proto.Marshal 转字节,再将字节类型的数据响应。当然在此之前我们还得通过两种方式找到 FileDescriptor,一种是 (file_by_filename) 通过文件名获取定义,例如 xxx/xxx/xxx.proto。另一种是(file_containing_symbol)通过声明获取 如:package.service.method。
了解了如何处理 就开干!
实现
第一步:肯定是先根据服务定义完成方法,配置好路由
第二步:实现不同的请求类型
这边我只实现了这三种请求类型,也能满足反射,但实际上还包括其他类型(感兴趣同学可以接着完成)。获取服务列表(ListServices)相对简单,大家可以看代码了解下github.com/crayxn/hyperf-grpc/blob... 。FileContainingSymbol、FileByFilename 两个其实是一样的就是为了获取到服务定义,并转byte类型 响应。
第三步:获取服务定义
跟Go不同的是,通过gRPC官方PHP插件生成的代码,是自带Byte类型的文件内容,再通过内容生成 FileDescriptor 并 存到 \Google\Protobuf\Internal\DescriptorPool 池里。
这边我为了偷懒,就直接rewrite了DescriptorPool 实现了通过类获取proto文件名、通过proto文件名获取服务定义内容。因为已经有Byte类型的定义内容就偷懒不再先获取FileDescriptor再去转Byte(找个借口,大家应该清楚php转byte的难受)。
第四步:响应
最后将不同请求类型对应的响应对象设置完成响应就可以了。
相关实现可以参照:github.com/crayxn/hyperf-grpc/blob...
运行demo可以参照:github.com/crayxn/grpc-stream-demo
如果对您有帮助,就点个赞吧
本作品采用《CC 协议》,转载必须注明作者和本文链接
顶顶
:+1: :+1: :+1: :+1: :+1: :+1: :+1:
环境 用的你的docker 镜像
帮看看是啥问题