go-micro

 ·  ☕ 6  · 👀...

介绍

Go Micro 整体架构设计

Go-Micro整体架构设计.png

  • Micro Runtime 应用层,就是一些基于微服务的应用组件,我们可以根据业务需要选择应用组件,例如:api网关负责将微服务接口暴露到公网中,web应用,处理一些网页应用。
  • Mico Service 服务层,这里就是我们开发的各种微服务了。
  • Cloud Platform 云平台,或者叫技术平台,负责支撑微服务运行的环境,例如:我们的容器平台、消息队列、数据库等等。

Go Micro核心模块设计

Go-Micro核心模块设计.png

  • Client 客户端,指的就是我们的的rpc客户端,调用微服务接口的客户端。
  • Server 服务端封装,负责注册服务、处理rpc请求等等。
  • Broker 消息队列的抽象,支持基于消息的事件处理,方便我们处理异步任务,可以根据需要选择各种消息队列,例如:RabbitMQ。
  • Codec 消息编码和解码的组件,客户端和服务端在处理消息的时候都需要codec组件,对消息进行编码或者解码,例如对protobuf格式的消息进行编码和解码。
  • Register register提供服务发现功能,支持consul, etcd, zookeeper, dns, gossip等作为注册中心。
  • Selector selector是一个负载均衡组件,支持随机、轮训等负载均衡算法,客户端在通过Register组件拿到多个服务端地址的时候,通过Selector组件的负载均衡算法,选择一个服务端进行通信。
  • Transport 负责客户端和服务端的通信,例如:使用http、websocket协议通信。

应用组件

  • API Gateway api网关,统一的Http api入口,可以将我们的微服务接口暴露到公网中。
  • Interactive CLI Go Micro微服务的命令行工具,可以用来查询服务,调用服务接口等等。
  • Web Dashboard Go Micro微服务web后台,可以用来查询我们正在运行的微服务状态信息。

安装

1
2
3
4
5
6
# 安装Go Micro
$ go get github.com/micro/go-micro
# 安装工具集(含网关、Web后台)
$ go get github.com/micro/micro
# 测试CLI
$ go get github.com/micro/examples/greeter/srv && srv

Micro CLI

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 查看帮助
$ micro help

# 查看服务列表
$ micro list services

# 查看指定服务信息
$ micro get 服务名

# 服务调用
$ micro call 服务名 方法名 '参数'

服务发现

基于mDNS服务发现

mDNS(多播DNS)是一种局域网内使用的DNS机制,他的大致原理如下:当有新的节点加入局域网的时候,如果打开了mDNS,就主动向局域网其他所有节点广播,自己提供的服务(域名是什么、ip地址是什么、端口号是什么), 这样我们任何一个节点都知道局域网提供了什么服务。

基于mDNS的服务发现,不需要额外的中间件和配置,适合个人开发做实验,团队多人合作开发,往往有部分微服务是在云服务器上面,通过mDNS无法查询这些服务的信息,生产环境也会选择其他服务发现中间件。

基于Consul的服务发现

Consul是解决服务发现、配置中心的分布式中间件,适合生产环境使用。

1
2
3
> MICRO_REGISTRY=consul \
MICRO_REGISTRY_ADDRESS=127.0.0.1:8500 \
go run orderservice.go

参数说明:

  • MICRO_REGISTRY 注册中心类型,这里设置为consul
  • MICRO_REGISTRY_ADDRESS - 注册中心地址, IP + PORT的形式

基于Etcd的服务发现

Etcd是强一致性的、分布式键值存储引擎,类似zookeeper。

1
2
3
> MICRO_REGISTRY= etcd \
MICRO_REGISTRY_ADDRESS=127.0.0.1:2379 \
go run orderservice.go
  • MICRO_REGISTRY 注册中心类型,这里设置为etcd
  • MICRO_REGISTRY_ADDRESS - 注册中心地址, IP + PORT的形式

官方例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> git clone https://github.com/micro/examples.git
> cd examples
##### 启动基础服务
> go run greeter/srv/main.go
##### 启动api服务(聚合服务)
> go run greeter/api/api.go
##### 启动go micro api网关
> micro api --handler=api
##### 测试网关api
> curl "http://localhost:8080/greeter/say/hello?name=John"

Web后台

Go Micro框架自带了一个web后台,可以通过这个后台,查看当前注册的服务,还有测试服务的接口。

启动Web后台

1
> micro web

通过http://localhost:8082访问后台

入门示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
> mkdir go-micro-demo
> cd go-micro-demo
> mkdir -p proto/order.proto
> mkdir proto
> mkdir -p proto/user.proto
> touch userservice.go
> touch orderservice.go
> tree 
.
├── go.mod                  # 依赖管理
├── orderservice.go         # 订单服务实现
├── proto                   # 保存微服务的接口定义
│   ├── order.proto         # 订单服务接口定义
│   └── user.proto          # 用户服务接口定义
└── userservice.go          # 用户服务实现

用户服务

定义用户微服务接口

proto/user.proto

syntax = "proto3";

// 定义包名
package proto;

// 定义user服务的接口
service UserSrv {
    // 获取用户账号信息
    rpc GetAccount(GetAccountRequest) returns (Account) {}
}

// 定义获取账号信息的请求消息
message GetAccountRequest {
    int32 id = 1; // 用户id
}

// 定义用户账号消息
message Account {
	int32 id = 1;  // id
	string username = 2; // 账号
	string address = 3; // 地址
	string phone =4; // 电话
}

编译接口文件

1
2
> cd go-micro-demo 
> protoc --proto_path=proto:. --micro_out=proto/ --go_out=proto/ proto/user.proto

用户实现服务

userservice.go

 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
	"context"
	"github.com/micro/go-micro"
	"wanglibing.com/go-micro-demo/proto"
)

// 定义用户服务, 实现proto协议定义的接口
type UserService struct {
}

// 实现查询账号信息接口
// 需要注意的是,go micro微服务的rpc接口,请求参数和返回参数,都作为函数参数传入,而grpc的接口,返回参数作为函数返回值。
func (u *UserService) GetAccount (ctx context.Context, request *proto.GetAccountRequest, response *proto.Account) error  {
	// 作为演示这里直接返回账号信息
	response.Id = request.Id // 从request获取请求参数.
	response.Username = "iamwlb"
	response.Address = "北京"
	response.Phone = "180344666666"

	return nil
}

func main() {
	// 定义一个微服务
	service := micro.NewService(
		micro.Name("go.micro.api.userservice"), // 定义用户服务的服务名
	)

	// 初始化
	service.Init()

	// 注册用户服务
	proto.RegisterUserSrvHandler(service.Server(), new(UserService))

	// 启动服务
	if err := service.Run(); err != nil {
		panic(err)
	}
}

订单服务

定义订单服务接口

proto/order.proto

syntax = "proto3";

// 定义包名
package proto;

// 定义订单服务的接口
service OrderSrv {
    // 获取订单信息
	rpc GetOrder(GetOrderRequest) returns (Order) {}
}

// 定义获取订单的请求消息
message GetOrderRequest {
    int32 id = 1; // 订单id
}

// 定义订单消息
message Order {
	int32 id = 1;  // 订单id
	string name = 2; // 商品名
	double price = 3; // 价格
	string username = 4; //用户
	string address = 5; // 用户地址
	string phone =6; // 联系电话
	string createTime = 7; //创建订单时间
}

编译接口文件

1
2
> cd go-micro-demo 
> protoc --proto_path=proto:. --micro_out=proto/ --go_out=proto/ proto/order.proto

实现订单服务

orderservice.go

 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package main

import (
	"context"
	"github.com/micro/go-micro"
	"time"
	"tizi365.com/tizi/proto"
)

// 定义用户服务, 实现proto协议定义的接口
type OrderService struct {
}

// 实现查询订单信息的接口
func (u *OrderService) GetOrder (ctx context.Context, request *proto.GetOrderRequest, response *proto.Order) error  {
	// 通常我们的订单信息都保存了用户的id, 例如用户id如下
	userId := 1312

	// 初始化用户服务对象
	// 初始化用户服务,需要用户服务的名字,这是一个初始化用户服务的时候定义的唯一标识
	userSrv := proto.NewUserSrvService("go.micro.api.userservice", service.Client())

	// 调用用户服务,查询用户信息,获取用户的电话和地址
	user, err := userSrv.GetAccount(context.TODO(), &proto.GetAccountRequest{Id:int32(userId)})
	if err == nil {
		// 调用成功, 初始化订单返回值
		response.Username = user.Username
		response.Address = user.Address
		response.Phone = user.Phone
	}

	response.Name = "大瓶可乐"
	response.Price = 6.5
	response.Id = request.Id // 从request获取请求参数.
	// 订单创建时间
	response.CreateTime = time.Now().Format(time.RFC3339)
	return nil
}

// 声明服务对象
var service micro.Service

func main() {
	// 定义一个微服务
	service = micro.NewService(
		micro.Name("go.micro.api.orderservice"), // 定义订单服务的服务名
	)

	// 初始化
	service.Init()

	// 注册订单服务
	proto.RegisterOrderSrvHandler(service.Server(), new(OrderService))

	// 启动服务
	if err := service.Run(); err != nil {
		panic(err)
	}
}

运行订单服务

1
> go run orderservice.go

调试微服务接口

通过命令行调试

1
2
3
4
##### 语法:
> micro call 服务名 接口 参数
##### 示例:
> micro call go.micro.api.orderservice OrderSrv.GetOrder '{"id":1}'

通过micro web调试

1
2
##### 启动micro web后台
> micro web
  1. 启动后,通过http://localhost:8082/访问后台。
  2. 【点击】右上角 【Client】,进入接口测试页面。

参考


Wanglibing
Wanglibing
Engineer,Lifelong learner