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方法

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

 


目录
相关文章
|
7月前
|
监控 算法 NoSQL
Go 微服务限流与熔断最佳实践:滑动窗口、令牌桶与自适应阈值
🌟蒋星熠Jaxonic:Go微服务限流熔断实践者。分享基于滑动窗口、令牌桶与自适应阈值的智能防护体系,助力高并发系统稳定运行。
1090 1
Go 微服务限流与熔断最佳实践:滑动窗口、令牌桶与自适应阈值
|
9月前
|
JSON 自然语言处理 API
gRPC凭什么成为微服务通信首选?深度解析RPC进化史
本文深入解析了分布式系统中服务通信的核心机制,重点介绍了 RPC 与 gRPC 的原理、优势及使用场景,并详解 gRPC 所依赖的序列化协议 Protocol Buffers(Protobuf)。内容涵盖 RPC 概念、gRPC 特性、Protobuf 语法及服务定义,适合微服务架构设计与维护人员阅读,助你构建高性能、低耦合的服务通信体系。
1062 73
gRPC凭什么成为微服务通信首选?深度解析RPC进化史
|
分布式计算 Go C++
初探Go语言RPC编程手法
总的来说,Go语言的RPC编程是一种强大的工具,让分布式计算变得简单如同本地计算。如果你还没有试过,不妨挑战一下这个新的编程领域,你可能会发现新的世界。
276 10
|
XML JSON Go
微服务架构下的配置管理:Go 语言与 yaml 的完美结合
微服务架构下的配置管理:Go 语言与 yaml 的完美结合
|
自然语言处理 负载均衡 API
gRPC 一种现代、开源、高性能的远程过程调用 (RPC) 可以在任何地方运行的框架
gRPC 是一种现代开源高性能远程过程调用(RPC)框架,支持多种编程语言,可在任何环境中运行。它通过高效的连接方式,支持负载平衡、跟踪、健康检查和身份验证,适用于微服务架构、移动设备和浏览器客户端连接后端服务等场景。gRPC 使用 Protocol Buffers 作为接口定义语言,支持四种服务方法:一元 RPC、服务器流式处理、客户端流式处理和双向流式处理。
|
Dubbo 网络协议 Java
RPC框架:一文带你搞懂RPC
这篇文章全面介绍了RPC(远程过程调用)的概念、原理和应用场景,解释了RPC如何工作以及为什么在分布式系统中广泛使用,并探讨了几种常用的RPC框架如Thrift、gRPC、Dubbo和Spring Cloud,同时详细阐述了RPC调用流程和实现透明化远程服务调用的关键技术,包括动态代理和消息的编码解码过程。
RPC框架:一文带你搞懂RPC
|
XML 负载均衡 监控
分布式-dubbo-简易版的RPC框架
分布式-dubbo-简易版的RPC框架
|
缓存 安全 Java
如何利用Go语言提升微服务架构的性能
在当今的软件开发中,微服务架构逐渐成为主流选择,它通过将应用程序拆分为多个小服务来提升灵活性和可维护性。然而,如何确保这些微服务高效且稳定地运行是一个关键问题。Go语言,以其高效的并发处理能力和简洁的语法,成为解决这一问题的理想工具。本文将探讨如何通过Go语言优化微服务架构的性能,包括高效的并发编程、内存管理技巧以及如何利用Go生态系统中的工具来提升服务的响应速度和资源利用率。
|
XML 存储 JSON
(十二)探索高性能通信与RPC框架基石:Json、ProtoBuf、Hessian序列化详解
如今这个分布式风靡的时代,网络通信技术,是每位技术人员必须掌握的技能,因为无论是哪种分布式技术,都离不开心跳、选举、节点感知、数据同步……等机制,而究其根本,这些技术的本质都是网络间的数据交互。正因如此,想要构建一个高性能的分布式组件/系统,不得不思考一个问题:怎么才能让数据传输的速度更快?
1218 1
|
Kubernetes Go Docker
掌握微服务架构:从Go到容器化的旅程
摘要,通常简短概述文章内容,要求精炼。在本文中,我们将打破常规,采用一种故事化叙述的摘要,旨在激发读者的好奇心和探究欲: “从宁静的海滨小城出发,我们踏上了一场技术探险之旅,探索微服务架构的奥秘。我们将学习如何用Go编写微服务,以及如何通过Docker和Kubernetes将它们打包进小巧的容器中。在这场旅程中,我们将遇到挑战、收获知识,最终实现应用的快速部署与可扩展性。”