为了账号安全,请及时绑定邮箱和手机立即绑定

Micro (1)

标签:
架构

简单介绍

Micro是一个用来简化微服务开发的框架,提供了如下功能:

  1. Go Micro - 基于Golang的插件式RPC框架,提供服务发现,客户端负载均衡,编码,同步和异步通讯功能。

  2. API - API Gateway(API 网关), 用来提供处理http请求。可以作为一个http的反向代理或者翻译相关的http请求到RPC服务。

  3. Sidecar - 用来接入其他语言编写的应用到Micro中。

  4. Web - 提供一个web dashboard,并且可以为Micro应用提供反向代理。

  5. CLI - 用来跟Micro服务交互的命令行工具。

  6. Bot - 用它我们可以在我们的服务中与Slack, HipChat, XMPP通讯。


    架构如下图所示:

    webp

    Micro架构图

安装

  1. 由于Micro的服务发现并没有自己实现,仅仅是提供Plugin来接入第三方服务发现(consul, etcd), 默认使用的是consul
    安装参考: consul installation doc

  2. 安装protobuf

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

go get github.com/micro/go-micro
  1. 安装micro, 参考github micro

go get github.com/micro/micro

接下来我们简单使用micro来构建一个hello world 应用。

  1. 创建一个proto文件, proto语法请参考google protobuf

// hello_world.protosyntax = "proto3";

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

message HelloRequest {    string name = 1;
}

message HelloResponse {    string greeting = 2;
}
  1. 通常我们需要将上述hello_world.proto文件编译输出相关语言的代码实现文件。

protoc --go_out=plugins=micro:. hello_world.proto

生成文件hello_world.pb.go

// Code generated by protoc-gen-go. DO NOT EDIT.// source: hello_world.proto/*
Package hello_world is a generated protocol buffer package.

It is generated from these files:
    hello_world.proto

It has these top-level messages:
    HelloWorldRequest
    HelloWorldResponse
*/package hello_world

import proto "github.com/golang/protobuf/proto"import fmt "fmt"import math "math"import (
    client "github.com/micro/go-micro/client"
    server "github.com/micro/go-micro/server"
    context "golang.org/x/net/context")// 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.ProtoPackageIsVersion2 // please upgrade the proto packagetype HelloWorldRequest struct {
    Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
}

func (m *HelloWorldRequest) Reset()                    { *m = HelloWorldRequest{} }
func (m *HelloWorldRequest) String() string            { return proto.CompactTextString(m) }
func (*HelloWorldRequest) ProtoMessage()               {}
func (*HelloWorldRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }

func (m *HelloWorldRequest) GetName() string {    if m != nil {        return m.Name
    }    return ""}

type HelloWorldResponse struct {
    Greeting string `protobuf:"bytes,2,opt,name=greeting" json:"greeting,omitempty"`
}

func (m *HelloWorldResponse) Reset()                    { *m = HelloWorldResponse{} }
func (m *HelloWorldResponse) String() string            { return proto.CompactTextString(m) }
func (*HelloWorldResponse) ProtoMessage()               {}
func (*HelloWorldResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }

func (m *HelloWorldResponse) GetGreeting() string {    if m != nil {        return m.Greeting
    }    return ""}

func init() {
    proto.RegisterType((*HelloWorldRequest)(nil), "HelloWorldRequest")
    proto.RegisterType((*HelloWorldResponse)(nil), "HelloWorldResponse")
}// Reference imports to suppress errors if they are not otherwise used.var _ context.Context
var _ client.Option
var _ server.Option// Client API for HelloWorld servicetype HelloWorldClient interface {
    Hello(ctx context.Context, in *HelloWorldRequest, opts ...client.CallOption) (*HelloWorldResponse, error)
}

type helloWorldClient struct {
    c           client.Client
    serviceName string
}

func NewHelloWorldClient(serviceName string, c client.Client) HelloWorldClient {    if c == nil {
        c = client.NewClient()
    }    if len(serviceName) == 0 {
        serviceName = "helloworld"
    }    return &helloWorldClient{
        c:           c,
        serviceName: serviceName,
    }
}

func (c *helloWorldClient) Hello(ctx context.Context, in *HelloWorldRequest, opts ...client.CallOption) (*HelloWorldResponse, error) {
    req := c.c.NewRequest(c.serviceName, "HelloWorld.Hello", in)    out := new(HelloWorldResponse)
    err := c.c.Call(ctx, req, out, opts...)    if err != nil {        return nil, err
    }    return out, nil}// Server API for HelloWorld servicetype HelloWorldHandler interface {
    Hello(context.Context, *HelloWorldRequest, *HelloWorldResponse) error
}

func RegisterHelloWorldHandler(s server.Server, hdlr HelloWorldHandler, opts ...server.HandlerOption) {
    s.Handle(s.NewHandler(&HelloWorld{hdlr}, opts...))
}

type HelloWorld struct {
    HelloWorldHandler
}

