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

这个网址打开是这样的:

go gRPC初体验(win10+普通网络)_第1张图片

可以看到最新版本已经是3.11了,那么问题来了,一大堆版本,有各种语言的,还有各种系统的,我们要下哪个呢?说实话我也不懂。。。不过既然是要在windows上体验,就下个win64的吧,最后的成功证明,我的直觉是对的,哈哈。

go gRPC初体验(win10+普通网络)_第2张图片

下下来之后,解压,然后,直接将bin里面的exe文件,就是下面这个,拷贝到PATH里的任一一个路径下面就行,既然我是为了用它做go语言的grpc,所以我选择了把它放在我的GOROOT/bin里面。

go gRPC初体验(win10+普通网络)_第3张图片

 然后,打开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文件在这里:

go gRPC初体验(win10+普通网络)_第4张图片

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

注意,这里我直接把protobuf的go语言包拉了下来,因为里面有protoc-gen-go。

go gRPC初体验(win10+普通网络)_第5张图片

接下来就是安装,安装其实就是编译包里面的文件,生成一个exe文件,然后放到$GOPATH/bin下面,安装命令如下:

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

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

2020.4.18补充:今天,一个同学按照我的blog装protoc-gen-go的时候,报了这个错:

go gRPC初体验(win10+普通网络)_第6张图片

按照这个错误,我打开我的github.com\golang\protobuf\protoc-gen-go\main.go瞅了一眼,发现28行并没有import它说找不到的这个包,后来发现,golang/protobuf这个仓库在2020.4.13提交过一次:

这次提交修改了main.go的内容,修改之后该怎么安装protoc-gen-go我还没有研究,不过经过试验,把版本回退到我clone的时候那个版本之后再go install是欧克的,所以如果你想先凑合用的话,就先把protobuf回退到这个版本,再go install。

git reset --hard d23c5127

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

go install执行成功不会有什么安装成功之类的信息,我们可以直接去$GOPATH/bin下看看有没有生成对应的exe文件。

看到有这个,那就是装成功了。

使用protoc生成go语言代码

刚才失败了,说是找不到这个proto-gen-go,现在我们装上了,可以再试一把了。

这回,没有报错,而且成功生成了一个go文件。

go gRPC初体验(win10+普通网络)_第7张图片

打开生成的代码一看,妈呀,刚才20行的proto文件,竟然生成了一个两百多行的go程序,好厉害,不得不说,这些rpc框架确实是很方便,如果没有这个,这些代码就要我们手动去写。

体验2

行了,go代码也生成了,接下来我们就可以使用这些生成好的代码,写一个客户端,一个服务器,体验一下rpc了。

客户端和服务器的程序呢,我也是用的grpc的helloworld包里面提供的,为了模拟这是我自己写的一个rpc,我又把里面的内容拷出来放到我自己新建的文件里了。

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

go gRPC初体验(win10+普通网络)_第8张图片

然后,把grpc包helloword里的客户端和服务器程序相应的贴进去。

go gRPC初体验(win10+普通网络)_第9张图片

贴进去之后,改一下,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跑起!

go gRPC初体验(win10+普通网络)_第10张图片

这一大堆错吓了我一跳。。。好在定睛一看,只是缺少依赖包而已。。。

安装grpc依赖包

根据上面的报错,先把这个golang.org/x/net装上。

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

 然后再跑一下。

go gRPC初体验(win10+普通网络)_第11张图片

还缺个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里。

go gRPC初体验(win10+普通网络)_第12张图片

哈哈,成功了,客户端收到了来自服务器的回复,正是我们熟悉的Hello world!

再瞅一眼服务器。

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

到这里,go语言grpc初体验就算是成功收尾了。

总结

这一趟做下来,也算是对grpc有个基本认识了,总结一下,当我们需要增加一个grpc接口的时候,其实就是以下几步

  • 修改proto文件,新增一个service,以及相应的请求和回复的message
  • 使用protoc生成go代码
  • 在服务器调用者和服务提供者的代码里分别调用生成的go包里的方法

这么一看,还蛮简单的,哈哈。

一个小补充

最后还想简单记录一个点,之前实习的时候在一次会上听到的,这个点就是,为什么程序不全使用thrift,而是同时使用thrift和grpc?

首先,thrift是Facebook的开源rpc框架,也是一个使用非常广泛的rpc框架(这个我也体验了一把,感兴趣的看这里go Thrift初体验(win10+普通网络))。

那么grpc和thrift相比优势在哪里呢,主要在于,grpc是基于http-2设计的,http-2的一个重要特点是在单个TCP连接上可以复用多个请求,这一点thrift是做不到的,也就是说,thrift的rpc,一次调用在收到回复之前,是会占用一个TCP连接的,当并发量很高,而一次调用耗时又很长的时候,thrift会出现连接被占满的情况,导致调用堆积,延时增大,而grpc,多个调用可以复用一个连接,这样显然就比thrift支持的并发调用数量更高。

如果是同机房调用,调用一次的延时是很低的,这个时候grpc的优势并不能体现,但如果服务请求者和服务提供者在不同机房,一次通信的延时可能很大,这个时候用grpc就是一个更好的选择。

grpc的官方文档有一句是,grpc在移动设备上表现更好,其实也就是上面说的这个道理。

你可能感兴趣的:(go,rpc)