gRPC go版本的初体验
概述
本文通过一个简单的初始教程,带领大家初步体验下gRPC框架。
什么是RPC
简单来说,RPC就是要像调用本地的函数一样去调远程函数,实现分布式调用,系统服务水平能力扩展。
gRPC是什么
- gRPC是一个由google开源的高性能的分布式调用框架,支持跨语言进行RPC调用,同时也是一个CNCF孵化项目。官方的网址为:https://grpc.io
- gRPC是一个现代开源高性能远程过程调用(RPC)框架,可以在任何环境中运行。它可以高效地连接数据中心内和数据中心之间的服务,并可插拔支持负载平衡、跟踪、运行状况检查和身份验证。它也适用于最后一英里的分布式计算,用于将设备、移动应用程序和浏览器连接到后端服务。
gRPC的优势
- 提供高效的进程间通信
- 具有简单且定义良好的服务接口和模式
- 属于强类型调用
- 支持多语言
- 支持双工通信
- 大厂背书社区活跃
gRPC的劣势
- gRPC不太适合面向外部的服务
- 巨大的服务定义变更是复杂的开发流程
- gRPC生态系统较小
快速开始
前提
环境介绍
本文的环境采用的是arm版本的centos7的容器进行测试,所以安装的软件均为arm版本的。
提示有些包可能需要科学上网才能下载到。
安装golang
curl -O https://dl.google.com/go/go1.19.4.linux-arm64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.19.4.linux-arm64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version
安装Protocol Buffer编译器
yum install -y wget unzip
wget https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-aarch_64.zip
unzip protoc-21.12-linux-aarch_64.zip -d /usr/local/
安装Go插件,并设置PATH环境变量
go env -w GOPROXY="https://goproxy.cn,direct"
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
export PATH="$PATH:$(go env GOPATH)/bin"
测试代码编写
- 创建一个项目文件夹grpc,并且创建3个子文件夹,分别作为服务端、客户端以及proto文件存放
go mod init grpc
mkdir server client protoc
- 在protoc中创建test.proto文件
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
option go_package = "grpc/protoc";
package protoc;
// The greeting service definition.
service MySvc {
rpc Myfunc (MyRequest) returns (MyReply) {}
}
// The request message containing the user's name.
message MyRequest {
string name = 1;
}
// The response message containing the greetings
message MyReply {
string result = 1;
}
这里采用的是proto buffer 版本为3,具体到语法规则可以参考官方网址:
https://developers.google.com/protocol-buffers/docs/proto3
- 使用protoc编译器自动生成go的grpc代码
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative protoc/test.proto
- 在server文件夹中创建服务端main.go代码
package main
import (
"context"
"google.golang.org/grpc"
"log"
"net"
pb "grpc/protoc"
)
type mysrv struct {
pb.UnsafeMySvcServer
}
func (m *mysrv) Myfunc(ctx context.Context, in *pb.MyRequest) (*pb.MyReply, error) {
return &pb.MyReply{Result: "my:" + in.GetName()}, nil
}
func main() {
l, err := net.Listen("tcp", "127.0.0.1:8877")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterMySvcServer(s, &mysrv{})
log.Printf("server listening at %v", l.Addr())
if err := s.Serve(l); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
- 在client文件夹中创建客户端main.go代码
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"log"
pb "grpc/protoc"
)
func main() {
conn, err := grpc.Dial("localhost:8877", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
m := pb.NewMySvcClient(conn)
res, err := m.Myfunc(context.Background(), &pb.MyRequest{Name: "hello"})
if err != nil {
log.Printf("err:%v", err)
}
log.Printf("res:%v", res.GetResult())
}
- 启动服务端
go run server/main.go
- 启动客户端
go run client/main.go
- 验证客户端输出
2022/12/25 09:02:24 res:my:hello
可以看到本地的客户端可以调用到远程到服务端到方法,并返回正确的结果。
体验总结
- 在大型的业务系统中,常常会使用分布式,微服务的方式来为整个系统提供服务,这些分布式、微服务部署在千差万别的网络中,不像原先的集中式,都在同一个代码仓库中,可以直接通过包的引用来调用,而且各个服务的写的语言又不一致,这就需要有一种标准来进行规范。
- 或许有人说,现在面向接口,restful风格的开发,也是可以实现的,没错,但是效率低下,无法像本地一样来进行调用。gRPC通过proto buffer数据规范来进行数据传输,效率更快,调用远程的函数犹如在本地调用一样,可以跨语言进行调用多个服务器,多种语言只需要满足一个proto文件规范,即可由protoc编译器和插件来自动为你生成对应语言的接口代码,开发者只需要实现该类的开发即可,只需要关注业务逻辑开发,不需要关注底层的通讯过程,大大提高了编程效率。
- 由于gRPC的调用需要在代码级别,不可以使用类似http/socket等来直接调用,所以gRPC是适用于面向内部的服务,不太合适面向外部服务,面向外部服务通常使用webservice/http/sock等协议。
- gRPC需要专业的系统规划设计师来对系统的整体接口进行把握和设计,才能发挥出gRPC的优势,实现分布式开发,各司其职,提高整体的编程效率。
- 如果说resetful风格的api调用,实现了前后端分离开发,那么gRPC就实现了后端多个服务组建的分布式开发,提高了后台编程效率。s