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