客户端调用
如何创建可复用的 Kitex Client?
- service name:
NewClient的第一个参数; 是服务发现和观测的核心维度; - 禁止模式: 每个请求调用一次
NewClient; 会放大连接、CPU、配置拉取和 goroutine; - 构造期配置: 连接超时、RPC 超时、重试、熔断等通常在
NewClient时一次性配置;
func newUserClient() (userservice.Client, error) {
cli, err := userservice.NewClient(
"user",
client.WithHostPorts("127.0.0.1:8888"),
client.WithConnectTimeout(200*time.Millisecond),
client.WithRPCTimeout(time.Second),
)
if err != nil {
return nil, fmt.Errorf("create user client: %w", err)
}
return cli, nil
}
如何发起一次 RPC 调用?
- 实践: 每个调用方法都会接收
context.Context和请求对象,返回响应与 error; - context: 约束本地调用的取消和 deadline;跨进程传播需要 超时配置 中的协议前提;
- Call Option: 通过方法尾参传入,只对单次调用生效,优先级高于 Client Option;
callopt.WithRPCTimeout: 单次覆盖超时; 只用于特例,不要到处散落;callopt.WithHostPort: 单次直连指定实例; 适合诊断,不适合生产流量;
func getUser(ctx context.Context, cli userservice.Client, id int64) (*api.GetUserResponse, error) {
resp, err := cli.GetUser(ctx, &api.GetUserRequest{Id: id})
if err != nil {
return nil, fmt.Errorf("get user %d: %w", id, err)
}
return resp, nil
}
如何给 Client 提供目标地址?
- 本地开发:
client.WithHostPorts直接指定实例地址; - 动态环境:
client.WithResolver获取实例列表,由 LoadBalancer 选择; - URL/DNS:
callopt.WithURL或 HTTP Resolver; 解析结果仍需连接目标; - 预热: 首次调用延迟敏感时用 warming up 初始化 Resolver 和连接池;
如何处理调用失败?
- 实践: 先处理
err,再读取 response; 不能假设失败时 response 可用; - 实践: 用
errors.Is、kerrors.IsTimeoutError或业务异常转换判断错误类别; - 实践: 不因“读请求”就盲目重试; 必须确认接口幂等并留有总时间预算;