Golang - Go-Micro(一)


今天了解了下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方法
  • 解釋響應消息

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM