服务 A 调服务 B 失败了,A 该把错误怎么交给自己的客户端?直接 return err 有什么问题?重试叠加会怎样?下游超时该报什么码?这篇用 客户端 → A → B 把每种做法的后果都量出来。
B 返回 A 原样透传 → 客户端 A 翻译 → 客户端 NotFound NotFound NotFound InvalidArgument InvalidArgument Internal Unauthenticated Unauthenticated Internal PermissionDenied PermissionDenied Internal FailedPrecondition FailedPrecondition Internal ResourceExhausted ResourceExhausted ResourceExhausted Unavailable Unavailable Unavailable DeadlineExceeded DeadlineExceeded Unavailable Internal Internal Internal
下游返回 InvalidArgument,说的是 A 传的参数有问题,不是 A 的客户端的参数有问题。原样透传会让客户端误解、误处理。常见做法是把它们折叠成 Internal。翻译表要自己定,不是协议规定的。
透传:客户端看到 code=Internal message="B 内部错误:库表 orders_v2 找不到,连接 10.0.0.5:5432 失败" 翻译:客户端看到 code=Internal message="下游服务出错" B 已经停掉,透传:客户端看到 code=Unavailable message="connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:9803: connect: connection refused…" B 已经停掉,翻译:客户端看到 code=Unavailable message="下游服务:Unavailable"
下游的 message 里可能有表名、地址等内部信息,对外返回通用描述,细节写日志。
只有客户端重试 3 次 B 收到 3 次;客户端最终:Unavailable 客户端 3 次 × A 应用层重试 3 次 B 收到 9 次;客户端最终:Unavailable 客户端 3 次 × A 的 gRPC 重试策略 3 次 B 收到 9 次;客户端最终:Unavailable 只有 A 重试 3 次(客户端不重试) B 收到 3 次;客户端最终:Unavailable
每层都重试,下游收到的次数是各层次数相乘。多层服务里通常只在一层重试,并配合重试节流。
透传(DeadlineExceeded) 客户端最终 DeadlineExceeded,用了 303.7 ms;B 收到 1 次,到达时刻 [2.033625ms] 翻译(Unavailable) 客户端最终 Unavailable,用了 937.6 ms;B 收到 3 次,到达时刻 [1.877584ms 314.555542ms 635.466917ms]
下游超时可以报 DeadlineExceeded 或 Unavailable,两者对客户端重试行为的影响不同:翻译成 Unavailable 会触发客户端重试,可能把慢下游进一步压垮。