课程链接:https://www.bilibili.com/video/BV1S24y1U7Xp
gRPC示例链接:https://gitee.com/huangheng179/golang-grpc-example
微服务架构
单体架构
- 一旦某个服务宕机,会引起整个应用不可用,隔离性差
- 只能整体应用进行伸缩,浪费资源,可伸缩性差
- 代码耦合在一起,可维护性差
微服务架构 解决单体架构的弊端,同时引入了新的问题
- 代码冗余
- 服务于服务之间存在调用关系
服务与服务拆分后,服务和服务之间发生的是进程间的调用,服务器间的调用。于是就需要发起网络调用,网络调用我们立马能想起Http,但是在微服务架构中,Http虽然便捷方便,但性能较低,这时候就需要引入RPC(远程过程调用),通过自定义协议发起TCP调用,来加快传输效率。
- HTTP 方便便捷 但是性能较低
- RPC是在TCP协议的基础上,自定义的网络协议,传输效率高,性能更高。
RPC(Remote Procedure Call,远程过程调用)是一种协议,用来屏蔽分布式计算中的各种调用细节,使得你可以像本地调用一样直接调用一个远程函数。gRPC是RPC的一种具体落地方案。
gRPC简介
gRPC是一个高性能、开源的通用的RPC框架。
在gRPC中,调用方称为cilent,被调用方称为server。
gRPC也是基于“服务定义”的思想。“服务定义”简单来说,就是通过某种方式描述一个服务,这种描述方式是与语言无关的。“服务定义“描述了提供的服务名是什么,有哪些方法可以被调用,这些方法有什么样的入参,有什么样的回参。
server在定义好了这些服务、这些方法后,gRPC会屏蔽底层的细节,cilent需要直接调用定义好的方法,就可以拿到预期的返回结果。
所谓的“服务定义”和“接口”的语义是相似的。双方约定好接口,然后在server端实现这个接口,cilent调用这个接口的代理对象。至于其他细节,交给gRPC。
gRPC是语言无关的,可以使用C++作为server,使用Golang、Java等作为cilent。
Protobuf简介
如上图所示,gRPC使用了Protocal Buffss(Protobuf),这是谷歌开源的一套成熟的数据结构序列化机制。
-
序列化:将对象转化为二进制串
-
反序列化:将二进制串转化为对象
Protobuf的优势
- 序列化后体积相比于json和xml更小,适合网络传输
- 支持跨平台多语言
- 消息格式升级和兼容性很好
- 序列化和反序列化速度快
gRPC相关的安装过程
安装Protobuf编译器
- 下载解压, 下载地址:https://github.com/protocolbuffers/protobuf/releases,并配置环境变量
- 输入
protoc
命令查看是否安装成功
安装gRPC的核心库
go get google.golang.org/grpc
安装Protobuf对应golang的代码生成工具protoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go基础之go get和go install
go get
主要用于获取、更新和安装远程依赖包。它会自动从远程代码库(如 GitHub、GitLab)下载依赖包,并将其安装到 GOPATH目录中。当执行go get
命令时,它会下载指定的包及其依赖项,并将其放置在正确的目录结构中,以供项目引用。通常,go get
会自动安装依赖项,无需手动执行go install
。
go install
则用于编译并安装 Go 语言的可执行程序。它将 Go 代码编译成二进制文件,并将其安装到 GOPATH的 bin 目录中,以供后续执行。当执行go install
命令时,它会在当前包的目录中执行编译过程,并将生成的可执行文件放置在 bin 目录中。通过go install
安装的可执行文件可以通过命令行直接运行,无需指定文件路径。
Protobuf的示例
编写Protobuf约束文件
syntax = "proto3";
// option go_package 用于指定生成的 Go 代码应该放在哪个 Go 包(package)中
// .:这表示生成的 Go 代码应该位于与 .proto 文件相同的目录中(即当前目录)。如果你想要生成的代码位于不同的目录中,你可以指定一个相对路径或绝对路径。
// service:这是 Go 包的名字。当 protoc 编译器生成 Go 代码时,它会在生成的 .pb.go 文件的顶部使用 package service 这一行来声明包名。
option go_package = ".;service";
service SayHello{
rpc SayHello(HelloRequest) returns (HelloResponse){}
}
// 注意 变量后的等于号是用于定义这个变量在message中的位置,而不是赋值。
message HelloRequest{
string requestName = 1;
}
message HelloResponse{
string responseMsg = 1;
}
根据Protobuf约束文件生成*.pb.go
和*_grpc.pb.go
文件
protoc --go_out=. hello.proto # 生成go相关文件
# 这条命令用于生成与 hello.proto 文件相关的 Go 结构体、枚举等。具体来说,它会读取 hello.proto 文件,并基于其中的消息定义(message)、服务定义(service)等生成相应的 Go 代码。这些生成的 Go 代码通常包含用于序列化和反序列化 Protocol Buffers 数据的函数和方法。
protoc --go-grpc_out=. hello.proto # 生成rpc相关文件
# 这条命令用于生成与 gRPC 相关的 Go 代码。它读取 hello.proto 文件中的服务定义,并生成实现 gRPC 客户端和服务器所需的 Go 接口和辅助函数。这包括客户端和服务器的桩(stubs)代码,用于进行 RPC 调用和响应。
Protobuf语法介绍
消息定义
message关键字
message: protobuf中定义一个消息类型式是通过关键字 message字段指定的。消息就是需要传输的数据格式的定义
message关键字类似于C++中的class, JAVA中的class, go中的struct
在消息中承载的数据分别对应于每一个字段,其中每个字段都有一个名字和一种类型
proto文件中可以定义多个消息类型
字段规则
required:消息体中必填字段,不设置会导致编码异常。在protobuf2中使用,在protobuf3中被删去
optional:消息体中可选字段。protobuf3没有了required、optional说明关键字,都默认为optional。
repeated:消息体中可重复字段,重复的值的顺序会被保留在go中重复的会被定义为切片。
消息号
在消息体的定义中,每个字段都必须要有一个唯一的标识号,标识号是[1,2^29-1]范围内的一个整数
嵌套消息
可以在其他消息类型中定义、使用消息类型,在下面的例子中,Person消息就定义在Personinfo消息内如
message PersonInfo{
message Person{
string name = 1;
int32 height = 2;
repeated int32 weight = 3;
}
repeated Person info = 1;
}
如果要在它的父消息类型的外部重用这个消息类型,需要Personlnfo.Person的形式使用它,如:
message PersonMessage{
PersonInfo.Person info = 1;
}
服务定义
可以使用service
关键词定义一个RPC服务接口。
service SearchService {
rpc Search1(SearchRequest) returns (SearchResponse);
rpc Search2(SearchRequest) returns (SearchResponse);
}
golang-gRPC示例
一个包含客户端代码、服务端代码和Protobuf文件的完整实例:https://gitee.com/huangheng179/golang-grpc-example
go基础之package和module
package
(包)是Go语言中的基础组织单位,它用于组成代码结构和解决命名隔离问题。每个包都由一系列相关的Go代码文件构成,这些文件在文件系统上位于同一个目录下。包是代码模块化和代码复用的关键,通过包,开发者可以将相关的函数、类型、变量等组织在一起,并通过包名来访问它们。此外,Go语言提供了很多内置包,如fmt
,同时开发者也可以根据自己的需要创建自定义包。在Go语言中,包是import的单位,import语句写在每个Go源码文件的开头。
module
(模块)是一个集合了许多包的更大单位,它主要解决的问题是版本控制和包分发。一个模块可以包含一个或多个包,并且每个模块都有一个明确的版本。模块是源代码更替和版本控制的单元,它使得开发者能够更方便地管理项目的依赖关系。在Go 1.11及以后的版本中,引入了模块支持,通过go mod
命令来管理项目的依赖和包。模块是require的单位,require语句写在go.mod
文件中。
服务端代码
-
创建gRPC Server对象grpcServer
-
将服务注册到gRPC Server的内部注册中心
这样可以在接收到请求时,通过内部的服务发现,发现该服务端接口并转接进行逻辑处理
-
创建Listen,监听TCP端口
-
grpcServer开始lis.Accept,直到Stop
客户端代码
- 创建与给定目标(服务端)的连接交互
- 创建客户端对象
- 发送RPC请求,等待同步响应,得到回调后返回响应结果
- 输出响应结果
gRPC的认证-安全传输
- SSL/TLS认证方式(采用http2协议)
- 基于Token的认证方式(基于安全连接)
- 自定义的身份认证
- 不采用任何措施的连接,这是不安全的连接(默认采用http1)