gRPC之gRPC服务超时设置

编程入门 行业动态 更新时间:2024-10-15 18:26:56

<a href=https://www.elefans.com/category/jswz/34/1761953.html style=gRPC之gRPC服务超时设置"/>

gRPC之gRPC服务超时设置

1、gRPC服务超时设置

gRPC默认的请求的超时时间是很长的,当你没有设置请求超时时间时,所有在运行的请求都占用大量资源且可能

运行很长的时间,导致服务资源损耗过高,使得后来的请求响应过慢,甚至会引起整个进程崩溃。

为了避免这种情况,我们的服务应该设置超时时间。前面的入门教程提到,当客户端发起请求时候,需要传入上下

context.Context,用于结束超时取消的请求。

本篇介绍如何设置gRPC请求的超时时间。

1.1 proto文件和编译

syntax = "proto3";package proto;option go_package = "./proto;proto";// 定义我们的服务(可定义多个服务,每个服务可定义多个接口)
service Simple{rpc Route (SimpleRequest) returns (SimpleResponse){};
}message SimpleRequest{// 定义发送的参数,采用驼峰命名方式,小写加下划线,如:student_namestring data = 1;//发送数据
}message SimpleResponse{// 定义接收的参数// 参数类型 参数名 标识号(不可重复)int32 code = 1;  //状态码string value = 2;//接收值
}
protoc --go_out=plugins=grpc:. simple.proto

1.2 客户端请求设置超时时间

修改调用服务端方法:

1、把超时时间设置为当前时间+3秒

clientDeadline := time.Now().Add(time.Duration(3 * time.Second))
ctx, cancel := context.WithDeadline(ctx, clientDeadline)
defer cancel()

2、响应错误检测中添加超时检测

// 传入超时时间为3秒的ctx
res, err := grpcClient.Route(ctx, &req)
if err != nil {//获取错误状态statu, ok := status.FromError(err)if ok {//判断是否为调用超时if statu.Code() == codes.DeadlineExceeded {log.Fatalln("Route timeout!")}}log.Fatalf("Call Route err: %v", err)
}
// 打印返回值
log.Println(res.Value)

3、完整的client.go代码

package mainimport ("context"pb "demo/proto""google.golang/grpc""google.golang/grpc/codes""google.golang/grpc/status""log""time"
)// Address 连接地址
const Address string = ":8000"var grpcClient pb.SimpleClientfunc main() {// 连接服务器conn, err := grpc.Dial(Address, grpc.WithInsecure())if err != nil {log.Fatalf("net.Connect err: %v", err)}defer conn.Close()ctx := context.Background()// 建立gRPC连接grpcClient = pb.NewSimpleClient(conn)// 设置2秒超时时间route(ctx, 2)
}// route 调用服务端Route方法
func route(ctx context.Context, deadlines time.Duration) {//设置超时时间clientDeadline := time.Now().Add(time.Duration(deadlines * time.Second))ctx, cancel := context.WithDeadline(ctx, clientDeadline)defer cancel()// 创建发送结构体req := pb.SimpleRequest{Data: "grpc",}// 调用我们的服务(Route方法)// 传入超时时间的ctxres, err := grpcClient.Route(ctx, &req)if err != nil {//获取错误状态statu, ok := status.FromError(err)if ok {//判断是否为调用超时if statu.Code() == codes.DeadlineExceeded {log.Fatalln("Route timeout!")}}log.Fatalf("Call Route err: %v", err)}// 打印返回值log.Println(res.Value)
}

1.3 服务端判断请求是否超时

当请求超时后,服务端应该停止正在进行的操作,避免资源浪费。

