扫码订阅《 Go语言微服务框架学习实践》或入驻星球,即可阅读文章!

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go友会
  • 城市
  • 校园
Go学院
  • Go小课
  • Go小考
  • Go实战
  • 精品课
Go求职
  • 求职辅导🔥
  • Offer收割社群
  • 企业题库
  • 面试宝典
Go宝典
  • 在线宝典
  • B站精选
  • 推荐图书
  • 每日博文
Go仓库
实验区
  • Go周边
  • Go下载
  • Go月刊
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
author-avatar

GOLANG ROADMAP


首页
Go友会
  • 城市
  • 校园
Go学院
  • Go小课
  • Go小考
  • Go实战
  • 精品课
Go求职
  • 求职辅导🔥
  • Offer收割社群
  • 企业题库
  • 面试宝典
Go宝典
  • 在线宝典
  • B站精选
  • 推荐图书
  • 每日博文
Go仓库
实验区
  • Go周边
  • Go下载
  • Go月刊
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
  • 《Go语言微服务框架学习实践》

    • 课程介绍
  • RPC远程调用机制

  • gRPC微服务框架

  • go-micro微服务框架

    • 第1节:go-micro框架介绍
    • 第2节:创建微服务
    • 第3节:心跳机制与可选项配置
    • 第4节:解耦利器–事件驱动机制
    • 第5节:Micro负载均衡组件–Selector
    • 第6节:RESTful API设计标准和实践
    • 第7节:Go-micro框架总结和说明

扫码订阅《 Go语言微服务框架学习实践》或入驻星球,即可阅读文章!

第2节:创建微服务


GOLANG ROADMAP

# 服务的定义

在micro框架中,服务用接口来进行定义,服务被定义为Service,完整的接口定义如下:

type Service interface {
    Init(...Option)
    Options() Options
    Client() client.Client
    Server() server.Server
    Run() error
    String() string
}
1
2
3
4
5
6
7
8

在该接口中,定义了一个服务实例具体要包含的方法,分别是:Init、Options、Client、Server、Run、String等6个方法。

# 初始化服务实例

micro框架,除了提供Service的定义外,提供创建服务实例的方法供开发者调用:

service := micro.NewService()
1

如上是最简单一种创建service实例的方式。NewService可以接受一个Options类型的可选项参数。NewService的定义如下:

func NewService(opts ...Option) Service {
    return newService(opts...)
}
1
2
3

# Options可选项配置

关于Options可配置选项,有很多可以选择的设置项。micro框架包中包含了options.go文件,定义了详细的可选项配置的内容。最基本常见的配置项有:服务名称,服务的版本,服务的地址,服务:

//服务名称
func Name(n string) Option {
    return func(o *Options) {
        o.Server.Init(server.Name(n))
    }
}

//服务版本
func Version(v string) Option {
    return func(o *Options) {
        o.Server.Init(server.Version(v))
    }
}

//服务部署地址
func Address(addr string) Option {
    return func(o *Options) {
        o.Server.Init(server.Address(addr))
    }
}

