Go Micro是一个插件化的基础框架,基于此可以构建微服务。Micro的设计哲学是『可插拔』的插件化架构。在架构之外,它默认实现了consul作为服务发现,通过http进行通信,通过protobuf和json进行编解码。
二、示例为了更为直观,先从示例开始。
1、环境搭建(安装依赖)
(1)安装protobuf
(2)安装go-micro
go get github.com/micro/go-micro
(3)安装micro
go get github.com/micro/micro
(4)安装consul
由于Micro的服务发现并没有自己实现,仅仅是提供Plugin来接入第三方服务发现(consul, etcd), 默认使用的是consule,因此需要安装consul。(以Windows开发环境为例)
在安装的位置解压得到 consul.exe 文件(我的解压位置是:C:\consul)
设置环境变量:
启动:
consul agent -dev
consul 自带 UI 界面,打开网址:http://localhost:8500 ,可以看到当前注册的服务界面
2、创建一个proto文件
我定义的文件名为:hello.proto
syntax = "proto3";
message HelloRequest {
string name = 1;
}
message HelloResponse {
string greeting = 2;
}
service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse) {}
}
3、生成 xx.pb.go、xx.micro.go文件
(1)命令及生成的代码如下:
protoc --go_out=plugins=micro:. hello.proto
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hello.proto
package hello
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type HelloRequest struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HelloRequest) Reset() { *m = HelloRequest{} }
func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
func (*HelloRequest) ProtoMessage() {}
func (*HelloRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_61ef911816e0a8ce, []int{0}
}
func (m *HelloRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HelloRequest.Unmarshal(m, b)
}
func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic)
}
func (m *HelloRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_HelloRequest.Merge(m, src)
}
func (m *HelloRequest) XXX_Size() int {
return xxx_messageInfo_HelloRequest.Size(m)
}
func (m *HelloRequest) XXX_DiscardUnknown() {
xxx_messageInfo_HelloRequest.DiscardUnknown(m)
}
var xxx_messageInfo_HelloRequest proto.InternalMessageInfo
func (m *HelloRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
type HelloResponse struct {
Greeting string `protobuf:"bytes,2,opt,name=greeting,proto3" json:"greeting,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HelloResponse) Reset() { *m = HelloResponse{} }
func (m *HelloResponse) String() string { return proto.CompactTextString(m) }
func (*HelloResponse) ProtoMessage() {}
func (*HelloResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_61ef911816e0a8ce, []int{1}
}
func (m *HelloResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HelloResponse.Unmarshal(m, b)
}
func (m *HelloResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HelloResponse.Marshal(b, m, deterministic)
}
func (m *HelloResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_HelloResponse.Merge(m, src)
}
func (m *HelloResponse) XXX_Size() int {
return xxx_messageInfo_HelloResponse.Size(m)
}
func (m *HelloResponse) XXX_DiscardUnknown() {
xxx_messageInfo_HelloResponse.DiscardUnknown(m)
}
var xxx_messageInfo_HelloResponse proto.InternalMessageInfo
func (m *HelloResponse) GetGreeting() string {
if m != nil {
return m.Greeting
}
return ""
}
func init() {
proto.RegisterType((*HelloRequest)(nil), "HelloRequest")
proto.RegisterType((*HelloResponse)(nil), "HelloResponse")
}
func init() { proto.RegisterFile("hello.proto", fileDescriptor_61ef911816e0a8ce) }
var fileDescriptor_61ef911816e0a8ce = []byte{
// 130 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0x48, 0xcd, 0xc9,
0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x52, 0xe2, 0xe2, 0xf1, 0x00, 0x71, 0x83, 0x52,
0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x84, 0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, 0x25, 0x18, 0x15,
0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x25, 0x6d, 0x2e, 0x5e, 0xa8, 0x9a, 0xe2, 0x82, 0xfc, 0xbc,
0xe2, 0x54, 0x21, 0x29, 0x2e, 0x8e, 0xf4, 0xa2, 0xd4, 0xd4, 0x92, 0xcc, 0xbc, 0x74, 0x09, 0x26,
0xb0, 0x42, 0x38, 0xdf, 0xc8, 0x98, 0x8b, 0xdd, 0x1d, 0xc4, 0x4e, 0x2d, 0x12, 0xd2, 0xe0, 0x62,
0x05, 0xeb, 0x13, 0xe2, 0xd5, 0x43, 0xb6, 0x43, 0x8a, 0x4f, 0x0f, 0xc5, 0x38, 0x25, 0x86, 0x24,
0x36, 0xb0, 0x63, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf5, 0x83, 0xc3, 0x7d, 0x9b, 0x00,
0x00, 0x00,
}
(2)命令及生成的代码如下:
protoc --proto_path=. --micro_out=. --go_out=. hello.proto
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: hello.proto
package hello
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
client "github.com/micro/go-micro/client"
server "github.com/micro/go-micro/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ client.Option
var _ server.Option
// Client API for Greeter service
type GreeterService interface {
Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error)
}
type greeterService struct {
c client.Client
name string
}
func NewGreeterService(name string, c client.Client) GreeterService {
if c == nil {
c = client.NewClient()
}
if len(name) == 0 {
name = "greeter"
}
return &greeterService{
c: c,
name: name,
}
}
func (c *greeterService) Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error) {
req := c.c.NewRequest(c.name, "Greeter.Hello", in)
out := new(HelloResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Greeter service
type GreeterHandler interface {
Hello(context.Context, *HelloRequest, *HelloResponse) error
}
func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler, opts ...server.HandlerOption) error {
type greeter interface {
Hello(ctx context.Context, in *HelloRequest, out *HelloResponse) error
}
type Greeter struct {
greeter
}
h := &greeterHandler{hdlr}
return s.Handle(s.NewHandler(&Greeter{h}, opts...))
}
type greeterHandler struct {
GreeterHandler
}
func (h *greeterHandler) Hello(ctx context.Context, in *HelloRequest, out *HelloResponse) error {
return h.GreeterHandler.Hello(ctx, in, out)
}
生成的文件如上图所示。
4、服务端代码
package main
import (
"fmt"
"github.com/micro/go-micro"
"golang.org/x/net/context"
)
import pb "MyMicro" //import proto生成的类
type Greeter struct {
}
/*
实现proto生成的hello.micro.go中的
type GreeterHandler interface {
Hello(context.Context, *HelloRequest, *HelloResponse) error}
*/
func (g *Greeter) Hello(ctx context.Context, rep *pb.HelloRequest, rsp *pb.HelloResponse) error {
rsp.Greeting = "Hello" + rep.Name
//fmt.Printf()
return nil
}
func main() {
//新建一个服务
service := micro.NewService(micro.Name("greeter"),
micro.Version("latest"),
micro.Metadata(map[string]string{"type": "hello world"}))
service.Init() //初始化服务
err := pb.RegisterGreeterHandler(service.Server(), new(Greeter)) //注册服务
if err != nil {
fmt.Println("注册服务出现了问题...", err)
return
}
//运行服务
if err := service.Run(); err != nil {
fmt.Println("服务运行出现了错误:", err)
}
}
5、客户端代码
package main
import (
pb "MyMicro"
"fmt"
"github.com/micro/go-micro"
"golang.org/x/net/context"
)
func main() {
service := micro.NewService(micro.Name("greeter"),
micro.Version("latest"),
micro.Metadata(map[string]string{"type": "hello world"}))
service.Init()
greeter := pb.NewGreeterService("greeter", service.Client()) //调用proto生成的hello.micro.go中的NewGreeterService方法
res := pb.HelloRequest{}
res.Name = "jiangzhou"
rsp, err := greeter.Hello(context.TODO(), &res) //Client API for Greeter service
if err != nil {
fmt.Println("请求服务出现了问题...", err)
return
}
fmt.Println("服务返回的结果为:", rsp.Greeting)
}
6、运行
consul agent -dev(Windows命令行命令 )
(2)运行服务器端:
(3)运行客户端端:
三、原理