English | 中文
所有语言的 tRPC 框架使用统一的错误定义,由错误码 code
和错误描述 msg
组成,这与 Golang 标准库的 error 只有一个字符串不同,所以 tRPC-Go 这边通过 errs 包封装了错误类型,方便用户使用。当用户需要返回错误时,使用 errs.New(code, msg)
来创建错误,而不是使用标准库的 errors.New(msg)
,如:
func (s *greeterServerImpl) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
if failed { // 业务逻辑失败
// 定义错误码,错误信息返回给上游
return nil, errs.New(int(your-err-code), "your business error message")
}
return &pb.HelloRepley{}, nil // 业务逻辑成功
}
tRPC-Go 的错误码分框架错误码 framework
,下游框架错误码 callee framework
,业务错误码 business
。
当前自身服务的框架自动返回的错误码,如调用下游服务超时,解包错误等,tRPC 使用的所有框架错误码都定义在 trpc.proto 中。
0~100 为服务端的错误,即当前服务在框架网络层收到请求包之后,进入业务处理函数之前出错,框架会返回错误给上游,业务是无感知的。在上游服务的视角来看就是下游框架错误码。
101~200 为客户端的错误,即调用下游服务时出现的客户端层面的错误。
201~400 为流式错误。
框架错误码日志表现如下:
type:framework, code:101, msg:xxx timeout
当前服务调用下游时,下游服务(被调服务)的框架返回的错误码,这对于下游服务的业务开发来说可能是无感知的,但很明确就是下游服务返回的错误,跟当前自身服务没有关系,当前服务是正常的,不过一般是由于自己参数错误引起下游出错。 出现这个错误,请根据错误信息检查请求参数并与下游服务联调解决。
一般日志表现如下:
type:callee framework, code:12, msg:rpcname:xxx invalid
当前服务调用下游时,下游服务的业务逻辑通过 errs.New
返回的错误码。注意:该错误类型是下游服务的业务逻辑返回的错误码,是下游服务定义的,具体含义需要查阅下游服务文档或咨询下游服务开发者。
tRPC-Go 推荐:业务错误时,使用 errs.New
来返回业务错误码,而不是在应答包里面自己定义错误码,错误码和应答包是互斥的,所以如果返回了错误,框架会忽略应答包。
建议用户自定义的错误码范围大于 10000。
一般日志表现如下:
type:business, code:10000, msg:xxx fail
注意:以下错误码说的是框架错误码和下游框架错误码。业务错误码是业务服务定义的,具体含义需要查阅下游服务文档或咨询下游服务开发者。错误码只是提供了概括性的错误类型,具体错误原因一定要仔细看错误详细信息。
错误码 | 含义 |
---|---|
0 | 成功 |
1 | 服务端解码错误,一般是上下游服务 pb 字段没有对齐或者没有同步更新,解包失败,上下游服务全部更新到 pb 最新版,保持 pb 同步即可解决 |
2 | 服务端编码错误,序列化响应包失败,一般是 pb 字段设置问题,如把不可见字符的二进制数据设置到 string 字段里面了,具体看错误信息 |
11 | 服务端没有相应的 service 实现 |
12 | 服务端没有相应的接口实现,调用函数填错 |
21 | 服务端业务逻辑处理时间过长超时,超过了链路超时时间或者消息超时时间 |
22 | 服务端过载,一般是下游服务端使用了过载保护插件 |
23 | 请求被服务端限流 |
24 | 服务端全链路超时,即上游调用方给的超时时间过短,还来不及进入本服务的业务逻辑 |
31 | 服务端系统错误,一般是 panic 引起的错误,大概率是被调服务空指针,数组越界等 |
41 | 鉴权不通过 |
51 | 请求参数校验不通过 |
101 | 请求在客户端调用超时 |
102 | 客户端全链路超时,即当前发起 rpc 的超时时间过短,有可能是上游给的超时时间不够,也有可能是前面的 rpc 调用已经耗尽了大部分时间 |
111 | 客户端连接错误,一般是下游没有监听该 ip:port,如下游启动失败 |
121 | 客户端编码错误,序列化请求包失败 |
122 | 客户端解码错误,一般是 pb 没有对齐 |
123 | 请求被客户端限流 |
124 | 客户端过载错误 |
131 | 客户端选 ip 路由错误,一般是服务名填错,或者该服务名下没有可用实例 |
141 | 客户端网络错误 |
151 | 响应参数校验不通过 |
161 | 上游调用方提前取消请求 |
171 | 客户端读取帧数据错误 |
201 | 服务端流式网络错误 |
351 | 客户端流式读取数据失败 |
999 | 未明确的错误,一般是下游直接用 Golang 标准库 errors.New(msg) 返回了不带数字的错误了,没有用框架自带的 errs.New(code, msg) |
tRPC-Go 中错误结构具体实现如下:
type Error struct {
Type int // 错误码类型 1 框架错误码 2 业务错误码 3 下游框架错误码
Code int32 // 错误码
Msg string // 错误信息描述
Desc string // 错误额外描述,主要用于监控前缀,如 trpc 框架错误为 trpc 前缀,http 协议错误为 http 前缀,用户可以通过实现拦截器捕获该 err 并更改该字段实现上报任意前缀的监控
}
错误处理流程:
- 当服务端通过
errs.New
返回业务错误时,框架会将该错误填入 trpc 协议头的业务错误func_ret
字段里。 - 当服务端通过
errs.NewFrameError
返回框架错误时,框架会将该错误填入 trpc 协议头的框架错误ret
字段里。 - 当服务端框架回包时,会判断是否有错误,有错误则会抛弃响应数据包,所以如果返回错误时,不要再试图通过响应包返回数据。
- 当客户端发起 RPC 调用时,框架需要先执行编码等操作,再把请求发送到下游,如果在发出网络数据之前出错,则直接返回
框架错误
给用户;如果发送请求成功并收到回包,但从回包的协议头中解析出框架错误则返回下游框架错误
,如果解析出业务错误则返回业务错误
。