go+protobuf+grpc+consul簡單的服務發現模型
阿新 • • 發佈:2021-06-24
一 環境準備
- windows64 (此處我用的windows,建議大家linux)
- 安裝consul,請自行搜尋
- 安裝protobuf,請自行搜尋
二 概念梳理
- consul 是服務發現工具,簡單地說,就是各個server將自己註冊到consul上,client不再記住各個server的ip+port,而是去consul上獲取想要連線的server。使得server對client不再需要暴露,可以動態伸縮。
- protobuf 可以拿來和xml、json對比,都是資料格式,只是protobuf更加輕量級,適合做微服務或者tcp通訊。使用起來相對繁瑣一點點。
- rpc 可以對比ipc(程序間通訊),它是各個服務間的通訊,重點在r和i的區別,rpc是遠端呼叫。
- grpc 是rpc的一種,它是進階版,更高效,基於http2(可以雙工通訊),預設採用protobuf格式的資料
三 實現過程
3.1目錄結構
- 專案名稱test_grpc_consul
- pb目錄為存放protobuf檔案
- person.proto為源生protobuf程式碼
- person.pb.go為編譯打包出的能為go呼叫的程式碼
- consul-server.go為server程式,實現了往consul的註冊和服務的監聽
- consul-client.go為client程式,實現了從consul查詢server併發起呼叫
- consul-deregister為一個管理程式,實現了consul中server的登出
3.2 protobuf的生成
person.proto
1 syntax = "proto3"; 2 3 package pb; 4 option go_package = "./;pb"; //此處我也不知道幹嘛用的,不加他報錯,網上搜索的解決方案 5 6 message Person{ 7 string name = 1; 8 int32 age = 2; 9 } 10 11 //新增rpc服務 12 service hello{ 13 rpc sayHello(Person) returns (Person); 14 15 }
將person.proto編譯打包
先cd到pb目錄,再執行以下命令
protoc --go_out=plugins=grpc:./ *.proto
生成person.pb.go檔案
其實golang中,一般的rpc中proto的打包為以下命令:
protoc --go_out=./ *.proto
3.3server程式
package main import ( "context" "fmt" "/test_grpc_consul/pb" //你們自己的路徑 "github.com/hashicorp/consul/api" "google.golang.org/grpc" "net" ) type Children struct { } func (this *Children)SayHello(ctx context.Context,p *pb.Person) (*pb.Person,error){ p.Name = "hello "+p.Name return p,nil } func main(){ //把grpc服務註冊到consul上 //初始化consul配置 consulConfig := api.DefaultConfig() //建立consul物件 consulClient,err := api.NewClient(consulConfig) if err!=nil{ fmt.Println("server, api.newclient err:",err) return } //告訴consul,即將註冊的服務的配置資訊 reg := api.AgentServiceRegistration{ Kind: "", ID: "wbw1_id", Name: "wbw001_grpc_consul", Tags: []string{"wbw1","asa1"}, Port: 8800, Address: "127.0.0.1", TaggedAddresses: nil, EnableTagOverride: false, Meta: nil, Weights: nil, Check: &api.AgentServiceCheck{ CheckID: "wbw1_id_check", Name: "", Args: nil, DockerContainerID: "", Shell: "", Interval: "5s", Timeout: "1s", TTL: "", HTTP: "", Header: nil, Method: "", Body: "", TCP: "127.0.0.1:8800", Status: "", Notes: "", TLSServerName: "", TLSSkipVerify: false, GRPC: "", GRPCUseTLS: false, AliasNode: "", AliasService: "", SuccessBeforePassing: 0, FailuresBeforeCritical: 0, DeregisterCriticalServiceAfter: "", }, Checks: nil, Proxy: nil, Connect: nil, Namespace: "", } //註冊gprc服務到consul上 consulClient.Agent().ServiceRegister(®) grpcServer := grpc.NewServer() pb.RegisterHelloServer(grpcServer,new(Children)) listener,err := net.Listen("tcp", "127.0.0.1:8800") if err != nil{ fmt.Println("listen err:",err) } defer listener.Close() grpcServer.Serve(listener) }
3.4 client程式
package main import ( "context" "fmt" "/test_grpc_consul/pb" //同server此處 "github.com/hashicorp/consul/api" "google.golang.org/grpc" "strconv" ) func main(){ consulConfig := api.DefaultConfig() conculClient,err := api.NewClient(consulConfig) if err!=nil{ fmt.Println("client, api.newclient err:",err) return } services,_,err := conculClient.Health().Service("wbw001_grpc_consul","wbw1",true,nil ) addr := services[0].Service.Address+":"+strconv.Itoa(services[0].Service.Port) //grpcConn,err := grpc.Dial("127.0.0.1:8800",grpc.WithInsecure()) grpcConn,err := grpc.Dial(addr,grpc.WithInsecure()) if err != nil{ fmt.Println("dial err:",err) } defer grpcConn.Close() grpcClient := pb.NewHelloClient(grpcConn) var person pb.Person person.Name = "wbw" person.Age = 18 p,err := grpcClient.SayHello(context.TODO(),&person) fmt.Println(p,err) }
3.5 server登出程式
package main import ( "fmt" "github.com/hashicorp/consul/api" ) func main(){ consulConfig := api.DefaultConfig() consulClient,err := api.NewClient(consulConfig) if err != nil{ fmt.Println("deregister, api.newclient err:",err) return } consulClient.Agent().ServiceDeregister("wbw1_id")
}
四 呼叫說明
4.1 啟動 consul
//本文請用
consul agent -dev
//但是生產環境建議用
// consul agent -server -bootstrap-expect 1 -data-dir D:\tools\consul_1.10.0_windows_amd64\data_dir\ -node=n1 -bind=10.10.10.18 -ui -rejoin -config-dir=D:\tools\consul_1.10.0_windows_amd64\config_dir\ -client 0.0.0.0
我們進入網址http://localhost:8500/
可以發現我們的consul啟動完成
4.2啟動server
先cd到test_grpc_consul目錄,再執行以下命令
go run consul-server.go
可以看到我們的服務已經執行了
然後進入網址http://localhost:8500/可以看到我們的服務已經成功註冊到consul了,點進去還能看到健康檢測正常
4.3啟動client
先cd到test_grpc_consul目錄,再執行以下命令
go run consul-client.go
呼叫成功!!!
4.4啟動登出程式
先cd到test_grpc_consul目錄,再執行以下命令
go run consul-deregister.go
我們可以看到該server已經不再consul中了,同時我們呼叫client也會失敗。
注意:
如果我們把client直連server,依然能成功,因為我們的server並沒有退出,僅僅是在consul中抹掉了痕跡。
四 補充說明
- 建議開啟go mod,這樣不依賴於gopath等路徑,且不需要go get等操作,能利用goland自動拉取