为了账号安全,请及时绑定邮箱和手机立即绑定

Micro (3)

标签:
架构

go-micro RPC框架源码分析

最近由于辞职,心想着要好好研究下RPC的实现,于是乎,就拿go-micro开刀了...
首先回顾一下go-micro RPC service的开发和启动流程,以hello world demo为例。

service := micro.NewService(
        micro.Name("hello_world"),
        micro.Version("latest"),
        micro.Metadata(map[string]string{            "type": "helloworld",
        }),
    )
# 调用micro.NewService(调用micro.newService)来创建实现micro.Service interface的micro.service
service.Init() # 调用micro.service#Init方法
hello_world.RegisterHelloWorldHandler(service.Server(), new(HelloWorld))
service.Run() # 调用micro.service#Run方法

与service启动相关struct和interface

// micro.Service interface// go-micro.gotype Service interface {
    Init(...Option)
    Options() Options
    Client() client.Client
    Server() server.Server
    Run() error
    String() string}// micro.service struct, implements interface micro.Service// service.gotype service struct {
    opts Options
    once sync.Once
}// micro.Options struct// options.gotype Options struct {
    Broker    broker.Broker
    Cmd       cmd.Cmd
    Client    client.Client
    Server    server.Server // server/server.go, interface, implemented by server/rpc_server.go, rpcServer struct
    Registry  registry.Registry
    Transport transport.Transport    // Register loop interval
    RegisterInterval time.Duration    // Before and After funcs
    BeforeStart []func() error
    BeforeStop  []func() error
    AfterStart  []func() error
    AfterStop   []func() error

    // Other options for implementations of the interface
    // can be stored in a context
    Context context.Context}

// server.Server interface// server/server.gotype Server interface {
    Options() Options
    Init(...Option) error
    Handle(Handler) error
    NewHandler(interface{}, ...HandlerOption) Handler
    NewSubscriber(string, interface{}, ...SubscriberOption) Subscriber
    Subscribe(Subscriber) error
    Register() error
    Deregister() error
    Start() error
    Stop() error
    String() string}// server.rpcServer struct, implements interface server.Server// server/rpc_server.gotype rpcServer struct {
    rpc  *server // server.server, server.rpc_service.go, struct
    exit chan chan error

    sync.RWMutex
    opts        Options
    handlers    map[string]Handler
    subscribers map[*subscriber][]broker.Subscriber    // used for first registration
    registered bool
    // graceful exit
    wg sync.WaitGroup
}// server.server struct// server/rpc_service.go// server represents an RPC Server.type server struct {
    name         string
    mu           sync.Mutex // protects the serviceMap
    serviceMap   map[string]*service
    reqLock      sync.Mutex // protects freeReq
    freeReq      *request
    respLock     sync.Mutex // protects freeResp
    freeResp     *response
    hdlrWrappers []HandlerWrapper
}



整个方法调用过程如图所示:

webp

go-micro service启动流程图

注明: 水平方向表示内部调用,垂直方向表示顺序调用。

根据上面所述流程,我们自己开发的Service是怎么让go-micro知道的呢?以及go-micro如何知道一个服务查询请求应该怎么处理呢?

服务注册

我们在hello_world service中仅仅调用如下代码即可完成我们自己的service的注册,看起来很简单:

hello_world.RegisterHelloWorldHandler(service.Server(), new(HelloWorld))

原来,在我们创建hello_world.proto文件时,micro已经帮我们生成注册Handler方法了。

func RegisterHelloWorldHandler(s server.Server, hdlr HelloWorldHandler, opts ...server.HandlerOption) {
  s.Handle(s.NewHandler(&HelloWorld{hdlr}, opts...))
}

该方法调用时,我们传入了micro.Service#Server()(返回值为接口类型server.Server, 由server.rpcServer实现)和实现了HelloWorldHandler interface的对象作为参数,实际上内部通过调用micro.Service#Server()#handle方法(即server.rpcServer#Handle):

// server.rpcServer// server/rpc_server.gofunc (s *rpcServer) Handle(h Handler) error {
    s.Lock()    defer s.Unlock()    if err := s.rpc.register(h.Handler()); err != nil {        return err
    }
    s.handlers[h.Name()] = h    return nil}

该方法会将我们的Service(此处也即是h Handler)添加到server.rpcServer.handlers map中,Service.Name()作为key,值为h Handler对象, s.handlers[h.Name()] = h
在启动过程中,我们创建了t := time.NewTicker(), 该定时器会不断的调用micro.service.opts.Server#Register, 我们看一下该方法:

// server.rpcServer// server/rpc_server.gofunc (s *rpcServer) Register() error {    // parse address for host, port
    config := s.Options()    var advt, host string
    var port int
    // check the advertise address first
    // if it exists then use it, otherwise
    // use the address
    if len(config.Advertise) > 0 {
        advt = config.Advertise
    } else {
        advt = config.Address
    }
    parts := strings.Split(advt, ":")    if len(parts) > 1 {
        host = strings.Join(parts[:len(parts)-1], ":")
        port, _ = strconv.Atoi(parts[len(parts)-1])
    } else {
        host = parts[0]
    }
    addr, err := addr.Extract(host)    if err != nil {        return err
    }    // register service
    node := &registry.Node{
        Id:       config.Name + "-" + config.Id,
        Address:  addr,
        Port:     port,
        Metadata: config.Metadata,
    }

    node.Metadata["transport"] = config.Transport.String()
    node.Metadata["broker"] = config.Broker.String()
    node.Metadata["server"] = s.String()
    node.Metadata["registry"] = config.Registry.String()

    s.RLock()    // Maps are ordered randomly, sort the keys for consistency
    var handlerList []string
    for n, e := range s.handlers {        // Only advertise non internal handlers
        if !e.Options().Internal {
            handlerList = append(handlerList, n)
        }
    }
    sort.Strings(handlerList)        //...省略部分代码
    var endpoints []*registry.Endpoint    for _, n := range handlerList {
        endpoints = append(endpoints, s.handlers[n].Endpoints()...)
    }    //...省略部分代码
    s.RUnlock()

    service := &registry.Service{
        Name:      config.Name,
        Version:   config.Version,
        Nodes:     []*registry.Node{node},
        Endpoints: endpoints,
    }

    s.Lock()
    registered := s.registered
    s.Unlock()    if !registered {
        log.Logf("Registering node: %s", node.Id)
    }    // create registry options
    rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}    if err := config.Registry.Register(service, rOpts...); err != nil {        return err
    }    // already registered? don't need to register subscribers
    if registered {        return nil
    }

    s.Lock()    defer s.Unlock()
    s.registered = true
        //...省略部分代码
    return nil}

调用该server.rpcServer#Register(),内部会创建一个registry.Service对象service,并且设置server.rpcServer.handlers(类型为server.Handler, 由server.rpcHandler实现)中的Endpoints,然后通过config.Registry.Register()Service Registry来注册该service



作者:zouqilin
链接:https://www.jianshu.com/p/4d71da02ac43


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消