• Golang


    今天了解了下GO的微服务,看了下Go-micro,做下记录。

    简单介绍

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

    • Go Micro - 基于Golang的插件式RPC框架,提供服务发现,客户端负载均衡,编码,同步和异步通讯功能。
    • API - API Gateway(API 网关), 用来提供处理http请求。可以作为一个http的反向代理或者翻译相关的http请求到RPC服务。
    • Sidecar - 用来接入其他语言编写的应用到Micro中。
    • Web - 提供一个web dashboard,并且可以为Micro应用提供反向代理。
    • CLI - 用来跟Micro服务交互的命令行工具。
    • Bot - 用它我们可以在我们的服务中与Slack, HipChat, XMPP通讯。

    架构图:

    安装依赖

    1.安装 consul

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

    2.安装protobuf

    go get github.com/micro/protobuf/{proto,protoc-gen-go}
    

    发现无法用 protoc-gen-go 生成代码。所以我去下载了protobuf

    这里我是MAC系统所以,下载对应的mac版本 protobuf

    解压将bin目录下的protoc放到物理机/usr/local/sbin下面。

    3.安装go-micro

    go get github.com/micro/go-micro
    

    4.安装micro

    go get github.com/micro/micro
    

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

    构建

    1.创建一个proto文件

    proto语法请参考 google protobuf

    syntax = "proto3";
    
    service HelloWorld {
        rpc Hello(HelloRequest) returns (HelloResponse) {}
    }
    
    message HelloRequest {
        string name = 1;
    }
    
    message HelloResponse {
        string greeting = 2;
    }
    

    2.编译成go

    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:
        HelloRequest
        HelloResponse
    */
    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 package
    
    type HelloRequest struct {
        Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
    }
    
    func (m *HelloRequest) Reset()                    { *m = HelloRequest{} }
    func (m *HelloRequest) String() string            { return proto.CompactTextString(m) }
    func (*HelloRequest) ProtoMessage()               {}
    func (*HelloRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
    
    func (m *HelloRequest) GetName() string {
        if m != nil {
            return m.Name
        }
        return ""
    }
    
    type HelloResponse struct {
        Greeting string `protobuf:"bytes,2,opt,name=greeting" json:"greeting,omitempty"`
    }
    
    func (m *HelloResponse) Reset()                    { *m = HelloResponse{} }
    func (m *HelloResponse) String() string            { return proto.CompactTextString(m) }
    func (*HelloResponse) ProtoMessage()               {}
    func (*HelloResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
    
    func (m *HelloResponse) GetGreeting() string {
        if m != nil {
            return m.Greeting
        }
        return ""
    }
    
    func init() {
        proto.RegisterType((*HelloRequest)(nil), "HelloRequest")
        proto.RegisterType((*HelloResponse)(nil), "HelloResponse")
    }
    
    // Reference imports to suppress errors if they are not otherwise used.
    var _ context.Context
    var _ client.Option
    var _ server.Option
    
    // Client API for HelloWorld service
    
    type HelloWorldClient interface {
        Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, 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 *HelloRequest, opts ...client.CallOption) (*HelloResponse, error) {
        req := c.c.NewRequest(c.serviceName, "HelloWorld.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 HelloWorld service
    
    type HelloWorldHandler interface {
        Hello(context.Context, *HelloRequest, *HelloResponse) 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 *HelloRequest, out *HelloResponse) 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, 0xe2,
        0xe2, 0xf1, 0x00, 0x09, 0x06, 0xa5, 0x16, 0x96, 0xa6, 0x16, 0x97, 0x08, 0x09, 0x71, 0xb1, 0xe4,
        0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, 0x81, 0xd9, 0x4a, 0xda, 0x5c, 0xbc,
        0x50, 0x35, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x42, 0x52, 0x5c, 0x1c, 0xe9, 0x45, 0xa9, 0xa9,
        0x25, 0x99, 0x79, 0xe9, 0x12, 0x4c, 0x60, 0x85, 0x70, 0xbe, 0x91, 0x19, 0x17, 0x17, 0x58, 0x71,
        0x38, 0xc8, 0x12, 0x21, 0x0d, 0x2e, 0x56, 0x30, 0x4f, 0x88, 0x57, 0x0f, 0xd9, 0x1a, 0x29, 0x3e,
        0x3d, 0x14, 0x13, 0x95, 0x18, 0x92, 0xd8, 0xc0, 0xee, 0x31, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff,
        0x7e, 0xdc, 0x2e, 0x9b, 0xa4, 0x00, 0x00, 0x00,
    }
    

    3.生成服务

    package main
    
    import (
        "fmt"
        "leaning01/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.HelloRequest, rsp *hello_world.HelloResponse) 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)
        } // 运行服务
    }
    
    

    4.客户端

    package main
    
    import (
        "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)
    }
    

    总结开发流程

    公共开发模块

    • 创建消息protobuf文件, 在其中定义消息
    • 根据定义的protobuf文件,生成基于该语言的实现类

    服务端

    • 实现在消息中定义的RPC方法
    • 初始化一个新的Service对象
    • 注册服务
    • 运行服务

    客户端

    • 初始化一个新的Service对象
    • 定义请求消息
    • 传入请求消息调用服务端定义RPC方法
    • 解释响应消息

    参考资料

  • 相关阅读:
    android 3G移植【转】
    【转】小白级的CocoaPods安装和使用教程
    【转】Core Bluetooth框架之二:后台处理
    【转】Core Bluetooth框架之一:Central与Peripheral
    ios ble 参考
    拼音处理
    通过触发器实现数据库的即时同步
    数据库中存取文件
    交叉报表处理实例
    SQL Server 2005 中实现通用的异步触发器架构
  • 原文地址:https://www.cnblogs.com/pzblog/p/9088282.html
Copyright © 2020-2023  润新知