grpc学习笔记 | 青训营
1.概述
单体架构存在的问题:
1、—旦某个服务宕机,会引起整个应用不可用,隔离性差
2、只能整体应用进行伸缩,浪费资源,可伸缩性差
3、代码耦合在一起,可维护性差
微服务架构:解决了单体架构的弊端但同时引入了新的问题
1、代码冗余
2、服务和服务之间存在调用关系
服务拆分后,服务和服务之间发生的是进程和进程之间的调用,服务器和服务器之间的调用。
那么就需要发起网络调用,网络调用我们能立马想起的就是http,但是在微服务架构中,http虽然便捷方便,但性能较低,这时候就需要引入RPC(远程过程调用),通过自定义协议发起TCP调用,来加快传输效率。
2.安装命令
go get 谷歌.golang.org/grpc
go install 谷歌.golang.org/protobuf/cmd/protoc-gen-go@latest
go install 谷歌.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
3.编写proto文件:
// 这里是说明使用的是proto3语法
syntax = "proto3";
// 说明最后生成的go文件是处在哪个目录哪个包中,. 代表当前目录生成,service代表了生成的go文件的包名是 service (两个参数之间用 ; 隔开)
option go_package = ".;service";
//然后我们定义一个服务,在这个服务中需要一个方法,这个方法可以接受客户端的参数,再返回服务端的响应。
//其实很容易看出,我们定义了一个service,称为SayHello,这个服务中有一个 rpc 方法,名为SayHello
//这个方法会发送一个HelloRequest,然后返回一个HelloResponse
service SayHello{
rpc SayHello(HelloRequest) returns (HelloResponse) {}
}
//message 关键字,其实你可以理解为Golang中的结构体,
// 这里比较特别的是变量后面的“赋值”,注意:这里不是赋值,而是在定义这个变量在这个message中的位置
message HelloRequest {
string requestName = 1;
// int64 age = 2;
}
message HelloResponse {
string requestMsg = 1;
}
执行命令:
protoc --go_out=. hello.proto // . 表示生成的文件在当前目录 , 第二个参数表示对哪个文件进行生成
protoc --go-grpc_out=. hello.proto
使用grpc的话,就是后续运用protoc --go-grpc_out=. hello.proto
命令生成的文件,填充里面的具体业务逻辑内容即可。
proto文件:
message
message:protobuf 中定义一个消息类型是通过关键字message字段指定的,消息就是需要传输的数据格式定义
message 关键字类似 go 语言中的struct结构体。
在消息中承载的数据分别对应每一个字段,==其中每一个字段都有一个名字和一种类型==。
一个proto 文件中可以定义多个消息类型。
字段规则
required: 消息体中必填字段,不设置会导致编码异常,在protobuf2中使用,protobuf3中删除
optional:消息体中**==可选字段==**,protobuf3中默认都是optional,没有其他说明关键字
repeate: 消息体中可重复字段,==重复的值的顺序会被保留,在go中重复的会被定义为切片。==
消息号
在消息体的定义中,==每个字段都必须有一个唯一的标识号==,标识号是 [1,2^29 -1] 范围内的一个**==整数==**。
嵌套消息
可以在其他消息类型中定义、使用消息类型、在下面的例子中,person 消息就定义在Personinfo 消息内如:
message PersonInfo{
message Person{
string name = 1;
int32 age = 2;
repeated int32 weight = 3;
}
repeated Person info = 1;
}
如果要在它的父消息类型的外部重用这个消息类型,需要PersonInfo.Person的形式使用它,如:
message PersonMessage{
PersonInfo.Person info = 1;
}
服务定义
如果想要将消息类型用在gRPC系统中,可以在一个**==.proto文件中定义一个 RPC 服务接口==**,protocol buffer 编译器将会根据所选择的不同语言生成服务接口代码及存跟。
service SearchService{
// rpc 服务函数名(参数) 返回 (返回参数)
rpc Search(SearchRequest) returns (SearchResponse) {}
}
上述代表表示,定义一个RPC服务,该方法接受参数是:SearchRequest,返回参数是:SearchResponse
4.服务端编写
- 创建 gRPC Server 对象,你可以理解为它是 Server 端的抽象对象
- 将 Server (其包含需要被调用的服务端接口)注册到 gRPC Server 的内部注册中心;这样可以在接受到请求时,通过内部的服务发现,发现该服务端接口并转接进行逻辑处理;
- 创建 Listen , 监听 TCP 端口
- gRPC Server 开始 lis.Accept ,直到 Stop
5.客户端编写
- 创建与给定目标(服务端)的连接交互
- 创建 server 的客户端对象
- 发送 RPC 请求,等待同步响应,得到回调后返回响应结果
- 输出响应结果
6.认证 - 安全传输
gRPC 是一个典型的 C/S 模型,需要开发客客户端 和 服务端,客户端 和 服务端需要达成协议,使用某一个确认的传输协议来传输数据,gPRC 通常默认使用protobuf 来作为传输协议,当然也可以使用其他自定义的。
那么,客户端 与 服务端进行通信之前,客户端如何知道自己的数据发送给哪一个明确的服务端呢?反过来,服务端是不是也需要有一种方式来弄清楚自己的数据发送给谁呢?
那么就不得不提到 gRPC 的认证:(此处的认证,不是用户的认证,而是指多个 server 和多个 client 之间,如何识别对方是谁,并且可以安全的进行数据传输)
- SSL/TLS认证方式(采用HTTP2协议)
- 基于
Tocken
的认证方式(基于安全连接) - 不采用任何措施的连接,这不是安全的连接(默认采用HTTP1)
- 自定义的身份认证
客户端 和 服务端之间调用,我们可以通过加入证书的方式,实现调用的安全性。
TLS(Transport Layer Security,安全传输层),TLS是建立在传输层 TCP 协议 上的协议,服务于应用层,它的前身是 SSL (Secure Socket Layer ,安全套接字层),它实现了将**==应用层的报文==**进行加密后再交由 TCP 进行传输的功能。
TLS 协议主要解决以下三个网络安全问题:
- 保密:保密通过加密
encryption
实现,所有信息都加密传输,第三方无法嗅探 - 完整性:通过 MAC 校验机制,一旦被篡改,通信双方立刻发现
- 认证:双方认证,双方都可以配备证书,防止身份泄漏
生产环境可以购买证书或者使用一些平台发放的免费证书
- key:服务器上的私钥文件,用于发送给客户端数据的加密,以及对从客户端接收到数据的解密
- csr:证书签名请求文件,用于提交给证书颁发机构(CA)对证书签名。
- crt:由证书颁发机构(CA) 签名后的证书,或者是开发者自签名的证书,包含证书持有人的信息,持有人的公钥,以及签署者的签名等信息
- pem:是基于Base64 编码的证书格式,扩展名包括 PEM、CRT和CER
一些名词解释:聊聊 HTTPS、和SSL/TLS 协议 -- 狂神
SSL/TLS 认证方式
首先通过 openssl
生成证书和私钥
- 官网下载:www.openssl.org/source/
- 其他人做的便捷版安装包:slproweb.com/products/Wi…
- 我们使用
便捷版安装包
,一直下一步即可 - 配置环境变量
- 命令行测试
openssl
生成证书
# 1. 生成私钥
openssl genrsa -out server.key 2048
# 2. 生成证书 全部回车即可、可以不填
openssl req -new -x509 -key server.key -out server.crt -days 36500
# 国家代码,2位,中国CN
Country Name (2 letter code) [AU]:CN
# 机构所在省份
State or Province Name (full name) [Some-State]:ShangHai
# 机构所在城市
Locality Name (eg, city) [Default City]:ShangHai
# 机构名称
Organization Name (eg, company) [Default Company Ltd]:TEST COMPANY
# 机构部门
Organizational Unit Name (eg, section) []:R&D center
# 机构域名 或 服务域名
Common Name (eg, your name or your server's hostname) []:www.qiyu319.com
# 邮箱
Email Address []:123467890@123.com
# 3. 生成csr
openssl req -new -key server.key -out server.csr
#更改openssl.cnf (Linux 是 openssl.cfg)**
1. 复制一份你安装的 openssl 的 bin 目录里面的 openssl.cnf 文件到你项目所在的目录
2. 找到`[ CA_default ]`,打开 copy_extensions = copy(就是把前面的#去掉)
3. 找到`[ req ]`,打开 req_extensions = v3_req # The extensions to add to a certificate request
4. 找到`[ v3_req ]`,添加subjectAltName = @alt_names
5. 添加新的标签[ alt_names ],和标签字段
DNS.1 = *.kuangstudy.com # 通过指定域名访问网站
# 生成证书私钥 test.key
openssl genpkey -algorithm RSA -out test.key
# 通过私钥test.key 生成证书请求文件test.csr(注意cfg和cnf)
openssl req -new -nodes -key test.key -out test.csr -days 3650 -subj "/C=cn/OU=myorg/O=mycomp/CN=myname" -config ./openssl.cfg -extensions v3_req
#test.csr 是上面生成的证书请求文件,ca.crt/server.key 是CA 证书文件和key,用来对test.csr 进行签名认证,这两个文件在第一部分生成
#生成 SAN 证书 pem
openssl x509 -req -days 365 -in test.csr -out test.pem -CA server.crt -CAkey server.key -CAcreateserial -extfile ./openssl.cfg -extensions v3_req
Tocken认证
我们先看一个gRPC
提供我们的一个接口,这个接口中有两个方法,接口位于credentials
包下,这个接口需要客户端来实现
type PerRPCCredentials interface {
GetRequestMetadata(ctx context.Context,uri ...string) (map[string]string,error)
RequireTransportSecurity() bool
}
第一个方法作用是:获取元数据信息,也就是客户端提供的key,value对,context用于控制超时和取消,uri是请求入口处的uri
第二个方法的作用是:是否需要基于TLS认证进行安全传输,如果返回值是true,则必须加上TLS验证,返回值是false则不用。
自定义Tocken
认证的代码
//客户端代码
type ClientTokenAuth struct{}
// GetRequestMetadata 客户端发送请求时,所携带的元信息
func (c ClientTokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"appid": "kuangshen",
"appkey": "123123",
}, nil
}
// RequireTransportSecurity 如果使用安全认证,就返回True,否则返回false
func (c ClientTokenAuth) RequireTransportSecurity() bool {
return true
}
在main函数中,配置客户端请求参数
//配置请求参数
var opts []grpc.DialOption
//添加安全认证 (如果不需要安全连接的话,就添加grpc.WithTransportCredentials(insecure.NewCredentials()))
opts = append(opts, grpc.WithTransportCredentials(creds))
//添加自己的Tocken认证,传入自己的一个认证的对象
opts = append(opts, grpc.WithPerRPCCredentials(new(ClientTokenAuth)))
//1.连接到server 端,将上面配置的opts参数传入
conn, err := grpc.Dial("127.0.0.1:9090", opts...)
==客户端配置完成==
==服务端==对客户端传来的元数据信息进行校验,进而完成具体的业务逻辑的实现
// 服务端代码
// SayHello 具体的业务处理代码
func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
//获取客户端传来的元数据信息
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, errors.New("未传输tocken")
}
//传输成功,获取传过来的数据
var appID, appkey string
if v, ok := md["appid"]; ok {
appID = v[0]
}
if v, ok := md["appkey"]; ok {
appkey = v[0]
}
if appID != "kuangshen" || appkey != "123123" {
return nil, errors.New("请求的元数据错误,tocken 不正确")
}
fmt.Println("正在调用服务端的SayHello方法")
return &pb.HelloResponse{RequestMsg: "hello" req.RequestName}, nil
}
==总结==
gRPC将各种认证方式浓缩统一到一个凭证(credentials)上,可以单独使用一种凭证,比如只使用TLS凭证或者只使用自定义凭证,也可以多种凭证组合,gRPC提供统一的API验证机制,使研发人员使用方便,这也是gRPC设计的巧妙之处
参考资料
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgbbkeg
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01