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