go微服务框架go-micro深度学习 rpc方法调用过程详解
摘要: 上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注册server信息,client获取server的地址信息,就可以和服务建立连接,然后就可以进行通信了。
上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注册server信息,client获取server的地址信息,就可以和服务建立连接,然后就可以进行通信了。这篇帖子详细说一下,go-micro的通信协议、编码,和具体服务方法的调用过程是如何实现的,文中的代码还是我github上的例子: gomicrorpc
go-micro 支持很多通信协议:http、tcp、grpc等,支持的编码方式也很多有json、protobuf、bytes、jsonrpc等。也可以根据自己的需要实现通信协议和编码方式。go-micro 默认的通信协议是http,默认的编码方式是protobuf,我就以默认的方式来分解他的具体实现。
服务的启动
go-micro在启动的时候会选择默认通信协议http和protobuf编码方式,但他是如何路由到具体方法的?在go-micro服务端启动的时候我们需要注册Handler,也就是我们具体实现结构体 ,如例子中注册方法时,我们调用的RegisterSayHandler方法
// 注册 Handlerrpcapi.RegisterSayHandler(service.Server(), new(handler.Say))
这个方法内部的体实现主要是利用了反射的力量,注册的对象是实现了rpc接口的方法,如我们的Say实现了SayHandler。go-micro默认的router会利用反射把Say对象的信息完全提取出来,解析出结构体内的方法及方法的参数,保存到一个map内-> map[结构体名称][方法信息集合]
具体的实现在rpc_router.go里router的Handle(Handler)方法,组织完成后map的是下图这样,保存了很多反射信息,用以将来调用。
下面是这个方法的主要代码,删除了一些,很希望大家读一下rpc_router.go里面的代码,prepareMethod方法是具体利用反射提取信息的方法。
func (router *router) Handle(h Handler) error { router.mu.Lock() defer router.mu.Unlock() // .... rcvr := h.Handler() s := new(service) s.typ = reflect.TypeOf(rcvr) s.rcvr = reflect.ValueOf(rcvr) // check name // .... s.name = h.Name() s.method = make(map[string]*methodType) // Install the methods for m := 0; m < s.typ.NumMethod(); m++ { method := s.typ.Method(m) // prepareMethod会把所有解析的信息返回来 if mt := prepareMethod(method); mt != nil { s.method[method.Name] = mt } } // ..... // save handler router.serviceMap[s.name] = s return nil}
serviceMap里保存的就是反射后的信息,下图是我用goland的debug得到的保存信息
路由信息处理完后,主要的工作就已经完成了,然后注册服务并启动服务,启动的服务是一个http的服务,我们可以看一下http_transport.go里的代码
服务的简单流程图如下 ,选择通信协议和编码方式->注册服务方法->启动服务并注册服务信息
客户端调用服务方法
客户端在启动的时候也要选择默认的通信协议http,和protobuf编码。客户端在调用rpc方法的时候如:
rsp, err := client.Hello(context.Background(), &model.SayParam{Msg: "hello server"})
go-micro为我们自动生成的rpcapi.micro.go里我们可以看一上Hello的具体实现,没有几行代码,但内部还是做了很多工作
func (c *sayService) Hello(ctx context.Context, in *model.SayParam, opts ...client.CallOption) (*model.SayResponse, error) { req := c.c.NewRequest(c.name, "Say.Hello", in) out := new(model.SayResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err } return out, nil}
他的实现方式是封装request,然后调用服务方法。这个request 是非常重要的:
func newRequest(service, endpoint string, request interface{}, contentType string, reqOpts ...RequestOption) Request { var opts RequestOptions for _, o := range reqOpts { o(&opts) } // set the content-type specified if len(opts.ContentType) > 0 { contentType = opts.ContentType } return &rpcRequest{ service: service, method: endpoint, endpoint: endpoint, body: request, contentType: contentType, opts: opts, }}
这个方法返回一个rpcRequest里面包含了详细的调用信息,servicec:服务名,method和endpoint目前是一样的是方法名这里是Say.Hello,contentType是protobuf,body 是具体的信息,也要要进行编码的内容,使用protobuf进行编码,然后会把这些信息放到一个http.Request里,再从Register或者从缓存获取服务器信息,连接服务器,发送数据。
简单流程图如下
client:封装参数-> 编码数据->连接服务->发送数据->接收返回数据,并解码。
service: 接收数据->解码数据,找到相应的实例和方法,利用反射调用具体方法->编码返数据->发送给客户端。
服务端处理请求
当服务端监接收到数据后,从http的Request里的Header中读取到相应的信息:编码方式,endpoint,请求的数据,由路由器进行对比和匹配找到保存的反射信息,利用反射把请求的数据根据相应的编码方式进行解码,再利用反射调用具体的方法,处理完把返回数据进行编码,组织一个http.Response传输给用户,客户端接收到数据后进行解码读取数据。 rpc_router.go里的call方法就是具体的调用过程方法,有时间大家可以读一下。
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这是一个我的QQ群架构华山论剑:836442475,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!
go微服务框架go-micro深度学习 rpc方法调用过程详解的更多相关文章
- go微服务框架go-micro深度学习(四) rpc方法调用过程详解
上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注册server信息,client获取server的地 ...
- go微服务框架go-micro深度学习(五) stream 调用过程详解
上一篇写了一下rpc调用过程的实现方式,简单来说就是服务端把实现了接口的结构体对象进行反射,抽取方法,签名,保存,客户端调用的时候go-micro封请求数据,服务端接收到请求时,找到需要调用调 ...
- RPC框架调用过程详解
RPC框架调用过程详解 2017年09月16日 21:14:08 荷叶清泉 阅读数 6275 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. ...
- 微服务框架SpringCloud(Dalston版)学习 (一):Eureka服务注册与发现
eureka-server eureka服务端,提供服务的注册与发现,类似于zookeeper 新建spring-boot工程,pom依赖: <dependency> <groupI ...
- Java数据持久层框架 MyBatis之API学习四(xml配置文件详解)
摘录网址: http://blog.csdn.net/u010107350/article/details/51292500 对于MyBatis的学习而言,最好去MyBatis的官方文档:http:/ ...
- 深度学习——优化器算法Optimizer详解(BGD、SGD、MBGD、Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam)
在机器学习.深度学习中使用的优化算法除了常见的梯度下降,还有 Adadelta,Adagrad,RMSProp 等几种优化器,都是什么呢,又该怎么选择呢? 在 Sebastian Ruder 的这篇论 ...
- 深度学习之卷积神经网络(CNN)详解与代码实现(一)
卷积神经网络(CNN)详解与代码实现 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/10430073.html 目 ...
- 【转载】 深度学习之卷积神经网络(CNN)详解与代码实现(一)
原文地址: https://www.cnblogs.com/further-further-further/p/10430073.html ------------------------------ ...
- faceswap深度学习AI实现视频换脸详解
给大家介绍最近超级火的黑科技应用deepfake,这是一个实现图片和视频换脸的app.前段时间神奇女侠加尔盖朵的脸被换到了爱情动作片上,233333.我们这里将会从github项目faceswap开始 ...
随机推荐
- Selenium Webdriver元素定位的八种常用方式(转载)
转载自 https://www.cnblogs.com/qingchunjun/p/4208159.html 在使用selenium webdriver进行元素定位时,通常使用findElement或 ...
- json11阅读
概要:json11是一个基于c++11的json解析库,dropbox出品. 使用 直接举自带单元测试test.cpp中的例子: const string simple_test = R"( ...
- KALI安装与环境配置
2018-2019 201899224<网络攻防实践>第二周作业 虚拟化网络攻防实验环境包括以下部分: 靶机:包含系统和应用程序安全漏洞,并作为攻击目标的主机.(Windows XP和Li ...
- mybatis动态排序
如果我们要传入排序字段作为一个参数到mybatis中,用以实现按照指定字段来排序的功能,那么我们需要使用$,而不是像其他参数一样,使用#.如下所示. <if test="sortnam ...
- javaweb开发3.基于Servlet+JSP+JavaBean开发模式的用户登录注册
转载孤傲苍狼博客http://www.cnblogs.com/xdp-gacl/p/3902537.html 1.层次比较分明的项目结构图
- docker容器的使用
Docker客户端 docker客户端非常简单,我们可以直接输入docker命令来查看到Docker客户端的所有命令选项. runoob@ docker 可以通过命令docker command -- ...
- 模板学习实践二 pointer
c++ template学习记录 使用模板将实际类型的指针进行封装 当变量退出作用域 自动delete // 1111.cpp : 定义控制台应用程序的入口点. // #include "s ...
- URL与URI的区别和联系
转自:https://www.cnblogs.com/chengdabelief/p/6635045.html 简单理解是这样的:理解URI和URL的区别,我们引入URN这个概念. URI = Uni ...
- android 学习网站
菜鸟教程 http://www.runoob.com/android/android-tutorial.html Android基础入门教程 http://www.runoob.com/w3cnot ...
- AngularJS封装webupload实现文件夹上传
百度的webupload没有开放api获取整个文件夹的信息.本文是二次开发webupload实现获取文件夹信息. 指令封装 /** * @license lx.ui.framework v1.0.0 ...