1. 程式人生 > >go micro實戰01:快速搭建服務

go micro實戰01:快速搭建服務

背景

go-micro給我們提供了一個非常便捷的方式來快速搭建微服務,而且並不需要提前系統瞭解micro,下面用一個簡單的示例來快速實現一個服務。

建立Proto檔案

因為我們要做微服務,那麼就一定有服務端和客戶端,這兩個端通過什麼格式進行內容傳輸,就涉及到了序列化,比較主流的序列化協議就是JSON和Protobuf,因為Protobuf是以二進位制傳輸的,體積比較小,所以傳輸速度也相對較快,今天就以protobuf來進行演示。

下面使用Proto3的語法在protos目錄建立檔案greeter.proto,該檔案定義一個名為Greeter的服務,以及對應的入參和出參。

syntax = "proto3";
package protos;

service Greeter {
    rpc Hello (Request) returns (Response) {
    };
}

message Request {
    string name = 1;
}

message Response {
    string greeting = 2;
}

生成Go檔案

生成Go檔案之前,要先確保本機安裝了protobuf,如果在終端輸入protoc沒有打印出幫助文件,那麼就是未安裝。

$ protoc
Usage: protoc [OPTION] PROTO_FILES
Parse PROTO_FILES and generate output based on the options given:
  -IPATH, --proto_path=PATH   Specify the directory in which to search for
                              imports.  May be specified multiple times;
                              directories will be searched in order.  If not
                              ……

可以通過官方文件提示的命令進行安裝。

go get github.com/micro/protoc-gen-micro/v2

安裝成功之後,通過protoc命令將greeter.proto檔案生成出對應的Go檔案。

protoc --proto_path=./protos --micro_out=./protos --go_out=./protos ./protos/greeter.proto
  • --proto_path是greeter.proto檔案所在的路徑

  • --micro_out是生成.go檔案的所在目錄,該檔案被用於建立服務

  • --go_out是生成.go檔案的所在目錄,該檔案被用於做資料序列化傳輸

可以根據需求自定義輸出目錄,我這邊輸出到了protos目錄,現在可以看到protos目錄中生成了兩個檔案。

greeter.pb.go
greeter.pb.micro.go

實現服務

因為剛才已經通過protobuf定義了服務的介面,所以接下來需要實現對應的服務。

第一步,實現定義的服務介面

在生成的greeter.pb.micro.go檔案中,可以看到我們greeter.proto檔案中一個名為GreeterHandler的介面。

type GreeterHandler interface {
    Hello(context.Context, *Request, *Response) error
}

我們需要先實現該介面,接下來建立server.go檔案,定義結構體Greeter,並實現Hello方法。

type Greeter struct {
}

func (g *Greeter) Hello(context context.Context, req *protos.Request, rsp *protos.Response) error {
    rsp.Greeting = "Hello " + req.Name
    return nil
}

Hello方法的後兩個引數剛好就是我們前面所生成的greeter.bp.go檔案中定義的Request和Response結構體。在方法內部,將請求引數的Name前面拼接上了Hello字串,並且賦值給了Response的Greeting變數。

第二步,初始化服務

我們建立一個名為greeter的服務。

func main() {
    service := micro.NewService(
        micro.Name("greeter"),
    )
    service.Init()
}

呼叫micro.NewService方法來建立一個新的服務,該方法的引數是可變引數,可以通過micro中的一系列方法來設定服務的引數,本次示例中只配置服務的名稱,記得在建立完服務後執行service.Init方法來初始化,micro版本建議使用v2。

第三步,註冊服務到handler

func main() {
    service := micro.NewService(
        micro.Name("greeter"),
    )
    service.Init()
    err := protos.RegisterGreeterHandler(service.Server(), new(Greeter))
    if err != nil {
        fmt.Println(err)
    }
}

第四步,將服務跑起來

    if err := service.Run(); err != nil {
        fmt.Println(err)
    }

完整程式碼如下

package main

import (
    "context"
    "fmt"

    "github.com/micro/go-micro/v2"
)

type Greeter struct {
}

func (g *Greeter) Hello(context context.Context, req *Request, rsp *Response) error {
    rsp.Greeting = "Hello " + req.Name
    return nil
}

func main() {
    service := micro.NewService(
        micro.Name("greeter"),
    )
    service.Init()

    err := protos.RegisterGreeterHandler(service.Server(), new(Greeter))
    if err != nil {
        fmt.Println(err)
    }

    if err := service.Run(); err != nil {
        fmt.Println(err)
    }
}

現在將服務端跑起來。

$ go run server.go
2020-03-27 11:28:20 Starting [service] greeter
2020-03-27 11:28:20 Server [grpc] Listening on [::]:63763
2020-03-27 11:28:20 Registry [mdns] Registering node: greeter-8afc1183-a159-4473-a567-c13b83d1d75c

實現客戶端

建立client.go檔案

func main() {
    service := micro.NewService(micro.Name("greeter.client"))
    service.Init()

    greeter := protos.NewGreeterService("greeter", service.Client())
    rsp, err := greeter.Hello(context.TODO(), &protos.Request{Name: "pingye"})
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(rsp.Greeting)
}

執行客戶端檔案,輸出Hello pingye,執行成功。

$ go run client.go
Hello pingye

服務註冊到了哪裡?

在啟動服務端的時候從終端輸出的資訊可以看出,有一個名為greeter的服務註冊到了Registry

2020-03-27 11:28:20 Starting [service] greeter
2020-03-27 11:28:20 Server [grpc] Listening on [::]:63763
2020-03-27 11:28:20 Registry [mdns] Registering node: greeter-8afc1183-a159-4473-a567-c13b83d1d75c

Registry是go-micro的註冊模組,作用是將服務註冊到某個介質,以方便客戶端使用。註冊模組預設支援cache、consul、etcd、k8s、mdns、memory等多種介質,預設使用的是mdns。

var (
    DefaultRegistry = NewRegistry()

    // Not found error when GetService is called
    ErrNotFound = errors.New("service not found")
    // Watcher stopped error when watcher is stopped
    ErrWatcherStopped = errors.New("watcher stopped")
)

mdns主要用於在沒有傳統DNS伺服器的情況下,在區域網中實現主機之間的發現與通訊,它遵從DNS協議。

Go語言元件示例開源庫,歡迎star
https://github.com/EnochZg/golang-examples