准备

  • 搭建好golang开发环境
  • 安装git等相关工具

开始

一、安装protobuf

protobuf用于生成微服务代码

go get github.com/micro/protoc-gen-micro

# 同时需要安装protoc和protoc-go-gen
go get -d -u github.com/golang/protobuf/protoc-gen-go
go install github.com/golang/protobuf/protoc-gen-go

如果需要别的语言的代码生成器,请参阅https://github.com/protocolbuffers/protobuf

关于protobuf的使用,请参阅https://developers.google.com/protocol-buffers/

二、服务发现

服务发现用于将服务名称解析为地址,服务发现可以使用etcd、zookeeper、consul等组件

安装etcd

etcd下载地址https://github.com/etcd-io/etcd/releases

三、写一个服务

以下为一个简单的rpc服务例子

创建服务proto

微服务的关键要求之一是严格定义接口。

Micro使用protobuf来实现这一目标。 在这里,我们使用Hello方法定义了Greeter处理程序。 它需要一个字符串参数同时使用一个HelloRequest和HelloResponse。

syntax = "proto3";

service Greeter {
    rpc Hello(HelloRequest) returns (HelloResponse) {}
}

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string greeting = 2;
}

生成proto

protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. path/to/greeter.proto

写服务业务逻辑

服务需要遵循以下规则:

  • 实现greeter定义的接口
  • 初始化一个micro.Service
  • 注册greeter处理函数
  • 运行服务
package main

import (
	"context"
	"fmt"

	micro "github.com/micro/go-micro"
	proto "github.com/micro/examples/service/proto"
)

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
	rsp.Greeting = "Hello " + req.Name
	return nil
}

func main() {
	// Create a new service. Optionally include some options here.
	service := micro.NewService(
		micro.Name("greeter"),
	)

	// Init will parse the command line flags.
	service.Init()

	// Register handler
	proto.RegisterGreeterHandler(service.Server(), new(Greeter))

	// Run the server
	if err := service.Run(); err != nil {
		fmt.Println(err)
	}
}

运行服务

go run examples/service/main.go

定义一个客户端

package main

import (
	"context"
	"fmt"

	micro "github.com/micro/go-micro"
	proto "github.com/micro/examples/service/proto"
)


func main() {
	// Create a new service. Optionally include some options here.
	service := micro.NewService(micro.Name("greeter.client"))
	service.Init()

	// Create new greeter client
	greeter := proto.NewGreeterService("greeter", service.Client())

	// Call the greeter
	rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{Name: "John"})
	if err != nil {
		fmt.Println(err)
	}

	// Print response
	fmt.Println(rsp.Greeting)
}

运行客户端

go run client.go

四、发布订阅

Go-micro具有用于事件驱动架构的内置消息代理接口。

PubSub与RPC在protobuf生成的相同消息上运行。它们会自动进行编码/解码,并通过代理发送。默认情况下,go-micro包含点对点http代理,但是可以通过go-plugins替换掉

发布

创建一个发布者

p := micro.NewPublisher("events", service.Client())
// 其中的events是话题名称

发布一个proto消息

p.Publish(context.TODO(), &proto.Event{Name: "event"})

订阅

创建一个消息句柄,

func ProcessEvent(ctx context.Context, event *proto.Event) error {
	fmt.Printf("Got event %+v\n", event)
	return nil
}

注册消息句柄到一个话题

micro.RegisterSubscriber("events", ProcessEvent)

详细例子请参考https://github.com/micro/examples/tree/master/pubsub

五、插件

默认情况下,go-micro仅在核心提供每个接口的一些实现,但它是完全可插入的。 github.com/micro/go-plugins上已有许多插件

插件使用

创建一个plugins.go文件

import (
        // etcd v3 registry
        _ "github.com/micro/go-plugins/registry/etcdv3"
        // nats transport
        _ "github.com/micro/go-plugins/transport/nats"
        // kafka broker
        _ "github.com/micro/go-plugins/broker/kafka"
)

构建二进制包

go build -i -o service ./main.go ./plugins.go

插件使用

service --registry=etcdv3 --transport=nats --broker=kafka

六、包装器

go-micro有很多中间件可以作为包装器使用

处理句柄

以下是一个处理句柄的日志函数示例

func logWrapper(fn server.HandlerFunc) server.HandlerFunc {
	return func(ctx context.Context, req server.Request, rsp interface{}) error {
		fmt.Printf("[%v] server request: %s", time.Now(), req.Endpoint())
		return fn(ctx, req, rsp)
	}
}

初始化如下

service := micro.NewService(
	micro.Name("greeter"),
	// wrap the handler
	micro.WrapHandler(logWrapper),
)

client

以下为一个客户端包装器log请求示例

type logWrapper struct {
	client.Client
}

func (l *logWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	fmt.Printf("[wrapper] client request to service: %s endpoint: %s\n", req.Service(), req.Endpoint())
	return l.Client.Call(ctx, req, rsp)
}

// implements client.Wrapper as logWrapper
func logWrap(c client.Client) client.Client {
	return &logWrapper{c}
}

初始化创建

service := micro.NewService(
	micro.Name("greeter"),
	// wrap the client
	micro.WrapClient(logWrap),
)