无缝衔接 gRPC 与 dubbo-go
最近我们 dubbo-go 社区里面,呼声很大的一个 feature 就是对 gRPC 的支持。在某位大佬的不懈努力之下,终于弄出来了。
今天我就给大家分析一下大佬是怎么连接 dubbo-go 和 gRPC 。
gRPC
先来简单介绍一下 gRPC 。它是 Google 推出来的一个 RPC 框架。gRPC是通过 IDL ( Interface Definition Language )——接口定义语言——编译成不同语言的客户端来实现的。可以说是RPC理论的一个非常非常标准的实现。
因而 gRPC 天然就支持多语言。这几年,它几乎成为了跨语言 RPC 框架的标准实现方式了,很多优秀的rpc框架,如 Spring Cloud 和 dubbo ,都支持 gRPC 。
server 端
在 Go 里面,server 端的用法是:
它的关键部分是:s := grpc.NewServer()和pb.RegisterGreeterServer(s, &server{})两个步骤。第一个步骤很容易,唯独第二个步骤RegisterGreeterServer有点麻烦。为什么呢?
因为pb.RegisterGreeterServer(s, &server{})这个方法是通过用户定义的protobuf编译出来的。
好在,这个编译出来的方法,本质上是:

也就是说,如果我们在 dubbo-go 里面拿到这个 _Greeter_serviceDesc ,就可以实现这个 server 的注册。因此,可以看到,在 dubbo-go 里面,要解决的一个关键问题就是如何拿到这个 serviceDesc 。
Client 端
Client 端的用法是:
这个东西要复杂一点:
1、创建连接:conn, err := grpc.Dial(address)
2、创建client:c := pb.NewGreeterClient(conn)
3、调用方法:r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
第一个问题其实挺好解决的,毕竟我们可以从用户的配置里面读出 address ;
第二个问题就是最难的地方了。如同 RegisterGreeterServer 是被编译出来的那样,这个 NewGreeterClient 也是被编译出来的。
而第三个问题,乍一看是用反射就能解决,但是我们打开 SayHello 就能看到:
结合 greetClient 的定义,很容易看到,我们的关键就在于 err := c.cc.Invoke ( ctx, "/helloworld.Greeter/SayHello", in, out, opts... )。换言之,我们只需要创建出来连接,并且拿到方法、参数就能通过类似的调用来模拟出 c.SayHello 。
通过对 gRPC 的简单分析,我们大概知道要怎么弄了。还剩下一个问题,就是我们的解决方案怎么和 dubbo-go 结合起来呢?
设计
我们先来看一下 dubbo-go 的整体设计,思考一下,如果我们要做 gRPC 的适配,应该是在哪个层次上做适配。
我们根据前面介绍的 gRPC 的相关特性可以看出来,gRPC 已经解决了 codec 和 transport 两层的问题。
而从 cluster 往上,显然 gRPC 没有涉及。于是,从这个图里面我们就可以看出来,要做这种适配,那么 protocol 这一层是最合适的。即,我们可以如同 dubbo protocol 那般,扩展出来一个 grpc protocol 。
这个 gRPC protocol 大体上相当于一个适配器,将底层的 gRPC 的实现和我们自身的 dubbo-go 连接在一起。

实现
在 dubbo-go 里面,和 gRPC 相关的主要是:

我们直接进去看看在 gRPC 小节里面提到的要点是如何实现的。
server端

这样看起来,还是很清晰的。如同 dubbo- go 其它的 protocol 一样,先拿到 service ,而后通过 service 来拿到 serviceDesc ,完成服务的注册。
注意一下上图我红线标准的 ds, ok := service.(DubboGrpcService) 这一句。
为什么我说这个地方有点奇怪呢?是因为理论上来说,我们这里注册的这个 service 实际上就是 protobuf 编译之后生成的 gRPC 服务端的那个 service ——很显然,单纯的编译一个 protobuf 接口,它肯定不会实现 DubboGrpcService 接口:

