go gRPC初體驗(win10+普通網絡)

在公司實習的時候,發現代碼裏面有grpc,當時啥也不懂,也不知道咋用的,好在實習期間並沒有需要新增rpc調用的地方,但還是覺得趁早弄明白比較好,以後總會用到。

既然是初體驗,肯定是從啥都沒有開始的,網上很多文章,安裝各種包、命令講的不是很系統,所以本篇就記錄一下從安裝開始,到運行一個小case的全過程

首先聲明一下,我是在win10上操作的,我覺得吧,什麼東西,如果能在windows上搞通了,在linux和mac上自然也就沒問題了。

另外再聲明一下,我電腦沒有翻牆,以下所有操作都是普通網絡環境就可以搞定的

安裝protoc

grpc使用protocol buffers作爲IDL,這很好理解,都是谷歌出的,而使用grpc,第一步其實就是自己寫好proto文件,然後使用protoc命令生成go語言包,所以,我們首先要裝protoc命令,這個東西我一開始一看還挺恐慌的,想着是不是得編譯安裝啥的,後來發現並不用,直接下載現成的exe文件就完事兒了,這裏直接給出網址 https://github.com/protocolbuffers/protobuf/releases

這個網址打開是這樣的:

可以看到最新版本已經是3.11了,那麼問題來了,一大堆版本,有各種語言的,還有各種系統的,我們要下哪個呢?說實話我也不懂。。。不過既然是要在windows上體驗,就下個win64的吧,最後的成功證明,我的直覺是對的,哈哈。

下下來之後,解壓,然後,直接將bin裏面的exe文件,就是下面這個,拷貝到PATH裏的任一一個路徑下面就行,既然我是爲了用它做go語言的grpc,所以我選擇了把它放在我的GOROOT/bin裏面。

 然後,打開cmd驗證一下,輸入

protoc --version

看到版本號,就說明protoc安裝成功了。

下載grpc包

這塊呢,因爲是普通網絡環境,go get是用不了的,所以我們用git下載grpc的go語言包。

git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc

這裏注意,我們clone下來之後把包放到了$GOPATH/src/google.golang.org/grpc,這是因爲,谷歌只是把程序放在了github一份,但是其他包引用grpc包的時候用的還是google.golang.org/grpc這個路徑。

一般情況下,裝個一個比較大的包會依賴很多其他包,grpc也是如此,但是正常情況下,到這裏我們也不知道它缺啥依賴,所以先不管,最後運行程序的時候根據錯誤提示,缺啥補啥就好了。

體驗1

老實說,第一次自己體驗,到這裏我已經認爲可以了。。。所以直接開始嘗試了。結果是失敗了,但是我覺得沒啥,按網上寫的一通亂裝,都不知道裝的那些東西是幹啥的,倒不如遇到問題了,再看到底是缺了啥,然後再去裝。

言歸正傳,初次體驗,我的目標很簡單,就是跑通grpc包裏提供的helloworld,grpc的官方文檔教的其實也是這個。

首先,在$GOPATH/src/下新建一個工程,就叫goGrpc-test吧。

然後,新建一個helloworld文件夾,在裏面新建一個helloworld.proto文件,把grpc包裏提供的helloworld.proto文件內容拷貝進去,proto文件在這裏:

proto文件內容是這些:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

這個proto文件吧,我以前也沒接觸過,要自己寫肯定是完全不會,不過看這個寫好的其實也能懂大概意思。

  • syntax = "proto3" 這個就是指定proto版本,我們一開始是裝的就是3.11,所以這裏也是proto3
  • option 這幾行我是真的毫無頭緒,這不是go麼,跟java有啥關係。。。
  • package helloworld 這行好理解,就是用protoc命令生成的go代碼的包名,因爲後面寫客戶端服務器程序都要引用這個包,所以就叫helloworld了,也就是跟所在路徑同名
  • service 這塊呢,就是定義了這個遠程調用的服務,服務請求者調用SayHello方法,請求中攜帶HelloRequest格式的信息,服務提供者則返回HelloReply格式的回覆
  • message 這個就是定義請求和回覆的格式,這個例子裏請求和格式都是簡單的string

歐克,這個proto大概理解了,接下來就是生成對應的go語言代碼,這裏終於要用到我們最開始安裝的protoc了,命令如下:

protoc --go_out=plugins=grpc:. helloworld.proto

然鵝,失敗了。。。

這報錯信息說找不到,protoc-gen-go,看這個命令,有一個--go_out,這個應該就是生成go代碼的意思,看來,生成go代碼還需要裝這個protoc-gen-go才行,好吧,退出體驗,繼續裝命令。

安裝protoc-gen-go

看網上的文章,這個又是go get裝的,既然是go-get,都可以通過git clone+go install取代,所以我們首先拉下代碼。