// Route 实现Route方法
func (s *SimpleService) Route(ctx context.Context, req *pb.SimpleRequest) (*pb.SimpleResponse, error) {data := make(chan *pb.SimpleResponse, 1)go handle(ctx, req, data)select {case res := <-data:return res, nilcase <-ctx.Done():return nil, status.Errorf(codes.Canceled, "Client cancelled, abandoning.")}
}
func handle(ctx context.Context, req *pb.SimpleRequest, data chan<- *pb.SimpleResponse) {select {case <-ctx.Done():log.Println(ctx.Err())runtime.Goexit() //超时后退出该Go协程case <-time.After(4 * time.Second): // 模拟耗时操作res := pb.SimpleResponse{Code:  200,Value: "hello " + req.Data,}// 修改数据库前进行超时判断// 如果已经超时,则退出// if ctx.Err() == context.Canceled{}data <- &res}
}

一般地,在写库前进行超时检测,发现超时就停止工作。

完整server.go代码:

package mainimport ("context"pb "demo/proto""google.golang/grpc""google.golang/grpc/codes""google.golang/grpc/status""log""net""runtime""time"
)// SimpleService 定义我们的服务
type SimpleService struct{}const (// Address 监听地址Address string = ":8000"// Network 网络通信协议Network string = "tcp"
)func main() {// 监听本地端口listener, err := net.Listen(Network, Address)if err != nil {log.Fatalf("net.Listen err: %v", err)}log.Println(Address + " net.Listing...")// 新建gRPC服务器实例grpcServer := grpc.NewServer()// 在gRPC服务器注册我们的服务pb.RegisterSimpleServer(grpcServer, &SimpleService{})//用服务器 Serve() 方法以及我们的端口信息区实现阻塞等待,直到进程被杀死或者 Stop() 被调用err = grpcServer.Serve(listener)if err != nil {log.Fatalf("grpcServer.Serve err: %v", err)}
}// Route 实现Route方法
func (s *SimpleService) Route(ctx context.Context, req *pb.SimpleRequest) (*pb.SimpleResponse, error) {data := make(chan *pb.SimpleResponse, 1)go handle(ctx, req, data)select {case res := <-data:log.Println("返回信息1!")return res, nilcase <-ctx.Done():log.Println("返回信息2!")return nil, status.Errorf(codes.Canceled, "Client cancelled, abandoning.")}
}func handle(ctx context.Context, req *pb.SimpleRequest, data chan<- *pb.SimpleResponse) {select {case <-ctx.Done():log.Println("err:", ctx.Err())//超时后退出该Go协程runtime.Goexit()// 模拟耗时操作case <-time.After(3 * time.Second):log.Println("time")res := pb.SimpleResponse{Code:  200,Value: "hello " + req.Data,}// 修改数据库前进行超时判断// 如果已经超时,则退出// if ctx.Err() == context.Canceled{}data <- &res}
}
# 项目结构
$ tree demo/
demo/
├── client.go
├── go.mod
├── go.sum
├── proto
│   └── simple.pb.go
├── server.go
└── simple.proto1 directory, 6 files

1.4 运行结果

服务端:

[root@zsx demo]# go run server.go
2023/02/13 10:22:59 :8000 net.Listing...
2023/02/13 10:23:07 返回信息2!
2023/02/13 10:23:07 err: context deadline exceeded

客户端:

[root@zsx demo]# go run client.go
2023/02/13 10:23:07 Route timeout!
exit status 1

1.5 如果客户端设置5秒的超时时间

//设置5秒超时时间
route(ctx, 5)
[root@zsx demo]# go run server.go
2023/02/13 10:24:15 :8000 net.Listing...
2023/02/13 10:24:20 time
2023/02/13 10:24:20 返回信息1!
[root@zsx demo]# go run client.go
2023/02/13 10:24:20 hello grpc

1.6 总结

超时时间的长短需要根据自身服务而定,例如返回一个hello grpc,可能只需要几十毫秒,然而处理大量数据的同

步操作则可能要很长时间。需要考虑多方面因素来决定这个超时时间,例如系统间端到端的延时,哪些RPC是串行

的,哪些是可以并行的等等。

更多推荐

gRPC之gRPC服务超时设置

本文发布于:2023-11-16 17:26:34,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1628423.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:gRPC

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!