Golang gRPC学习(04): Deadlines超时限制

为什么要使用Deadlines#
当我们使用gRPC时,gRPC库关系的是连接,序列化,反序列化和超时执行。Deadlines 允许gRPC客户端设置自己等待多长时间来完成rpc操作,直到出现这个错误 DEADLINE_EXCEEDED。但是在正常情况下,这个DEADLINE_EXCEEDED默认设置是一个很大的数值。
一些语言的API用deadline,一些用 timeout。

在正常情况下,你没有设置deadline,那么所有的请求可能在最大请求时间过后才超时。这样你对于你的服务器资源,可能存在风险,比如内存,可能因为这个长期运行的服务而增长很快,从而耗尽资源。
为了避免这种情况,需要给你的客户端请求程序设置一个默认的超时时间,在这段时间内请求没有返回,那么就超时报错。

怎么使用?Deadlines使用步骤#
使用步骤:#
1.设置deadlines

Copy
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

Copy
if ctx.Err() == context.Canceled {
return status.New(codes.Canceled, “Client cancelled, abandoning.”)
}
具体使用:#

  1. 建立连接时超时控制:
    客户端建立连接时,使用的Dial()函数,它位于
    google.golang.org/grpc/clientconn.go 中,我们看看这个函数内容:

Copy
func Dial(target string, opts …DialOption) (*ClientConn, error) {
return DialContext(context.Background(), target, opts…)
}
它里面调用的 DialContext() 函数,这个函数非常长,他们在同一个文件中,它是实际执行的函数,这里面就有context的timeout和Done相关操作。你也可以到google.golang.org/grpc/clientconn.go文件中去看看这个函数DialContext具体是干嘛的。

使用的时候传入设置timeout的context,如下:

Copy
ctx, cancel := context.Timeout(context.Bakcground(), time.Second*5)
defer cancel()
conn, err := grpc.DialContext(ctx, address, grpc.WithBlock(), grpc.WithInsecure())
grpc.WithInsecure() ,这个参数啥意思?
gRPC是建立在HTTP/2上的,所以对TLS提供了很好的支持。如果在客户端建立连接过程中设置 grpc.WithInsecure() 就可以跳过对服务器证书的验证。写练习时可以用这个参数,但是在真实的环境中,不要这样做,因为有泄露信息的风险。
grpc.WithBlock()
这个参数会阻塞等待握手成功。
因为用Dial连接时是异步连接,连接状态为正在连接,如果设置了这个参数就是同步连接,会阻塞等待握手成功。
这个还和超时设置有关,如果你没有设置这个参数,那么context超时控制将会失效。
2. 调用时超时:
函数的调用超时控制

Copy
ctx, cancel := context.WithTimeout(context.TODO(), time.Second*5)
defer cancel()
result, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
实例#
用grpc官方的例子来练习下

目录结构:

Copy
grpc-tutorial
– 04deadlines
–client
- main.go
–server
- main.go
–proto/echo
- echo.proto
- echo.pb.go
1.首先是定义服务 echo.proto#
Copy
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){}
}
进入到proto/echo目录,生成go文件,命令如下:

protoc -I . --go_out=plugins=grpc:. ./echo.proto

2.客户端#
client\main.go
有2个主要的函数,2端都是stream和都不是stream,先看都不是stream的函数

都不是stream的函数

Copy
// 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)

}
上面的code设置在文件 grpc/codes/codes.go

Copy
type Code uint32

const (
OK Code = 0
Canceled Code = 1
Unknown Code = 2
InvalidArgument Code = 3
DeadlineExceeded Code = 4
… …
)
2端都是stream的函数:

Copy
// 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)//双向stream
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 执行函数

Copy
func

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值