git clone https://github.com/golang/protobuf.git  $GOPATH/src/github.com/golang

注意,這裏我直接把protobuf的go語言包拉了下來,因爲裏面有protoc-gen-go。

接下來就是安裝,安裝其實就是編譯包裏面的文件,生成一個exe文件,然後放到$GOPATH/bin下面,安裝命令如下:

go install github.com/golang/protobuf/protoc-gen-go

go install執行成功不會有什麼安裝成功之類的信息,我們可以直接去$GOPATH/bin下看看有沒有生成對應的exe文件。

看到有這個,那就是裝成功了。

使用protoc生成go語言代碼

剛纔失敗了,說是找不到這個proto-gen-go,現在我們裝上了,可以再試一把了。

這回,沒有報錯,而且成功生成了一個go文件。

打開生成的代碼一看,媽呀,剛纔20行的proto文件,竟然生成了一個兩百多行的go程序,好厲害,不得不說,這些rpc框架確實是很方便,如果沒有這個,這些代碼就要我們手動去寫。

體驗2

行了,go代碼也生成了,接下來我們就可以使用這些生成好的代碼,寫一個客戶端,一個服務器,體驗一下rpc了。

客戶端和服務器的程序呢,我也是用的grpc的helloworld包裏面提供的,爲了模擬這是我自己寫的一個rpc,我又把裏面的內容拷出來放到我自己新建的文件裏了。

首先,自己新建一個client.go,一個server.go。

然後,把grpc包helloword裏的客戶端和服務器程序相應的貼進去。

貼進去之後,改一下,import,改成我們剛剛自己生成的helloworld包。

最終的server.go如下:

package main

import (
	"context"
	"log"
	"net"

	"google.golang.org/grpc"
	pb "goGrpc-test/helloworld"
)

const (
	port = ":50051"
)

// server is used to implement helloworld.GreeterServer.
type server struct {
	pb.UnimplementedGreeterServer
}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.GetName())
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

client.go代碼如下:

package main

import (
	"context"
	"log"
	"os"
	"time"

	"google.golang.org/grpc"
	pb "goGrpc-test/helloworld"
)

const (
	address     = "localhost:50051"
	defaultName = "world"
)

func main() {
	// Set up a connection to the server.
	conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	// Contact the server and print out its response.
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}

到這裏已經忍不住開始激動了,馬上要見證成果了!先把server跑起!

這一大堆錯嚇了我一跳。。。好在定睛一看,只是缺少依賴包而已。。。

安裝grpc依賴包

根據上面的報錯,先把這個golang.org/x/net裝上。

 git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net

 然後再跑一下。

還缺個text和genproto,一口氣裝上:

git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto

體驗3

依賴裝好了,再來!

先服務器跑起。

這回沒報錯,還彈出個windows防火牆,說明開始監聽端口了,嘿嘿。

接下來,客戶端走起,注意這裏客戶端和服務器分別跑在兩個terminal裏。

哈哈,成功了,客戶端收到了來自服務器的回覆,正是我們熟悉的Hello world!

再瞅一眼服務器。

也打印到了接收到的信息,完美!

到這裏,go語言grpc初體驗就算是成功收尾了。

總結

這一趟做下來,也算是對grpc有個基本認識了,總結一下,當我們需要增加一個grpc接口的時候,其實就是以下幾步

  • 修改proto文件,新增一個service,以及相應的請求和回覆的message
  • 使用protoc生成go代碼
  • 在服務器調用者和服務提供者的代碼裏分別調用生成的go包裏的方法

這麼一看,還蠻簡單的,哈哈。

一個小補充

最後還想簡單記錄一個點,之前實習的時候在一次會上聽到的,這個點就是,爲什麼程序不全使用thrift,而是同時使用thrift和grpc?

首先,thrift是Facebook的開源rpc框架,也是一個使用非常廣泛的rpc框架。

那麼grpc和thrift相比優勢在哪裏呢,主要在於,grpc是基於http-2設計的,http-2的一個重要特點是在單個TCP連接上可以複用多個請求,這一點thrift是做不到的,也就是說,thrift的rpc,一次調用在收到回覆之前,是會佔用一個TCP連接的,當併發量很高,而一次調用耗時又很長的時候,thrift會出現連接被佔滿的情況,導致調用堆積,延時增大,而grpc,多個調用可以複用一個連接,這樣顯然就比thrift支持的併發調用數量更高。

如果是同機房調用,調用一次的延時是很低的,這個時候grpc的優勢並不能體現,但如果服務請求者和服務提供者在不同機房,一次通信的延時可能很大,這個時候用grpc就是一個更好的選擇。

grpc的官方文檔有一句是,grpc在移動設備上表現更好,其實也就是上面說的這個道理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章