go微服务框架go-micro深度学习(二) 入门例子

本文涉及的产品
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:

   上一篇帖子简单介绍了go-micro的整体框架结构,这一篇主要写go-micro使用方式的例子,中间会穿插一些go-micro的源码,和调用流程图,帮大家更好的理解go-micro的底层。更详细更具体的调用流程和细节,会在以后的帖子里详细讲解。

     例子的github地址: gomicrorpc   跑一遍例子,也就会明白个大概。

安装所需要的环境

    go-micro服务发现默认使用的是consul

brew install consul
consul agent -dev

   或者直接使用使用docker跑

docker run -p 8300:8300 -p 8301:8301 -p 8301:8301/udp -p 8302:8302/udp -p 8302:8302 -p 8400:8400 -p 8500:8500 -p 53:53/udp consul

    我个人更喜欢etcdv3原因我上一篇也有提到过,gomicro服务发现不支持consul集群,我之前也写过etcdv3 集群的搭建和使用帖子,有时间大家可以看一下

    安装go-micro框架

go get github.com/micro/go-micro

    安装protobuf和依赖 prtobuf的基础知识我这里就不讲了,如果不了解的可以看一下官方文档,就是一个跨平台,跨语言的数据序列化库,简单易学。

    是go-micro用于帮助我们生成服务接口和一系列的调用代码

brew install protobuf
go get -u -v github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u -v github.com/micro/protoc-gen-micro

    protobuf也可以直接从源码安装

复制代码
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protobuf-all-3.6.1.tar.gz
tar zxvf protobuf-all-3.6.1.tar.gz
cd protobuf-3.6.1/
./autogen.sh
./configure
 make
make install
protoc -h
复制代码

 

    安装micro工具包,这个安装是可选项,micro提供了一系列的工具来帮助我们更好的使用go-micro。

go get github.com/micro/micro

 

例子1

创建proto文件common.proto,这个文件包含了传入和返回的参数,参数包含了常用的基础类型、数组、map等。还有一个Say 服务,这个服务里有一个rpc方法。

复制代码
syntax = "proto3";

package model;

message SayParam {
    string msg = 1;
}

message Pair {
    int32 key = 1;
    string values = 2;
}

message SayResponse {
    string msg = 1;
    // 数组
    repeated string values = 2;
    // map
    map<string, Pair> header = 3;
    RespType type = 4;
}

enum RespType {
    NONE = 0;
    ASCEND = 1;
    DESCEND = 2;
}

// 服务接口
service Say {
    rpc Hello(SayParam) returns (SayResponse) {}
}
复制代码

 

