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"

测试代码编写

  1. 创建一个项目文件夹grpc,并且创建3个子文件夹,分别作为服务端、客户端以及proto文件存放
go mod init grpc
mkdir server client protoc
  1. 在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

  1. 使用protoc编译器自动生成go的grpc代码
protoc --go_out=. --go_opt=paths=source_relative     --go-grpc_out=. --go-grpc_opt=paths=source_relative     protoc/test.proto
  1. 在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)
	}
}
  1. 在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())

}
  1. 启动服务端
go run server/main.go
  1. 启动客户端
go run client/main.go
  1. 验证客户端输出
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