那么 ds, ok := service.(DubboGrpcService) 这一句,究竟怎么才能让它能够执行成功呢?
我会在后面给大家揭晓这个谜底。
Client端
dubbo-go 设计了自身的 Client ,作为对 gRPC 里面 Client 的一种模拟与封装:
注意看,这个 Client 的定义与前面 greetClient 的定义及其相似。再看下面的 NewClient 方法,里面也无非就是创建了连接 conn ,而后利用 conn 里创建了一个 Client 实例。
注意的是,这里面维护的 invoker 实际上是一个 stub 。
当真正发起调用的时候:

红色框框框住的就是关键步骤。利用反射从 invoker ——也就是 stub ——里面拿到调用的方法,而后通过反射调用。
代码生成
前面提到过 ds, ok := service.(DubboGrpcService) 这一句,面临的问题是如何让 protobuf 编译生成的代码能够实现 DubboGrpcService 接口呢?
有些小伙伴可能也注意到,在我贴出来的一些代码里面,反射操作会根据名字来获取method实例,比如NewClient方法里面的method := reflect.ValueOf(impl).MethodByName("GetDubboStub")这一句。这一句的impl,即指服务的实现,也是 protobuf 里面编译出来的,怎么让 protobuf 编译出来的代码里面含有这个 GetDubboStub 方法呢?
到这里,答案已经呼之欲出了:修改 protobuf 编译生成代码的逻辑!
庆幸的是,在 protobuf 里面允许我们通过插件的形式扩展我们自己的代码生成的逻辑。
所以我们只需要注册一个我们自己的插件:
然后这个插件会把我们所需要的代码给嵌入进去。比如说嵌入GetDubboStub方法:
还有DubboGrpcService接口:

