简介
其实不止再微服务中,再平常的网络请求或者第三方系统进行交互都需要设置超时时间;
为什么需要超时机制?
总体上讲,肯定是为了增加系统的可靠性:
- 系统自我保护:快速失败,在业务最大允许等待时间内未收到返回数据,主动放弃等待,释放占用资源,避免请求不断累积带来的客户端雪崩效应
- 成功率:服务处理超时的原因有很多,但常见的超时都是短暂的,主要是:网络抖动或者网络拥塞;这些短时间影响服务端状态的情况而造成请求成功率下降,需要补救措施;简单的补救有超时重试操作:当请求超时后,将会重试到非当前服务器,降低重试超时的几率
代码
proto
syntax = "proto3";
option go_package = ".;proto";
service Greeter{
rpc SayHello(HelloRequest) returns (HelloReplay);
}
message HelloRequest{
string name = 1;
}
message HelloReplay{
string message = 1;
}
.pb.go
// 具体代码省略,使用名称生成即可
protoc -I . hello.proto --go_out=plugins=grpc:.
Server
package main
import (
"ShopBefore/rpc/grpc_timeout/proto"
"context"
"google.golang.org/grpc"
"net"
"time"
)
type Server struct{}
func (s Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReplay, error) {
// Server里面休眠5s
time.Sleep(5 * time.Second)
return &proto.HelloReplay{Message: "hello " + request.Name}, nil
}
func main() {
server := grpc.NewServer()
proto.RegisterGreeterServer(server, &Server{})
listen, _ := net.Listen("tcp", ":8081")
_ = server.Serve(listen)
}
Client
package main
import (
"ShopBefore/rpc/grpc_timeout/proto"
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/status"
"time"
)
func main() {
conn, _ := grpc.Dial("localhost:8081", grpc.WithTransportCredentials(insecure.NewCredentials()))
client := proto.NewGreeterClient(conn)
// 配置超时时间3s
ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
res, err := client.SayHello(ctx, &proto.HelloRequest{Name: "番茄炒蛋"})
if err != nil {
err, ok := status.FromError(err)
if !ok {
panic("解析error失败")
}
// DeadlineExceeded
fmt.Println(err.Code())
// context deadline exceeded
fmt.Println(err.Message())
} else {
fmt.Println(res.Message)
}
}