一、简单介绍 Go Micro是一个插件化的基础框架,基于此可以构建微服务。Micro的设计哲学是『可插拔』的插件化架构。在架构之外,它默认实现了consul作为服务发现,通过http进行通信,通过protobuf和json进行编解码。
二、示例 为了更为直观,先从示例开始。
1、环境搭建(安装依赖)
(1)安装protobuf
具体内容参考:https://blog.csdn.net/weixin_42117918/article/details/88920221
(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:https://www.consul.io/downloads.html
文章图片
在安装的位置解压得到 consul.exe 文件(我的解压位置是:C:\consul)
设置环境变量:
文章图片
启动:
cmd 命令窗口执行:
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.protopackage helloimport (
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 packagetype HelloRequest struct {
Namestring`protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized[]byte`json:"-"`
XXX_sizecacheint32`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.InternalMessageInfofunc (m *HelloRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}type HelloResponse struct {
Greetingstring`protobuf:"bytes,2,opt,name=greeting,proto3" json:"greeting,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized[]byte`json:"-"`
XXX_sizecacheint32`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.InternalMessageInfofunc (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.protopackage helloimport (
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 servicetype GreeterService interface {
Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error)
}type greeterService struct {
cclient.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 servicetype 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 mainimport (
"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 mainimport (
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、运行 (1)启动consul:
consul agent -dev(Windows命令行命令 )
(2)运行服务器端:
文章图片
(3)运行客户端端:
文章图片
三、原理 【Golang|Golang 微服务框架——Micro的使用】参考:https://blog.csdn.net/weixin_42117918/article/details/89148666
推荐阅读
- 微服务|微服务系列:服务发现与注册-----Eureka(面试突击!你想了解的Eureka都在这里.持续更新中......)
- 每日一书|每日一书丨学习微服务最好的方式(阅读《微服务架构设计模式》)
- 【golang】leetcode中级-字母异位词分组&无重复字符的最长子串
- 彻底理解Golang Map
- kratos线上开源年会它来啦~
- 深入浅出 Golang 资源嵌入方案(go-bindata篇)
- 深入浅出 Golang 资源嵌入方案(前篇)
- golang 经典案例总结
- Go实战 | 基于有向无环图的并发执行流的实现
- Golang 数组和切片