grpc简介
gRPC由google开发,是一款语言中立、平台中立、开源的远程过程调用系统,gRPC客户端和服务端可以在多种环境中运行和交互,例如用java写一个服务端,可以用go语言写客户端调用
微服务架构中,由于每个服务对应的代码库是独立运行的,无法直接调用,彼此间的通信就是个大问题
gRPC可以实现微服务,将大的项目拆分为多个小且独立的业务模块,也就是服务,各服务间使用高效的protobuf协议进行RPC调用,gRPC默认使用protocol buffers,这是google开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如JSON)。
可以用proto files创建gRPC服务,用message类型来定义方法参数和返回类型。
数据在进行网络传输的时候,是需要进行序列化的,序列化的协议有很多中,比如xml,json,protobuf等,gRpc默认使用的是protocol buffers,是google开源的一套成熟的结构数据序列化机制。
所谓序列化,将数据结构转换为二进制串的过程,反序列化,将序列化过程中所产生的二进制串转换为数据结构或者对象的过程。
protobuf
protobuf是谷歌开源的一种数据格式,适合高性能,对响应速度有要求的传输场景。因为它是二进制数据格式,需要编码和解码,数据本身没有可读性,因此只能反序列化后得到真正的可读数据。
优势:
- 序列化后体积比json和xml小,适合网络传输
- 支持跨平台多语言
- 消息格式升级和兼容性不错
- 序列化和反序列化速度很快
下载安装
https://github.com/protocolbuffers/protobuf/releases 下载地址
最新版本为22.2
#配置环境变量
mv protoc-22.2-linux-x86_64 protoc
mv protoc /usr/local/
vim /etc/profile
#按照如下添加
#:/usr/local/protoc/bin
source /etc/profile
配置完成后,直接启动
安装go专用的protoc生成器
go get github.com/golang/protobuf/protoc-gen-go #该库已经弃用
安装完成后,会在gopath目录下生成可执行文件,protobuf的编译器插件protoc-gen-go,执行protoc命令会指定调用这个插件。
在执行的时候,会报错,提示找不到执路径
protoc-gen-go: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
--go_out: protoc-gen-go: Plugin failed with status code 1
此时按照如下方法解决
找到protoc-gen-go 文件,执行以下命令,该文件通过go get安装时会安装在$GOPATH/go/bin目录下
cp protoc-gen-go /usr/local/bin/然后vim ~/.bash_profile
export GOPATH=$HOME/go PATH=$PATH:$GOPATH/bin
使用protobuf:
- 定义一种源文件,扩展名为.proto,使用这种源文件,可以定义存储类的内容
- protobuf有自己的编译器protoc,可以将.proto编译成对应语言的文件,就可以使用了
编写helloworld示例
编写一个protobuf
场景,需要传输用户信息,其中有username和age两个字段
//user.proto
//定义当前proto语法的版本,有2和3,
syntax="proto3";
//option go_package="path;name" path表示生成的go文件存放的地址,会自动生成
//name表示生成的go文件所属的包名
option go_package="./service";
//指定等会文件生成出来的package
package service;
//消息传输对象
message User{
string username=1;
int32 age=2;
}
转换
完成后使用命令转换
protoc --go_out=./ user.proto
此时就会创建以后个service/user.pb.go
调用方法
package main
import (
"demo1/service"
"fmt"
"github.com/golang/protobuf/proto"
)
func main() {
user := &service.User{
Username: "yangchao",
Age: 18,
}
//序列化
marshal, err := proto.Marshal(user)
if err != nil {
panic(err)
}
//反序列化
newUser := &service.User{}
err = proto.Unmarshal(marshal, newUser)
if err != nil {
panic(err)
}
fmt.Println(newUser.Username, newUser.Age)
}