Grpc介紹 — ProToBuf基本使用

RPC(Remote Procedure Call)遠程過程調用,關注筆者的同窗應該知道以前筆者出過關於Thrift對應的問題,此次主要來講的是Google開源的Grpc,和Thrift有很大的區別Grpc是基於HTTP2.0而且依賴protobuf,爲何又推出關於grpc的文章呢?請你們繼續往下看。php

附上:html

喵了個咪的博客:w-blog.cnjava

博文實例demo:GitHub - sunmi-OS/grpc-php-to-golang-demogit

grpc官網:grpc / grpc.iogithub

protobuf代碼倉庫:Releases · protocolbuffers/protobuf · GitHubgolang

一,爲何要用grpc它的優點是什麼

一個高性能、通用的開源RPC框架,其由Google主要面向移動應用開發並基於HTTP/2協議標準而設計,基於ProtoBuf(Protocol Buffers)序列化協議開發,且支持衆多開發語言。 gRPC基於HTTP/2標準設計,帶來諸如雙向流控、頭部壓縮、單TCP鏈接上的多複用請求等特性。這些特性使得其在移動設備上表現更好,更省電和節省空間佔用。vim

性能 Grpc PK Thrift 借鑑:開源RPC(gRPC/Thrift)框架性能評測 - 滄海一滴 - 博客園框架

PS:筆者也作了對應的性能測試,後面的文章會附上詳細步驟,經過這個現有的結果一個簡單的結論tcp

從壓測的結果商米咱們能夠獲得如下重要結論:ide

  • 總體上看,長鏈接性能優於短鏈接,性能差距在兩倍以上;
  • 對比Go語言的兩個RPC框架,Thrift性能明顯優於gRPC,性能差距也在兩倍以上;
  • 對比Thrift框架下的的兩種語言,長鏈接下Go 與C++的RPC性能基本在同一個量級,在短鏈接下,Go性能大概是C++的二倍;
  • 兩套RPC框架,以及兩大語言運行都很是穩定,5w次請求耗時約是1w次的5倍;

這裏主要要回答的一個問題是既然已經用thrift而且性能仍是grpc的2倍爲何還要用grpc呢?

這裏主要要說到兩個Go的微服務框架,go-kit和istio

  • go-kit 支持thrift可是在thrift的狀況下不支持鏈路追蹤
  • istio由於是無侵入式連thrift也不支持

主要的致使這個問題的緣由在於thrift的傳輸方式是經過TCP的方式傳輸,對於這些框架想在傳輸過程當中加入些鏈路的ID是沒法實現的,istio連對於thrift的請求次數感知都作不到,對於grpc由於是基於http2在harder頭上能夠作不少補充參數,對於這類微服務框架很是友好。


二,安裝protobuf

安裝protobuf爲了生成對應語言的文件必須須要protoc的命名,protoc是c語言的protobuf的命名,有兩種訪問一個是本身編譯:

wget https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protobuf-cpp-3.6.1.tar.gz
> tar -zxvf protobuf-cpp-3.6.1.tar.gz
> cd protobuf-3.6.1
> ./configure
> make
> make install
> protoc --version
libprotoc 3.6.1

或者根據更具系統直接使用編譯好的bin文件運行protoc(這裏使用的是MAC OSX系統)

wget https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protoc-3.6.1-osx-x86_64.zip
> tar -zxvf protoc-3.6.1-osx-x86_64.zip
> cd protoc-3.6.1-osx-x86_6/bin
> ./protoc --version
> libprotoc 3.6.1

安裝好了咱們就要來運行下測試程序了


三,Golang 環境準備

不得不說Go是Google的親兒子,天然Grpc的支持不會差依賴只須要一個命令就能夠(這裏使用的是go 1.11版本):

> go get google.golang.org/grpc

若是你們報錯,緣由是這個代碼已經轉移到github上面了,可是代碼裏面的包依賴仍是沒有修改,仍是google.golang.org這種,因此有的不能使用go get的方式安裝,可使用如下安裝方式:

> git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
> git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net
> git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
> git clone https://github.com/golang/sys.git $GOPATH/src/golang.org/x/sys
> go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
> git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto
> cd $GOPATH/src/
> go install google.golang.org/grpc

先使用筆者的準備好的:

> cd $GOPATH/src
> mkdir -p grpc-php-to-golang-demo/protobuf
> cd grpc-php-to-golang-demo/protobuf
> vim helloworld.proto

文件內容以下:

syntax = "proto3";

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

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;
}

生成對應的文件:

> mkdir -p go-server/helloworld
> protoc --go_out=plugins=grpc:./go-server/helloworld ./helloworld.proto
> cd go-server/helloworld/
> ll
total 16
drwxr-xr-x  3 wenzhenxi  staff    96  2 15 14:24 ./
drwxr-xr-x  3 wenzhenxi  staff    96  2 15 14:23 ../
-rw-r--r--  1 wenzhenxi  staff  6915  2 15 14:24 helloworld.pb.go

編寫服務端和客戶端Go程序:

> cd $GOPATH/src/grpc-php-to-golang-demo
> mkdir -p golang/holleworld
> cd golang/holleworld

服務端:

> vim server.go 

package main

import (
	"log"
	"net"

	pb "grpc-php-to-golang-demo/protobuf/go-server/helloworld"

	"google.golang.org/grpc"
	"golang.org/x/net/context"
	"google.golang.org/grpc/reflection"
)

const (
	port = ":50051"
)

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

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	return &pb.HelloReply{Message: "Hello " + in.Name}, 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{})
	// Register reflection service on gRPC server.
	reflection.Register(s)
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

客戶端:

> vim client.go

package main

import (
	"log"
	"os"
	"time"

	pb "grpc-php-to-golang-demo/protobuf/go-server/helloworld"

	"google.golang.org/grpc"
	"golang.org/x/net/context"
)

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

func main() {
	// Set up a connection to the server.
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	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]
	}

	go func() {
		r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
		if err != nil {
			log.Fatalf("could not greet: %v", err)
		}
		log.Printf("Greeting: %s", r.Message)
	}()

	time.Sleep(10 * time.Second)

}

運行測試:

> go build server.go
> go build client.go
./server
./client
2019/02/15 14:35:35 Greeting: Hello world

此時在go to go的場景就調用通了

最終產物能夠參考demoGitHub - sunmi-OS/grpc-php-to-golang-demo

相關文章
相關標籤/搜索