什么是重试

如果服务出现了错误,主要是网络,服务器出现了短暂异常的时候,该怎么办?

我们都会人工或者自动的重新连接服务试试,看服务是否恢复可用了。

这种重新进行连接服务的一种方式就是重试。如果是在微服务里,应该属于微服务治理的范畴。

重试是处理网络服务出现暂时不可用的一种方法。

怎么进行重试

第一:你要能知道网络出现了错误。

怎么才能知道网络出现了错误呢?

一种是你主动探测网络是否可用,比如说健康检查;一种是根据定义的错误码来进行重试。比如http的一些错误码。

第二:根据上面的探测或者错误码决定是否重试。

因为不是所有的错误都要进行重试,我们要根据具体情况来做决定是否重试。

第三:重试的策略

就是怎么进行重试。

在gRPC的这份设计中,主要有2中重试策略:

  1. Retry Policy,出错时立即重试

  2. Hedging Policy,定时发送并发的多个请求,根据请求的响应情况决定是否发送下一个同样的请求,还是返回(好像该策略目前未实现)

  3. 在Retry和Heading基础上的限流

客户端的重试策略和限流策略都是用一个配置文件配置 - service config,这个配置文件用proto定义了一些字段和格式,文件在 grpc/service_config/service_config.proto 中,它最终会解析为一个json格式,proto->json 规则文档

一些Service Config文档例子:doc/service_config

例子

参考官方的例子把我们前面的hello word程序用retry策略改写下。

客户端

主要是要在 Dial() 建立连接的这个函数里加一个参数 grpc.WithDefaultServiceConfig() ,这个就是配置重试策略的参数。

conn, err := grpc.Dial(Address, grpc.WithInsecure(),grpc.WithDefaultServiceConfig(retryPolicy))

里面的参数 retryPolicy 是一个json的字符串,这个就是service config:

retryPolicy = `{
"methodConfig":[{
"name":[{"service": "grpc-tutorial.05retry.hello.hello"}],
"waitForReady": true,
"retryPolicy": {
"MaxAttempts": 4,
"InitialBakckoff": ".01s",
"MaxBackoff": ".01s",
"BackoffMultiplier": 1.0,
"RetryableStatusCodes": ["UNAVAILABLE"]
}
}]}`
  • MaxAttempts:

    最多请求次数。这里设置为4,一次原始请求,三次重试请求。

MaxAttempts必须是大于1的整数,对于大于5的值会被视为5。

  • InitialBakckoff, BackoffMultiplier, MaxBackoff

    这3个参数要结合看, 意思是在进行下一次重试请求前,会计算需要等待的时间,计算公式为:

    • 第一次重试间隔是 random(0, InitialBakckoff)
    • 第 n 次的重试间隔为 random(0, min( InitialBakckoff*BackoffMultiplier*(n-1) , MaxBackoff ))

InitialBakckoff 和 MaxBackoff 必须指定,并且必须具有大于0。

BackoffMultiplier 必须指定,并且大于零。

  • RetryableStatusCodes

    会根据这个 RetryableStatusCodes 来判断是否进行重试。这里设置为 UNAVAILABLE,会根据这个状态来进行重试。

retryableStatusCodes 必须制定为状态码的数据,不能为空,并且没有状态码必须是有效的 gPRC 状态码,可以是整数形式,并且不区分大小写 ([14], [“UNAVAILABLE”], [“unavailable”)

服务端

在服务端我要制造重试的情况出来,主要是 failRequest() 这个函数,改写一下程序:

type failServer struct {
pb.UnimplementedHelloServer
mu sync.Mutex reqNum uint
reqMax uint
} func (f *failServer) failRequest() error {
f.mu.Lock()
defer f.mu.Unlock()
f.reqNum++
if (f.reqMax > 0) && (f.reqNum % f.reqMax == 0) {
return nil
}
return status.Errorf(codes.Unavailable, "failRequest: failing it")
}

然后在main函数初始化一下这个failServer struct:

failService := &failServer{
reqNum: 0,
reqMax: 4,
}

完整的例子在:这里github

运行看看:

先运行服务端:go run server/main.go

在运行客户端:GRPC_GO_RETRY=on go run client/main.go

注意:

运行客户端一定要在环境变量里加上 GRPC_GO_RETRY=on

可是报错了:

sayhello err: rpc error: code = Unavailable desc = failRequest: failing it

exit status 1

而且服务端也只打印了一条信息:

request failed num: 1

Golang gRPC学习(05): retry重试的更多相关文章

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

    为什么要使用Deadlines 当我们使用gRPC时,gRPC库关系的是连接,序列化,反序列化和超时执行.Deadlines 允许gRPC客户端设置自己等待多长时间来完成rpc操作,直到出现这个错误 ...

  2. golang——gRPC学习

    1.获取gRPC 环境变量GOPATH的src目录下执行: git clone https://github.com/grpc/grpc-go.git google.golang.org/grpc g ...

  3. Golang gRPC学习(03): grpc官方示例程序route_guide简析

    代码主要来源于grpc的官方examples代码: route_guide https://github.com/grpc/grpc-go/tree/master/examples/route_gui ...

  4. gRPC学习之三:初试GO版gRPC开发

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. gRPC学习

    概述 gRPC 一开始由 google 开发,是一款语言中立.平台中立.开源的远程过程调用(RPC)系统. 在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法, ...

  6. gRPC学习之一:在CentOS7部署和设置GO

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  7. gRPC学习之二:GO的gRPC开发环境准备

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos gRPC学习系列文章链接 在CentOS7部署和设置G ...

  8. gRPC学习之四:实战四类服务方法

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. gRPC学习之五:gRPC-Gateway实战

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  10. Golang 语法学习笔记

    Golang 语法学习笔记 包.变量和函数. 包 每个 Go 程序都是由包组成的. 程序运行的入口是包 main. 包名与导入路径的最后一个目录一致."math/rand" 包由 ...

随机推荐

  1. [转帖]Java 容器化的历史坑(史坑) - 资源限制篇

    原文:https://blog.mygraphql.com/zh/posts/cloud/containerize/java-containerize/java-containerize-resour ...

  2. Python处理Oracle数据库的学习过程

    Python处理Oracle数据库的学习过程 背景 产品数据存在一些大小写敏感的数据迁移到不敏感的数据库时出现报错的情况. 基于此, 我这边跟帅男同学学习了下Python的使用. 因为这一块一直比较菜 ...

  3. [转帖]centos7 firewall-cmd主机之间端口转发

    目录 1. firewalld 1.1 firewalld守护进程 1.2 控制端口/服务 1.3 伪装IP 1.4 端口转发 2. 案例 2.1 配置ServerA 2.2 安装nginx测试 (可 ...

  4. ebpf的简单学习

    ebpf的简单学习-万事开头难 前言 bpf 值得是巴克利包过滤器 他的核心思想是在内核态增加一个可编程的虚拟机. 可以在用户态定义很多规则, 然后直接在内核态进行过滤和使用. 他的效率极高. 因为避 ...

  5. [转帖]Redis之安全措施

    指令安全 Redis的一些指令会对Redis服务的稳定性及安全性各方面造成影响,例如keys指令在数据量大的情况下会导致Redis卡顿,flushdb和flushall会导致Redis的数据被清空. ...

  6. PostgreSQL简单添加只读用户的方法

    1. 添加了白名单只读来避免开发同事错误的修改数据库内的数据, 但是他们总想去查询数据库的内容. 最简单的办法是修改pg_hba.conf添加只读用户. 2. 添加只读用户. 使用psql登录pg数据 ...

  7. Mybatis 拦截器实现单数据源内多数据库切换 | 京东物流技术团队

    物流的分拣业务在某些分拣场地只有一个数据源,因为数据量比较大,将所有数据存在一张表内查询速度慢,也为了做不同设备数据的分库管理,便在这个数据源内创建了多个不同库名但表完全相同的数据库,如下图所示: 现 ...

  8. echarts轮训展示某个

    //学校资产占比的配置 function schollAssets() { var myChart = window.$echarts.init( document.getElementById('s ...

  9. MongoDB 选型介绍

    什么是 MongoDB 前言 MongoDB 的主要特性 MongoDB 对比关系型数据库 MySQL 什么时候考虑 MongoDB 参考 什么是 MongoDB 前言 MongoDB 是一个开源.高 ...

  10. 给你一颗“定心丸”——记一次由线上事故引发的Log4j2日志异步打印优化分析

    一.内容提要 自知是人外有人,天外有天,相信对于Log4j2的异步日志打印早有老师或者同学已是熟稔于心,优化配置更是信手拈来,为了防止我在这里啰里八嗦的班门弄斧,我先将谜底在此公布:log4j2.as ...