//元数据项设置
func Metadata(md map[string]string) Option {
    return func(o *Options) {
        o.Server.Init(server.Metadata(md))
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

完整的实例化对象代码如下所示:

func main() {
    //创建一个新的服务对象实例
    service := micro.NewService(
        micro.Name("helloservice"),
        micro.Version("v1.0.0"),
    )
}
1
2
3
4
5
6
7

开发者可以直接调用micro.Name为服务设置名称,设置版本号等信息。在对应的函数内部,调用了server.Server.Init函数对配置项进行初始化。

# 定义服务接口,实现服务业务逻辑

在前面的课程中,已经学习掌握了使用protobuf定义服务接口,并对服务进行具体实现。使用protobuf定义服务接口并自动生成go语言文件,需要经过以下几个步骤,我们通过示例进行说明:

我们依然通过案例来讲解相关的知识点:在学校的教务系统中,有学生信息管理的需求。学生信息包含学生姓名,学生班级,学习成绩组成;可以根据学生姓名查询学生的相关信息,我们通过rpc调用和学生服务来实现该案例。

# 1、定义.proto文件

使用proto3语法定义数据结构体和服务方法。具体定义内容如下:

syntax = 'proto3';
package message;

//学生数据体
message Student {
    string name = 1; //姓名
    string classes = 2; //班级
    int32 grade = 3; //分数
}

//请求数据体定义
message StudentRequest {
    string name = 1;
}

//学生服务
service StudentService {
    //查询学生信息服务
    rpc GetStudent (StudentRequest) returns (Student);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2、编译.proto文件

在原来学习gRPC框架时,我们是将.proto文件按照grpc插件的标准来进行编译。而现在,我们学习的是go-micro,因此我们可以按照micro插件来进行编译。micro框架中的protobuf插件,我们需要单独安装。

  • 安装micro框架的protobuf插件

    go get github.com/micro/protobuf/{proto,protoc-gen-go}
    
    1

    通过上述命令可以成功安装proto插件,安装成功后可以在本地环境中的$GOPATH目录中的src/github.com/micro/protobuf中看到新安装的插件。源码目录如下图所示:

WX20190826-113159@2x

  • 指定micro插件进行编译

    protoc --go_out=plugins=micro:. message.proto
    
    1

    上述编译命令执行成功,可以在项目目录下的message目录下生成message.pb.go文件,该文件是由protoc编译器自动编译生成,开发者不能修改。message.pb.go如图所示:

    WX20190826-113429@2x

# 3、编码实现服务功能

在项目目录下,实现StudentService定义的rpc GetStudent功能。新建studentManager.go文件,具体实现如下:

//学生服务管理实现
type StudentManager struct {
}

//获取学生信息的服务接口实现
func GetStudent(ctx context.Context, request *message.StudentRequest, response *message.Student) error {

    studentMap := map[string]message.Student{
        "davie":  message.Student{Name: "davie", Classes: "软件工程专业", Grade: 80},
        "steven": message.Student{Name: "steven", Classes: "计算机科学与技术", Grade: 90},
        "tony":   message.Student{Name: "tony", Classes: "计算机网络工程", Grade: 85},
        "jack":   message.Student{Name: "jack", Classes: "工商管理", Grade: 96},
    }

    if request.Name == "" {
        return errors.New(" 请求参数错误,请重新请求。")
    }

    student := studentMap[request.Name]

    if student.Name != "" {
        response = &student
    }
    return errors.New(" 未查询当相关学生信息 ")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 运行服务

在之前的学习过程中,我们是通过自己编写server.go程序,注册服务,并实现请求的监听。现在,我们用micro框架来实现服务的运行。完整的运行服务的代码如下:

func main() {

    //创建一个新的服务对象实例
    service := micro.NewService(
        micro.Name("student_service"),
        micro.Version("v1.0.0"),
    )

    //服务初始化
    service.Init()

    //注册
message.RegisterStudentServiceHandler(service.Server(), new(StudentManager))

    //运行
    err := service.Run()
    if err != nil {
        log.Fatal(err)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 客户端调用

客户端可以构造请求对象,并访问对应的服务方法。具体方法实现如下:

func main() {

    service := micro.NewService(
        micro.Name("student.client"),
    )
    service.Init()

    studentService := message.NewStudentServiceClient("student_service", service.Client())

    res, err := studentService.GetStudent(context.TODO(), &message.StudentRequest{Name: "davie"})
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(res.Name)
    fmt.Println(res.Classes)
    fmt.Println(res.Grade)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 运行结果

运行服务端

运行main.go文件中的main函数,服务注册成功,并输出如下日志:

WX20190826-231749@2x

2019/08/26 22:50:18 Transport [http] Listening on [::]:54343
2019/08/26 22:50:18 Broker [http] Connected to [::]:54344
2019/08/26 22:50:19 Registry [mdns] Registering node: student_service-346b454c-998d-4e85-a8cc-befbc0198eef
1
2
3

运行客户端

客户端负责发起请求和功能调用,运行client.go程序,程序正常输出。

# 注册服务到consul

默认注册到mdns

在我们运行服务端的程序时,我们可以看到Registry [mdns] Registering node:xxx这个日志,该日志显示go-micro框架将我们的服务使用默认的配置注册到了mdns中。mdns是可简单翻译为mdns,是go-micro的默认配置选项。

注册到consul

在前面的微服务理论课程中,我们已经学习过consul。consul是服务注册与发现的组件,因此,如果我们本地系统已经安装了consul环境,我们可以选择将我们的服务注册到consul中。指定注册到consul时,需要先将consul进行启动。

  • 启动consul 启动命令如下:

    consul agent -dev
    
    1

    通过上述命令,我们可以在终端中启动consul。

  • 指定服务注册到consul 通过命令运行服务程序,并指定注册到consul,详细命令如下:

    go run main.go --registry=consul
    
    1

    通过–registry选项,指定要注册到的服务发现组件。

  • 查看服务 由于consul给我们提供了ui界面,因此我们可以通过浏览器界面来访问consul节点页面。访问本地8500端口,浏览器地址是:

    http://localhost:8500
    
    1

img

  • 服务的定义
  • 初始化服务实例
  • Options可选项配置
  • 定义服务接口,实现服务业务逻辑
  • 1、定义.proto文件
  • 2、编译.proto文件
  • 3、编码实现服务功能
  • 运行服务
  • 客户端调用
  • 运行结果
  • 注册服务到consul