func (h *HelloWorld) Hello(ctx context.Context, in *HelloWorldRequest, out *HelloWorldResponse) error {    return h.HelloWorldHandler.Hello(ctx, in, out)
}

func init() { proto.RegisterFile("hello_world.proto", fileDescriptor0) }

var fileDescriptor0 = []byte{    // 136 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcc, 0x48, 0xcd, 0xc9,    0xc9, 0x8f, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x52, 0xe7,    0x12, 0xf4, 0x00, 0x09, 0x86, 0x83, 0xc4, 0x82, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x84,    0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x25,    0x03, 0x2e, 0x21, 0x64, 0x85, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x42, 0x52, 0x5c, 0x1c, 0xe9,    0x45, 0xa9, 0xa9, 0x25, 0x99, 0x79, 0xe9, 0x12, 0x4c, 0x60, 0xd5, 0x70, 0xbe, 0x91, 0x03, 0x17,    0x17, 0x42, 0x87, 0x90, 0x11, 0x17, 0x2b, 0x98, 0x27, 0x24, 0xa4, 0x87, 0x61, 0xa1, 0x94, 0xb0,    0x1e, 0xa6, 0xd9, 0x4a, 0x0c, 0x49, 0x6c, 0x60, 0x37, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff,    0x80, 0x8c, 0xf7, 0x9b, 0xb8, 0x00, 0x00, 0x00,
}

下面简述其中几个关键输出:

package hello_world // 消息定义所在packagetype HelloWorldRequest struct {
    Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
} //请求消息类type HelloWorldResponse struct {
    Greeting string `protobuf:"bytes,2,opt,name=greeting" json:"greeting,omitempty"`
} // 响应消息类type HelloWorldClient interface {
    Hello(ctx context.Context, in *HelloWorldRequest, opts ...client.CallOption) (*HelloWorldResponse, error)
} // 服务请求接口, 定义客户端可调用的请求方法'Hello', 客户端编程使用type HelloWorldHandler interface {
    Hello(context.Context, *HelloWorldRequest, *HelloWorldResponse) error
} // 服务端interface, 定义服务端需要实现的方法'Hello', 服务端编程使用func RegisterHelloWorldHandler(s server.Server, hdlr HelloWorldHandler, opts ...server.HandlerOption) {
    s.Handle(s.NewHandler(&HelloWorld{hdlr}, opts...))
} // 服务端使用该方法注册定义的Service, 服务端编程使用type HelloWorld struct {
    HelloWorldHandler
}
func (h *HelloWorld) Hello(ctx context.Context, in *HelloWorldRequest, out *HelloWorldResponse) error {    return h.HelloWorldHandler.Hello(ctx, in, out)
}// 定义HelloWorld类,需要服务端实现其中的Handle的方法'Hello', 服务端编程使用

服务端实现

package mainimport (    "fmt"
    "./hello_world" // import proto生成的类
    "github.com/micro/go-micro"
    "golang.org/x/net/context")type HelloWorld struct{}

func (g *HelloWorld) Hello(ctx context.Context, req *hello_world.HelloWorldRequest, rsp *hello_world.HelloWorldResponse) error {
    rsp.Greeting = "Hello World: " + req.Name    return nil
} // 实现hello_world service中Hello方法func main() {
    service := micro.NewService(
        micro.Name("hello_world"), // 定义service的名称为hello_world
        micro.Version("latest"),
        micro.Metadata(map[string]string{            "type": "helloworld",
        }),
    )

    service.Init() // 初始化service

    hello_world.RegisterHelloWorldHandler(service.Server(), new(HelloWorld)) // 注册服务

    if err := service.Run(); err != nil {
        fmt.Println(err)
    } // 运行服务}

客户端实现

package mainimport (    "fmt"
    "./hello_world"
    "github.com/micro/go-micro"
    "golang.org/x/net/context")func main() {
    service := micro.NewService(
        micro.Name("hello_world"),
        micro.Version("latest"),
        micro.Metadata(map[string]string{            "type": "helloworld",
        }),
    )

    service.Init()

    greeter := hello_world.NewHelloWorldClient("hello_world", service.Client()) // 创建服务hello_world的client对象, 以便调用其中定义的RPC方法'Hello'

    rsp, err := greeter.Hello(context.TODO(), &hello_world.HelloWorldRequest{Name: "Alice"}) // 传入HelloWorldRequest对象作为调用RPC方法的参数'Hello'
    if err != nil {
        fmt.Println(err)        return
    }

    fmt.Println(rsp.Greeting)
}

总结开发流程

  1. 公共开发模块

  • 创建消息protobuf文件, 在其中定义RPC方法

  • 根据定义的protobuf文件,生成基于该语言的实现类

服务端

  • 实现在消息中定义的RPC方法

  • 初始化一个新的Service对象

  • 注册服务

  • 运行服务

客户端

  • 初始化一个新的Service对象

  • 定义请求消息

  • 传入请求消息调用服务端定义RPC方法

  • 解释响应消息



作者:zouqilin
链接:https://www.jianshu.com/p/36d9376321cd


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消