上一篇帖子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方法

// 注册 Handler
rpcapi.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 := ; 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) > {
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方法就是具体的调用过程方法,有时间大家可以读一下。

go微服务框架go-micro深度学习(四) rpc方法调用过程详解的更多相关文章

  1. go微服务框架go-micro深度学习 rpc方法调用过程详解

    摘要: 上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注册server信息,client获取serv ...

  2. RPC框架调用过程详解

    RPC框架调用过程详解 2017年09月16日 21:14:08 荷叶清泉 阅读数 6275   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. ...

  3. go微服务框架go-micro深度学习(五) stream 调用过程详解

        上一篇写了一下rpc调用过程的实现方式,简单来说就是服务端把实现了接口的结构体对象进行反射,抽取方法,签名,保存,客户端调用的时候go-micro封请求数据,服务端接收到请求时,找到需要调用调 ...

  4. 微服务框架SpringCloud(Dalston版)学习 (一):Eureka服务注册与发现

    eureka-server eureka服务端,提供服务的注册与发现,类似于zookeeper 新建spring-boot工程,pom依赖: <dependency> <groupI ...

  5. Java数据持久层框架 MyBatis之API学习六(Mapper XML 文件详解)

    对于MyBatis的学习而言,最好去MyBatis的官方文档:http://www.mybatis.org/mybatis-3/zh/index.html 对于语言的学习而言,马上上手去编程,多多练习 ...

  6. 21个项目玩转深度学习:基于TensorFlow的实践详解02—CIFAR10图像识别

    cifar10数据集 CIFAR-10 是由 Hinton 的学生 Alex Krizhevsky 和 Ilya Sutskever 整理的一个用于识别普适物体的小型数据集.一共包含 10 个类别的 ...

  7. 21个项目玩转深度学习:基于TensorFlow的实践详解01—MNIST机器学习入门

    数据集 由Yann Le Cun建立,训练集55000,验证集5000,测试集10000,图片大小均为28*28 下载 # coding:utf-8 # 从tensorflow.examples.tu ...

  8. 21个项目玩转深度学习:基于TensorFlow的实践详解06—人脸检测和识别——项目集锦

    摘自:https://github.com/azuredsky/mtcnn-2 mtcnn - Multi-task CNN library language dependencies comment ...

  9. 21个项目玩转深度学习:基于TensorFlow的实践详解03—打造自己的图像识别模型

    书籍源码:https://github.com/hzy46/Deep-Learning-21-Examples CNN的发展已经很多了,ImageNet引发的一系列方法,LeNet,GoogLeNet ...

随机推荐

  1. 生日蛋糕 POJ - 1190 (搜索+剪枝)

    7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱.当 ...

  2. 【Java并发核心九】并发集合框架

    1.List接口:ArrayList 和 Vector ArrayList不是线程安全的,Vector是线程安全的,Vector有一个子类,可实现后进先出(LIFO)的对象堆栈(LinkedList ...

  3. BZOJ-1- 4868: [Shoi2017]期末考试-三分

    三分出成绩时间,假设当前出成绩最优,那么提前就会调增老师,增加不愉快度多于少等待的:如果延迟时间. 那么等待更久,增加的不愉快度也将多余少调增剩省下的. 于是:对于当前点,两边都是有单调性的. 就是说 ...

  4. react编码规范

    1.每个文件只写一个组件,但是多个无状态组件可以放在单个文件中: 2.有内部状态,方法或要对外暴露ref的组件,用类式组件: 3.无内部状态,方法或无需对外暴露ref的组件,用函数式组件: 4.有内部 ...

  5. jquery,underscore,lodash那些事儿

    一.参考链接 https://jquery.com/ https://en.wikipedia.org/wiki/JQuery https://developer.mozilla.org/zh-CN/ ...

  6. 网络基础配置--usg系统升级

    1.usg2000系统升级 1.1.TFTP设置 这里用到一个工具:3CDeamon, 是在由3Com开发类别 Web Development Freeware 软件,是一个简易服务器工具,含TFTP ...

  7. BigDecimal使用中的一些注意事项

    Java的商业计算,不能用float和double,因为他们无法进行精确计算.但是Java的设计者给编程人员提供了一个很有用的类BigDecimal,他可以完善float和double类无法进行精确计 ...

  8. go defer笔记

    1.函数中return xxx非原子指令 2.函数返回过程:先给返回值赋值:再调用defer:最后回到调用函数中 即:返回值 = xxx; defer; return; 3.多个defer调用顺序类似 ...

  9. 潭州课堂25班:Ph201805201 tornado 项目 第一课 项目介绍和创建 (课堂笔记)

    tornado 相关说明 , 查找 python3 的路径: binbin@abc:~$ which python3/usr/bin/python3 创建虚拟环境 : 创建工程; 用 pycharm ...

  10. Yii Cache 缓存的使用

    我的缓存组件配置在config\main.php文件,配置如下: 'components' => [ 'cache' => [ 'class' => 'yii\caching\Fil ...