博客
关于我
Golang gRPC学习(04): Deadlines超时限制
阅读量:434 次
发布时间:2019-03-06

本文共 5369 字,大约阅读时间需要 17 分钟。

为什么要使用Deadlines

在使用gRPC时,客户端和服务器之间的连接、序列化、反序列化以及超时执行是常见的操作。Deadlines(截止时间)允许客户端设置等待多长时间完成RPC操作的限制,直到出现错误DEADLINE_EXCEEDED。默认情况下,DEADLINE_EXCEEDED的值通常设置得很高。

如果没有设置Deadlines,所有请求可能会在最大请求时间过后才超时,这会导致服务器资源消耗增加,如内存膨胀等问题。因此,为客户端请求程序设置一个默认超时时间是必要的,当请求在此时间内未返回时,会超时报错。

Deadlines的使用步骤

1. 设置Deadlines

var deadlineMs = flag.Int("deadline_ms", 20*1000, "Default deadline in milliseconds.")
clientDeadline := time.Now().Add(time.Duration(*deadlineMs) * time.Millisecond)
ctx, cancel := context.WithDeadline(ctx, clientDeadline)

2. 检查Deadlines

if ctx.Err() == context.Canceled {
return status.New(codes.Canceled, "Client cancelled, abandoning.")
}

2.2 具体使用

1. 建立连接时超时控制

Dial()函数位于google.golang.org/grpc/clientconn.go中,实际执行由DialContext()函数完成。客户端应传入设置超时的context,如下所示:

ctx, cancel := context.Timeout(context.Background(), time.Second*5)
defer cancel()
conn, err := grpc.DialContext(ctx, address, grpc.WithBlock(), grpc.WithInsecure())

注意事项:

  • grpc.WithInsecure():跳过对服务器证书的验证,适用于练习,但在生产环境中不建议使用。
  • grpc.WithBlock():阻塞等待握手成功,否则超时控制失效。

2. 调用时超时

ctx, cancel := context.WithTimeout(context.TODO(), time.Second*5)
defer cancel()
result, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})

实例

1. 定义服务echo.proto

syntax = "proto3";
package echo;
message EchoRequest {
string message = 1;
}
message EchoResponse {
string message = 1;
}
service Echo {
rpc UnaryEcho(EchoRequest) returns (EchoRequest) {}
rpc ServerStreamingEcho(EchoRequest) returns (stream EchoResponse) {}
rpc ClientStreamingEcho(stream EchoRequest) returns (EchoResponse) {}
rpc BidirectionalStreamingEcho(stream EchoRequest) returns (stream EchoResponse) {}
}

2. 客户端client/main.go

都不是stream的函数

// unaryCall 不是stream的请求
func unaryCall(c pb.EchoClient, requestID int, message string, want codes.Code) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
req := &pb.EchoRequest{Message: message}
_, err := c.UnaryEcho(ctx, req)
got := status.Code(err)
fmt.Printf "[%v] wanted = %v, got = %v\n", requestID, want, got
}

2端都是stream的函数

// streamingCall,2端都是stream
func streamingCall(c pb.EchoClient, requestID int, message string, want codes.Code) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
stream, err := c.BidirectionalStreamingEcho(ctx)
if err != nil {
log.Printf("Send error : %v", err)
return
}
err = stream.Send(&pb.EchoRequest{Message: message})
if err != nil {
log.Printf("Send error : %v", err)
return
}
_, err = stream.Recv()
got := status.Code(err)
fmt.Printf "[%v] wanted = %v, got = %v\n", requestID, want, got
}

main 执行函数