在根目录下运行,生成两个模板文件

  protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. example1/proto/*.proto 

一个文件是proto的go 结构文件,还有一个go-micro rpc的接口文件。

server 端:

复制代码
type Say struct {}

func (s *Say) Hello(ctx context.Context, req *model.SayParam, rsp *model.SayResponse) error {
    fmt.Println("received", req.Msg)
    rsp.Header = make(map[string]*model.Pair)
    rsp.Header["name"] = &model.Pair{Key: 1, Values: "abc"}

    rsp.Msg = "hello world"
    rsp.Values = append(rsp.Values, "a", "b")
    rsp.Type = model.RespType_DESCEND

    return nil
}


func main() {
    // 我这里用的etcd 做为服务发现,如果使用consul可以去掉
    reg := etcdv3.NewRegistry(func(op *registry.Options){
        op.Addrs = []string{
            "http://192.168.3.34:2379", "http://192.168.3.18:2379", "http://192.168.3.110:2379",
        }
    })

    // 初始化服务
    service := micro.NewService(
        micro.Name("lp.srv.eg1"),
        micro.Registry(reg),
    )
    service.Init()
    // 注册 Handler
    model.RegisterSayHandler(service.Server(), new(Say))

    // run server
    if err := service.Run(); err != nil {
        panic(err)
    }
}
复制代码

服务发现我使用的是etcdv3  替换了默认的consul

micro.NewService 初始化服务,然后返回一个Service接口的实例,newService()方法的大概流程如下,

 

先是给各个接口初始化默认值,再使用传入的值替换默认值,这也是go-micro可替换插件的地方。

service有一个Init()可选方法,这是一个单例方法,

复制代码
func (s *service) Init(opts ...Option) {
    // process options
    for _, o := range opts {
        o(&s.opts)
    }

    s.once.Do(func() {
        // save user action
        action := s.opts.Cmd.App().Action
        // set service action
        s.opts.Cmd.App().Action = func(c *cli.Context) {
                .........//这里就不把代码全显示出来了
                .........
        }
}
复制代码

用于始化cmd的一些信息

 service.Run()方法 调用流程

   因为在初始化的时候没有指定端口,系统会自动分配一个端口号分给Server,并把这个server的信息注册到Register。

   BeferStart和AfterStart也都是可以自定义的

client 端:

复制代码
func main() {
    // 我这里用的etcd 做为服务发现,如果使用consul可以去掉
    reg := etcdv3.NewRegistry(func(op *registry.Options){
        op.Addrs = []string{
            "http://192.168.3.34:2379", "http://192.168.3.18:2379", "http://192.168.3.110:2379",
        }
    })

    // 初始化服务
    service := micro.NewService(
        micro.Registry(reg),
    )
    service.Init()
    sayClent := model.NewSayService("lp.srv.eg1", service.Client())


    rsp, err := sayClent.Hello(context.Background(), &model.SayParam{Msg: "hello server"})
    if err != nil {
        panic(err)
    }

    fmt.Println(rsp)

}
复制代码

 上面根据proto文件的生成的两个文件中有一个是rpc的接口文件,接口文件已经帮我们把调用方法的整个流程封装好了。

  只需要给出服务名称和licent就可以。然后调用Hello方法

  源码:

复制代码
func (c *sayService) Hello(ctx context.Context, in *SayParam, opts ...client.CallOption) (*SayResponse, error) {
    req := c.c.NewRequest(c.name, "Say.Hello", in)
    out := new(SayResponse)
    err := c.c.Call(ctx, req, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}
复制代码

 主要的流程里都在c.c.Call方法里。简单来说流程如下

 

就是得到节点信息address,根据address去查询 pool里是否有连接,如果有则取出来,如果没有则创建,然后进行数据传输,传输完成后把client放回到pool内。pool的大小也是可以控制的,这部分的代码读起来特别爽,具体的细节和处理流程会在以后的帖子里详细讲解

 例子2

    例子1,做了一个简单的服务,已经不能再简单了,只是为了能让大家熟悉一下go-micro。看完例子1后应该会有更多的想法,想使用更多的go-micro的功能,比如protobuf生成的类都在一起,如果想model和api分开怎么处理,怎么使用go-micro的双向流,怎么使用消息推送,等等。所以我就双做了一个小例子,这个例子里包含了一些东西。

    

    这个例子我就只说一下组织结构,也没有多少代码,大家有时间看一下就ok了。

    proto下的两个文件夹,一个model一个rpcapi,是把数据和api分开,api引用了model

看一下rpcapi

复制代码
syntax = "proto3";

package rpcapi;
import "github.com/lpxxn/gomicrorpc/example2/proto/model/common.proto";

// 服务接口
service Say {
    rpc Hello(model.SayParam) returns (model.SayResponse) {}
    rpc Stream(model.SRequest) returns (stream model.SResponse) {}

}
复制代码

    import了model里的common.proto

在生成的时候一个只要go_out另一个只要micro_out就好了

  protoc --proto_path=$GOPATH/src:. --go_out=. example2/proto/model/*.proto 
  
  protoc --proto_path=$GOPATH/src:. --micro_out=. example2/proto/rpcapi/*.proto 

    订阅一个信息

    // Register Subscribers
    if err := server.Subscribe(server.NewSubscriber(common.Topic1, subscriber.Handler)); err != nil {
        panic(err)
    }

   当有信息发送时,所有订阅了lp.srv.eg2.topic1这个信息的服务都会收到信息

   客户端发送信息

    p := micro.NewPublisher(common.Topic1, service.Client())
    p.Publish(context.TODO(), &model.SayParam{Msg: lib.RandomStr(lib.Random(3, 10))})

   如果是生产环境一定不要用go-micro默认的信息发布和订阅处理方式,micro的插件plugin里是有很多成熟的插件。

   使用双向流的小功能

   这个方法只是每次向客户端发送一些数据,每次只发送一部分。比如我们给客户端推送的数据很大时,一次性全都推过去,是不太正确的做法,分批推送还是比较好的。

复制代码
func (s *Say) Stream(ctx context.Context, req *model.SRequest, stream rpcapi.Say_StreamStream) error {

    for i := 0; i < int(req.Count); i++ {
        rsp := &model.SResponse{}
        for j := lib.Random(3, 5); j < 10; j++ {
            rsp.Value = append(rsp.Value, lib.RandomStr(lib.Random(3, 10)))
        }
        if err := stream.Send(rsp); err != nil {
            return err
        }
        // 模拟处理过程
        time.Sleep(time.Microsecond * 50)
    }
    return nil

    return nil
}
复制代码

 

    希望这个小例子能让大家入门go-micro.

目录
相关文章
|
12天前
|
JavaScript Java Go
探索Go语言在微服务架构中的优势
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出。本文将深入探讨Go语言在构建微服务时的性能优势,包括其在内存管理、网络编程、并发模型以及工具链支持方面的特点。通过对比其他流行语言,我们将揭示Go语言如何成为微服务架构中的一股清流。
103 53
|
6天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
|
1月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
101 3
|
9天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
10天前
|
Go 数据处理 API
Go语言在微服务架构中的应用与优势
本文摘要采用问答形式,以期提供更直接的信息获取方式。 Q1: 为什么选择Go语言进行微服务开发? A1: Go语言的并发模型、简洁的语法和高效的编译速度使其成为微服务架构的理想选择。 Q2: Go语言在微服务架构中有哪些优势? A2: 主要优势包括高性能、高并发处理能力、简洁的代码和强大的标准库。 Q3: 文章将如何展示Go语言在微服务中的应用? A3: 通过对比其他语言和展示Go语言在实际项目中的应用案例,来说明其在微服务架构中的优势。
|
11天前
|
存储 设计模式 安全
Go语言中的并发编程:从入门到精通###
本文深入探讨了Go语言中并发编程的核心概念与实践技巧,旨在帮助读者从理论到实战全面掌握Go的并发机制。不同于传统的技术文章摘要,本部分将通过一系列生动的案例和代码示例,直观展示Go语言如何优雅地处理并发任务,提升程序性能与响应速度。无论你是Go语言初学者还是有一定经验的开发者,都能在本文中找到实用的知识与灵感。 ###
|
16天前
|
Serverless Go
Go语言中的并发编程:从入门到精通
本文将深入探讨Go语言中并发编程的核心概念和实践,包括goroutine、channel以及sync包等。通过实例演示如何利用这些工具实现高效的并发处理,同时避免常见的陷阱和错误。
|
16天前
|
Cloud Native 持续交付 云计算
云原生入门指南:从容器到微服务
【10月更文挑战第28天】在数字化转型的浪潮中,云原生技术成为推动现代软件开发的关键力量。本篇文章将带你了解云原生的基本概念,探索它如何通过容器化、微服务架构以及持续集成和持续部署(CI/CD)的实践来提升应用的可伸缩性、灵活性和可靠性。你将学习到如何利用这些技术构建和部署在云端高效运行的应用,并理解它们对DevOps文化的贡献。
38 2
|
19天前
|
Kubernetes 关系型数据库 MySQL
Kubernetes入门:搭建高可用微服务架构
【10月更文挑战第25天】在快速发展的云计算时代,微服务架构因其灵活性和可扩展性备受青睐。本文通过一个案例分析,展示了如何使用Kubernetes将传统Java Web应用迁移到Kubernetes平台并改造成微服务架构。通过定义Kubernetes服务、创建MySQL的Deployment/RC、改造Web应用以及部署Web应用,最终实现了高可用的微服务架构。Kubernetes不仅提供了服务发现和负载均衡的能力,还通过各种资源管理工具,提升了系统的可扩展性和容错性。
57 3
|
29天前
|
Cloud Native Go API
Go语言在微服务架构中的创新应用与实践
本文深入探讨了Go语言在构建高效、可扩展的微服务架构中的应用。Go语言以其轻量级协程(goroutine)和强大的并发处理能力,成为微服务开发的首选语言之一。通过实际案例分析,本文展示了如何利用Go语言的特性优化微服务的设计与实现,提高系统的响应速度和稳定性。文章还讨论了Go语言在微服务生态中的角色,以及面临的挑战和未来发展趋势。