这个东西,属于难者不会会者不难。就是如果你不知道可以通过plugin的形式来修改生成的代码,那就是真难;但是如果知道了,这个东西就很简单了——无非就是水磨工夫罢了。
无缝衔接 gRPC 与 dubbo-go的更多相关文章
- 无缝衔接demo
如题. <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" con ...
- DJI Terra+EasyEarth让数据获取与应用无缝衔接
大数据时代对地理信息数据的获取与应用提出了更高的要求: ⏩低成本.全要素.高效获取 ⏩数据采集.处理到应用无缝衔接 DJI Terra大疆智图 DJI Terra大疆智图是一款提供自主航线规划.飞行航 ...
- ASP.NET Core GRPC 和 Dubbo 互通
一.前言 Dubbo 是比较流行的服务治理框架,国内不少大厂都在使用.以前的 Dubbo 使用的是私有协议,采集用的 hessian 序列化,对于多语言生态来说是极度的不友好.现在 Dubbo 发布了 ...
- Dubbo 在跨语言和协议穿透性方向的探索:支持 HTTP/2 gRPC
Dubbo 在跨语言和协议穿透性方向上的探索:支持 HTTP/2 gRPC 和 Protobuf 本文整理自刘军在 Dubbo 成都 meetup 上分享的<Dubbo 在多语言和协议穿透性方向 ...
- Dubbo Spring Cloud 之 HTTP 实战
上一篇文章<Spring Cloud Alibaba | Dubbo 与 Spring Cloud 完美结合>我们介绍了Dubbo Spring Cloud的基本使用,使用的服务中心为Sp ...
- dotnet core 之 gRPC
dotnet core gRPC 原文在本人公众号中,欢迎关注我,时不时的会分享一些心得 HTTP和RPC是现代微服务架构中很常用的数据传输方式,两者有很多相似之处,但是又有很大的不同.HTTP是一种 ...
- dubbo使用和配置讲解
1. 分布式系统中相关概念 1.1 互联网项目特点及目标 1.1.1 特点: 用户多 流量大.并发高 海量数据 易受攻击 功能繁琐 变更快 1.1.2 指标及相关目标 互联网项目三高目标:高并发.高可 ...
- Swift - 多层无缝循环滚动背景(SpriteKit游戏开发)
在游戏开发中,比如跑酷游戏.我们需要实现背景的无限循环滚动,来营造运动的效果.除了单层的背景滚动,还有视差滚动. 视差滚动是指让多层背景以不同的速度移动,形成立体的效果,从而带来非常出色的视觉体验. ...
- 用CSS3实现无限循环的无缝滚动
有时候在页面的某个模块中,需要无限循环的滚动一些消息.那么如果我们用js实现无缝衔接滚动的思路是什么呢(比如我们这个模块是向上滚动的)? 克隆A一份完全一样的数据B放在原数据A的后面: 使用setIn ...
- 基于 IJKPlayer-concat 协议的视频无缝拼接技术实现
一.前言 Hi,大家好,我是承香墨影! 开门见山,开篇名义.今天来聊聊如何将多段视频,拼接成一个完整而连续的视频,然后无缝进行播放. 这样的需求应该不算偏门吧? 最简单的就是一些视频 App,会将大段 ...
随机推荐
- awk第一天
awk第一天 1.用awk 打印整个test.txt (以下操作都是用awk工具实现,针对test.txt) awk '{print}' test.txt [root@master ~]# awk ' ...
- [TM4]TM4C123G使用笔记
[TM4]TM4C123G使用笔记 TI的板子真让人头大甚至重装了两遍KEIL5 如何用keil5新建工程可以参考如下博客: https://blog.csdn.net/D_XingGuang/art ...
- 更新|3DCAT实时云渲染 v2.1.2版本全新发布
3DCAT实时渲染云在近期发布了新的v2.1.2的版本,让我们来看下做了哪些更新. 1. 整体UI的变更 目前的UI风格更加美观,区分开了3DCAT 应用控制中心和个人信息管理中心. 3DCAT 应用 ...
- 从零开始写 Docker(八)---实现 mydocker run -d 支持后台运行容器
本文为从零开始写 Docker 系列第八篇,实现类似 docker run -d 的功能,使得容器能够后台运行. 完整代码见:https://github.com/lixd/mydocker 欢迎 S ...
- OpenCV常量值含义表
色彩空间转换常量 常量值 说明 cv2.COLOR_BGR2GRAY 从 BGR 色彩空间转换到 GRAY 色彩空间 cv2.COLOR_RGB2GRAY 从 RGB 色彩空间转换到 GRAY 色彩空 ...
- Oracle 关闭 DBLink
alter system set open_links=0 sid ='*' scope=spfile; System altered. alter system set open_links_per ...
- Spring框架之IoC( Inversion of Control )基础知识入门
1.IoC创建对象的方式 使用无参构造创建对象 假如要使用有参构造创建: 下标赋值constructor-arg <!--有参--> <bean id="User" ...
- 鸿蒙HarmonyOS实战-ArkUI组件(Progress)
一.Progress Progress组件是一种用户界面(UI)元素,用于向用户显示某些任务的进度.它通常以进度条的形式出现,显示任务完成的百分比.Progress组件可以在确定任务持续时间未知的情况 ...
- #dp,矩阵乘法#洛谷 5371 [SNOI2019]纸牌
题目 一副纸牌有 \(n\) 种,每种有 \(m\) 张, 现在有 \(k\) 个限制条件形如第 \(k_i\) 种牌至少选 \(a_i\) 张, 一个三元组合法当且仅当其为 \((i,i+1,i+2 ...
- #交互#CF1370F2 The Hidden Pair (Hard Version)
题目 分析 考虑询问所有点可以知道两个标记点路径上的一个点, 以该点为根建树,可以二分出离该点较远的一个标记点, 再用这个标记点一次询问推出另一个,最多11次询问 代码 #include <cs ...