func main() {
flag.Parse()
conn, err := grpc.Dial(*addr, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect : %v ", err)
}
defer conn.Close()
c := pb.NewEchoClient(conn)
// 成功请求
unaryCall(c, 1, "word", codes.OK)
// 超时 deadline
unaryCall(c, 2, "delay", codes.DeadlineExceeded)
// A successful request with propagated deadline
unaryCall(c, 3, "[propagate me]world", codes.OK)
// Exceeds propagated deadline
unaryCall(c, 4, "[propagate me][propagate me]world", codes.DeadlineExceeded)
// Receives a response from the stream successfully.
streamingCall(c, 5, "[propagate me]world", codes.OK)
// Exceeds propagated deadline before receiving a response
streamingCall(c, 6, "[propagate me][propagate me]world", codes.DeadlineExceeded)
}

3. 服务端server/main.go

定义一个struct

type server struct {
pb.UnimplementedEchoServer
client pb.EchoClient
cc *grpc.ClientConn
}

2端不是stream的函数

func (s *server) UnaryEcho(ctx context.Context, req *pb.EchoRequest) (*pb.EchoResponse, error) {
message := req.Message
if strings.HasPrefix(message, "[propagate me]") {
time.Sleep(800 * time.Millisecond)
message := strings.TrimPrefix(message, "[propagate me]")
return s.client.UnaryEcho(ctx, &pb.EchoRequest{Message: message})
}
if message == "delay" {
time.Sleep(1500 * time.Millisecond)
}
return &pb.EchoResponse{Message: message}, nil
}

2端设置stream的函数

func (s *server) BidirectionalStreamingEcho(stream pb.Echo_BidirectionalStreamingEchoServer) error {
for {
req, err := stream.Recv()
if err == io.EOF {
return status.Error(codes.InvalidArgument, "request message not received")
}
if err != nil {
return err
}
message := req.Message
if strings.HasPrefix(message, "[propagate me]") {
time.Sleep(800 * time.Millisecond)
message := strings.TrimPrefix(message, "[propagate me]")
res, err := s.client.UnaryEcho(stream.Context(), &pb.EchoRequest{Message: message})
if err != nil {
return err
}
stream.Send(res)
}
if message == "delay" {
time.Sleep(1500 * time.Millisecond)
}
stream.Send(&pb.EchoResponse{Message: message})
}
}

执行

运行server/main.goclient/main.go,执行结果如下:

go run main.go[1] wanted = OK, got = OK
[2] wanted = DeadlineExceeded, got = DeadlineExceeded
[3] wanted = OK, got = Unavailable
[4] wanted = DeadlineExceeded, got = Unavailable
[5] wanted = OK, got = Unavailable
[6] wanted = DeadlineExceeded, got = Unavailable

转载地址:http://hzfyz.baihongyu.com/

你可能感兴趣的文章
oobbs开发手记
查看>>
OPEN CASCADE Curve Continuity
查看>>
Open Graph Protocol(开放内容协议)
查看>>
Open vSwitch实验常用命令
查看>>
Open WebUI 忘了登入密码怎么办?
查看>>
open-vm-tools-dkms : 依赖: open-vm-tools (>= 2:9.4.0-1280544-5ubuntu3) 但是它将不会被安装
查看>>
open3d-Dll缺失,未找到指定模块解决
查看>>
Openbox-桌面图标设置
查看>>
opencart出现no such file or dictionary
查看>>
opencv Mat push_back
查看>>
opencv SVM分类Demo
查看>>
opencv videocapture读取视频cap.isOpened 输出总是false
查看>>
opencv waitKey() 函数理解及应用
查看>>
OpenCV 中的图像转换
查看>>
OpenCV 在 Linux 上的 python 与 anaconda 无法正常工作.收到未实现 cv2.imshow() 的错误
查看>>
Opencv 完美配置攻略 2014 (Win8.1 + Opencv 2.4.8 + VS 2013)上
查看>>
opencv 模板匹配, 已解决模板过大程序不工作的bug
查看>>
OpenCV 错误:(-215)size.width>0 &&函数imshow中的size.height>0
查看>>
opencv&Python——多种边缘检测
查看>>
opencv&python——高通滤波器和低通滤波器
查看>>